Merge pull request #8311 from huffman/feat/angular-loading

Add priority loading for model entities
This commit is contained in:
Brad Hefta-Gaub 2016-08-08 13:06:56 -07:00 committed by GitHub
commit 882ad2f6fb
7 changed files with 44 additions and 6 deletions

View file

@ -739,7 +739,14 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
connect(&identityPacketTimer, &QTimer::timeout, getMyAvatar(), &MyAvatar::sendIdentityPacket);
identityPacketTimer.start(AVATAR_IDENTITY_PACKET_SEND_INTERVAL_MSECS);
ResourceCache::setRequestLimit(MAX_CONCURRENT_RESOURCE_DOWNLOADS);
const char** constArgv = const_cast<const char**>(argv);
QString concurrentDownloadsStr = getCmdOption(argc, constArgv, "--concurrent-downloads");
bool success;
int concurrentDownloads = concurrentDownloadsStr.toInt(&success);
if (!success) {
concurrentDownloads = MAX_CONCURRENT_RESOURCE_DOWNLOADS;
}
ResourceCache::setRequestLimit(concurrentDownloads);
_glWidget = new GLCanvas();
getApplicationCompositor().setRenderingWidget(_glWidget);
@ -3240,6 +3247,18 @@ void Application::init() {
getEntities()->setViewFrustum(_viewFrustum);
}
getEntities()->setEntityLoadingPriorityFunction([this](const EntityItem& item) {
auto dims = item.getDimensions();
auto maxSize = glm::max(dims.x, dims.y, dims.z);
if (maxSize <= 0.0f) {
return 0.0f;
}
auto distance = glm::distance(getMyAvatar()->getPosition(), item.getPosition());
return atan2(maxSize, distance);
});
ObjectMotionState::setShapeManager(&_shapeManager);
_physicsEngine->init();

View file

@ -529,7 +529,7 @@ void EntityTreeRenderer::processEraseMessage(ReceivedMessage& message, const Sha
std::static_pointer_cast<EntityTree>(_tree)->processEraseMessage(message, sourceNode);
}
ModelPointer EntityTreeRenderer::allocateModel(const QString& url, const QString& collisionUrl) {
ModelPointer EntityTreeRenderer::allocateModel(const QString& url, const QString& collisionUrl, float loadingPriority) {
ModelPointer model = nullptr;
// Only create and delete models on the thread that owns the EntityTreeRenderer
@ -543,6 +543,7 @@ ModelPointer EntityTreeRenderer::allocateModel(const QString& url, const QString
}
model = std::make_shared<Model>(std::make_shared<Rig>());
model->setLoadingPriority(loadingPriority);
model->init();
model->setURL(QUrl(url));
model->setCollisionModelURL(QUrl(collisionUrl));

View file

@ -28,11 +28,14 @@ class AbstractViewStateInterface;
class Model;
class ScriptEngine;
class ZoneEntityItem;
class EntityItem;
class Model;
using ModelPointer = std::shared_ptr<Model>;
using ModelWeakPointer = std::weak_ptr<Model>;
using CalculateEntityLoadingPriority = std::function<float(const EntityItem& item)>;
// Generic client side Octree renderer class.
class EntityTreeRenderer : public OctreeRenderer, public EntityItemFBXService, public Dependency {
Q_OBJECT
@ -46,6 +49,10 @@ public:
virtual PacketType getExpectedPacketType() const { return PacketType::EntityData; }
virtual void setTree(OctreePointer newTree);
// Returns the priority at which an entity should be loaded. Higher values indicate higher priority.
float getEntityLoadingPriority(const EntityItem& item) const { return _calculateEntityLoadingPriorityFunc(item); }
void setEntityLoadingPriorityFunction(CalculateEntityLoadingPriority fn) { this->_calculateEntityLoadingPriorityFunc = fn; }
void shutdown();
void update();
@ -66,7 +73,7 @@ public:
void reloadEntityScripts();
/// if a renderable entity item needs a model, we will allocate it for them
Q_INVOKABLE ModelPointer allocateModel(const QString& url, const QString& collisionUrl);
Q_INVOKABLE ModelPointer allocateModel(const QString& url, const QString& collisionUrl, float loadingPriority = 0.0f);
/// if a renderable entity item needs to update the URL of a model, we will handle that for the entity
Q_INVOKABLE ModelPointer updateModel(ModelPointer original, const QString& newUrl, const QString& collisionUrl);
@ -202,6 +209,10 @@ private:
QList<EntityItemID> _entityIDsLastInScene;
static int _entitiesScriptEngineCount;
CalculateEntityLoadingPriority _calculateEntityLoadingPriorityFunc = [](const EntityItem& item) -> float {
return 0.0f;
};
};

View file

@ -484,7 +484,7 @@ ModelPointer RenderableModelEntityItem::getModel(EntityTreeRenderer* renderer) {
if (!getModelURL().isEmpty()) {
// If we don't have a model, allocate one *immediately*
if (!_model) {
_model = _myRenderer->allocateModel(getModelURL(), getCompoundShapeURL());
_model = _myRenderer->allocateModel(getModelURL(), getCompoundShapeURL(), renderer->getEntityLoadingPriority(*this));
_needsInitialSimulation = true;
// If we need to change URLs, update it *after rendering* (to avoid access violations)
} else if ((QUrl(getModelURL()) != _model->getURL() || QUrl(getCompoundShapeURL()) != _model->getCollisionURL())) {

View file

@ -52,7 +52,6 @@ public:
bool& keepSearching, OctreeElementPointer& element, float& distance,
BoxFace& face, glm::vec3& surfaceNormal,
void** intersectedObject, bool precisionPicking) const override;
ModelPointer getModel(EntityTreeRenderer* renderer);
virtual bool needsToCallUpdate() const override;

View file

@ -826,7 +826,9 @@ void Model::setURL(const QUrl& url) {
invalidCalculatedMeshBoxes();
deleteGeometry();
_renderWatcher.setResource(DependencyManager::get<ModelCache>()->getGeometryResource(url));
auto resource = DependencyManager::get<ModelCache>()->getGeometryResource(url);
resource->setLoadPriority(this, _loadingPriority);
_renderWatcher.setResource(resource);
onInvalidate();
}

View file

@ -238,6 +238,8 @@ public:
// returns 'true' if needs fullUpdate after geometry change
bool updateGeometry();
void setLoadingPriority(float priority) { _loadingPriority = priority; }
public slots:
void loadURLFinished(bool success);
void loadCollisionModelURLFinished(bool success);
@ -405,6 +407,10 @@ protected:
bool _visualGeometryRequestFailed { false };
bool _collisionGeometryRequestFailed { false };
private:
float _loadingPriority { 0.0f };
};
Q_DECLARE_METATYPE(ModelPointer)