From 9f12d3a3658298c6afb7d6a27b65735fdd4e4548 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Thu, 21 Sep 2017 17:51:00 -0700 Subject: [PATCH 1/3] fix missing models --- .../src/EntityTreeRenderer.cpp | 8 ++++++ .../src/RenderableEntityItem.cpp | 17 ++++++++++++ .../src/RenderableEntityItem.h | 26 +++++++++++++++++++ .../src/RenderableModelEntityItem.cpp | 16 +++++------- .../src/RenderableModelEntityItem.h | 6 ++--- .../src/model-networking/ModelCache.cpp | 2 +- .../render-utils/src/MeshPartPayload.cpp | 4 +-- libraries/render-utils/src/Model.cpp | 8 ++---- 8 files changed, 66 insertions(+), 21 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index a79e29f003..f303617be0 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -222,6 +222,14 @@ void EntityTreeRenderer::updateChangedEntities(const render::ScenePointer& scene _renderablesToUpdate.insert({ entityId, renderable }); } + if (!_entitiesInScene.empty()) { + for (const auto& entry : _entitiesInScene) { + const auto& renderable = entry.second; + if (renderable) { + renderable->update(scene, transaction); + } + } + } if (!_renderablesToUpdate.empty()) { for (const auto& entry : _renderablesToUpdate) { const auto& renderable = entry.second; diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp index 3f1e89b86c..ea514d3181 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp @@ -291,6 +291,18 @@ void EntityRenderer::updateInScene(const ScenePointer& scene, Transaction& trans }); } +void EntityRenderer::update(const ScenePointer& scene, Transaction& transaction) { + if (!isValidRenderItem()) { + return; + } + + if (!needsUpdate()) { + return; + } + + doUpdate(scene, transaction, _entity); +} + // // Internal methods // @@ -304,6 +316,11 @@ bool EntityRenderer::needsRenderUpdate() const { return needsRenderUpdateFromEntity(_entity); } +// Returns true if the item needs to have update called +bool EntityRenderer::needsUpdate() const { + return needsUpdateFromEntity(_entity); +} + // Returns true if the item in question needs to have updateInScene called because of changes in the entity bool EntityRenderer::needsRenderUpdateFromEntity(const EntityItemPointer& entity) const { bool success = false; diff --git a/libraries/entities-renderer/src/RenderableEntityItem.h b/libraries/entities-renderer/src/RenderableEntityItem.h index 6b47ff8b1d..56cb39252f 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.h +++ b/libraries/entities-renderer/src/RenderableEntityItem.h @@ -49,6 +49,8 @@ public: virtual bool addToScene(const ScenePointer& scene, Transaction& transaction) final; virtual void removeFromScene(const ScenePointer& scene, Transaction& transaction); + virtual void update(const ScenePointer& scene, Transaction& transaction); + protected: virtual bool needsRenderUpdateFromEntity() const final { return needsRenderUpdateFromEntity(_entity); } virtual void onAddToScene(const EntityItemPointer& entity); @@ -71,6 +73,12 @@ protected: // Returns true if the item in question needs to have updateInScene called because of changes in the entity virtual bool needsRenderUpdateFromEntity(const EntityItemPointer& entity) const; + // Returns true if the item in question needs to have update called + virtual bool needsUpdate() const; + + // Returns true if the item in question needs to have update called because of changes in the entity + virtual bool needsUpdateFromEntity(const EntityItemPointer& entity) const { return false; } + // Will be called on the main thread from updateInScene. This can be used to fetch things like // network textures or model geometry from resource caches virtual void doRenderUpdateSynchronous(const ScenePointer& scene, Transaction& transaction, const EntityItemPointer& entity) { } @@ -80,6 +88,8 @@ protected: // data in this method if using multi-threaded rendering virtual void doRenderUpdateAsynchronous(const EntityItemPointer& entity); + virtual void doUpdate(const ScenePointer& scene, Transaction& transaction, const EntityItemPointer& entity) { } + // Called by the `render` method after `needsRenderUpdate` virtual void doRender(RenderArgs* args) = 0; @@ -148,6 +158,15 @@ protected: onRemoveFromSceneTyped(_typedEntity); } + using Parent::needsUpdateFromEntity; + // Returns true if the item in question needs to have update called because of changes in the entity + virtual bool needsUpdateFromEntity(const EntityItemPointer& entity) const override final { + if (Parent::needsUpdateFromEntity(entity)) { + return true; + } + return needsUpdateFromTypedEntity(_typedEntity); + } + using Parent::needsRenderUpdateFromEntity; // Returns true if the item in question needs to have updateInScene called because of changes in the entity virtual bool needsRenderUpdateFromEntity(const EntityItemPointer& entity) const override final { @@ -162,6 +181,11 @@ protected: doRenderUpdateSynchronousTyped(scene, transaction, _typedEntity); } + virtual void doUpdate(const ScenePointer& scene, Transaction& transaction, const EntityItemPointer& entity) override final { + Parent::doUpdate(scene, transaction, entity); + doUpdateTyped(scene, transaction, _typedEntity); + } + virtual void doRenderUpdateAsynchronous(const EntityItemPointer& entity) override final { Parent::doRenderUpdateAsynchronous(entity); doRenderUpdateAsynchronousTyped(_typedEntity); @@ -170,6 +194,8 @@ protected: virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const { return false; } virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) { } virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) { } + virtual bool needsUpdateFromTypedEntity(const TypedEntityPointer& entity) const { return false; } + virtual void doUpdateTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) { } virtual void onAddToSceneTyped(const TypedEntityPointer& entity) { } virtual void onRemoveFromSceneTyped(const TypedEntityPointer& entity) { } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 2508b598af..a8a7dcdcf7 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -904,7 +904,7 @@ using namespace render; using namespace render::entities; ItemKey ModelEntityRenderer::getKey() { - return ItemKey::Builder::opaqueShape().withTypeMeta(); + return ItemKey::Builder().withTypeMeta(); } uint32_t ModelEntityRenderer::metaFetchMetaSubItems(ItemIDs& subItems) { @@ -1026,7 +1026,7 @@ void ModelEntityRenderer::animate(const TypedEntityPointer& entity) { entity->copyAnimationJointDataToModel(); } -bool ModelEntityRenderer::needsRenderUpdate() const { +bool ModelEntityRenderer::needsUpdate() const { ModelPointer model; withReadLock([&] { model = _model; @@ -1057,10 +1057,10 @@ bool ModelEntityRenderer::needsRenderUpdate() const { return true; } } - return Parent::needsRenderUpdate(); + return Parent::needsUpdate(); } -bool ModelEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const { +bool ModelEntityRenderer::needsUpdateFromTypedEntity(const TypedEntityPointer& entity) const { if (resultWithReadLock([&] { if (entity->hasModel() != _hasModel) { return true; @@ -1122,7 +1122,7 @@ bool ModelEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoin return false; } -void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) { +void ModelEntityRenderer::doUpdateTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) { if (_hasModel != entity->hasModel()) { _hasModel = entity->hasModel(); } @@ -1175,8 +1175,8 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce properties.setLastEdited(usecTimestampNow()); // we must set the edit time since we're editing it auto extents = model->getMeshExtents(); properties.setDimensions(extents.maximum - extents.minimum); - qCDebug(entitiesrenderer) << "Autoresizing" - << (!entity->getName().isEmpty() ? entity->getName() : entity->getModelURL()) + qCDebug(entitiesrenderer) << "Autoresizing" + << (!entity->getName().isEmpty() ? entity->getName() : entity->getModelURL()) << "from mesh extents"; QMetaObject::invokeMethod(DependencyManager::get().data(), "editEntity", @@ -1203,7 +1203,6 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce entity->updateModelBounds(); } - if (model->isVisible() != _visible) { // FIXME: this seems like it could be optimized if we tracked our last known visible state in // the renderable item. As it stands now the model checks it's visible/invisible state @@ -1234,7 +1233,6 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce }); } - if (_animating) { if (!jointsMapped()) { mapJoints(entity, model->getJointNames()); diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index b9c751761d..e2c7939845 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -138,10 +138,10 @@ protected: virtual ItemKey getKey() override; virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) override; - virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override; - virtual bool needsRenderUpdate() const override; + virtual bool needsUpdateFromTypedEntity(const TypedEntityPointer& entity) const override; + virtual bool needsUpdate() const override; virtual void doRender(RenderArgs* args) override; - virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override; + virtual void doUpdateTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override; private: void animate(const TypedEntityPointer& entity); diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 468d22ce9e..74c8d06736 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -464,7 +464,7 @@ void GeometryResourceWatcher::setResource(GeometryResource::Pointer resource) { _resource = resource; if (_resource) { if (_resource->isLoaded()) { - _geometryRef = std::make_shared(*_resource); + resourceFinished(true); } else { startWatching(); } diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 517fe97dba..924c199239 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -321,8 +321,8 @@ template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, Ren } -ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int _meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform) : - _meshIndex(_meshIndex), +ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform) : + _meshIndex(meshIndex), _shapeID(shapeIndex) { assert(model && model->isLoaded()); diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 42bb91ce94..e729a9519b 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -209,11 +209,6 @@ void Model::updateRenderItems() { return; } - glm::vec3 scale = getScale(); - if (_collisionGeometry) { - // _collisionGeometry is already scaled - scale = glm::vec3(1.0f); - } _needsUpdateClusterMatrices = true; _renderItemsNeedUpdate = false; @@ -221,7 +216,7 @@ void Model::updateRenderItems() { // the application will ensure only the last lambda is actually invoked. void* key = (void*)this; std::weak_ptr weakSelf = shared_from_this(); - AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [weakSelf, scale]() { + AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [weakSelf]() { // do nothing, if the model has already been destroyed. auto self = weakSelf.lock(); @@ -1219,6 +1214,7 @@ const render::ItemIDs& Model::fetchRenderItemIDs() const { } void Model::createRenderItemSet() { + updateClusterMatrices(); if (_collisionGeometry) { if (_collisionRenderItems.empty()) { createCollisionRenderItemSet(); From be27376c52d3b37106383a8cab1ab458f3f4d6e1 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 22 Sep 2017 10:02:41 -0700 Subject: [PATCH 2/3] add comment about bottleneck --- .../entities-renderer/src/EntityTreeRenderer.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index f303617be0..c29d92bae9 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -222,12 +222,14 @@ void EntityTreeRenderer::updateChangedEntities(const render::ScenePointer& scene _renderablesToUpdate.insert({ entityId, renderable }); } - if (!_entitiesInScene.empty()) { - for (const auto& entry : _entitiesInScene) { - const auto& renderable = entry.second; - if (renderable) { - renderable->update(scene, transaction); - } + // NOTE: Looping over all the entity renderers is likely to be a bottleneck in the future + // Currently, this is necessary because the model entity loading logic requires constant polling + // This was working fine because the entity server used to send repeated updates as your view changed, + // but with the improved entity server logic (PR 11141), updateInScene (below) would not be triggered enough + for (const auto& entry : _entitiesInScene) { + const auto& renderable = entry.second; + if (renderable) { + renderable->update(scene, transaction); } } if (!_renderablesToUpdate.empty()) { From 86198606e036f7f5cafbc75295983fd0c5421a5a Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 22 Sep 2017 11:46:24 -0700 Subject: [PATCH 3/3] add _modelJustLoaded and updateTransforForSkinnedMesh on creation --- .../src/RenderableModelEntityItem.cpp | 12 ++++++++++++ .../src/RenderableModelEntityItem.h | 4 ++++ libraries/render-utils/src/MeshPartPayload.cpp | 8 ++++++++ libraries/render-utils/src/Model.cpp | 1 - 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index a8a7dcdcf7..799a84aaee 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -1032,6 +1032,10 @@ bool ModelEntityRenderer::needsUpdate() const { model = _model; }); + if (_modelJustLoaded) { + return true; + } + if (model) { if (_needsJointSimulation || _moving || _animating) { return true; @@ -1148,9 +1152,11 @@ void ModelEntityRenderer::doUpdateTyped(const ScenePointer& scene, Transaction& return; } + _modelJustLoaded = false; // Check for addition if (_hasModel && !(bool)_model) { model = std::make_shared(nullptr, entity.get()); + connect(model.get(), &Model::setURLFinished, this, &ModelEntityRenderer::handleModelLoaded); model->setLoadingPriority(EntityTreeRenderer::getEntityLoadingPriority(*entity)); model->init(); entity->setModel(model); @@ -1241,6 +1247,12 @@ void ModelEntityRenderer::doUpdateTyped(const ScenePointer& scene, Transaction& } } +void ModelEntityRenderer::handleModelLoaded(bool success) { + if (success) { + _modelJustLoaded = true; + } +} + // NOTE: this only renders the "meta" portion of the Model, namely it renders debugging items void ModelEntityRenderer::doRender(RenderArgs* args) { PROFILE_RANGE(render_detail, "MetaModelRender"); diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index e2c7939845..ad0afeee0a 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -151,6 +151,7 @@ private: // Transparency is handled in ModelMeshPartPayload virtual bool isTransparent() const override { return false; } + bool _modelJustLoaded { false }; bool _hasModel { false }; ::ModelPointer _model; GeometryResource::Pointer _compoundShapeResource; @@ -178,6 +179,9 @@ private: bool _animating { false }; uint64_t _lastAnimated { 0 }; float _currentFrame { 0 }; + +private slots: + void handleModelLoaded(bool success); }; } } // namespace diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 924c199239..3f57a1779a 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -328,10 +328,18 @@ ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, in assert(model && model->isLoaded()); _model = model; auto& modelMesh = model->getGeometry()->getMeshes().at(_meshIndex); + const Model::MeshState& state = model->getMeshState(_meshIndex); updateMeshPart(modelMesh, partIndex); + computeAdjustedLocalBound(state.clusterMatrices); updateTransform(transform, offsetTransform); + Transform renderTransform = transform; + if (state.clusterMatrices.size() == 1) { + renderTransform = transform.worldTransform(Transform(state.clusterMatrices[0])); + } + updateTransformForSkinnedMesh(renderTransform, transform, state.clusterBuffer); + initCache(); } diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index e729a9519b..9948a8bddd 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1265,7 +1265,6 @@ void Model::createVisibleRenderItemSet() { shapeID++; } } - computeMeshPartLocalBounds(); } void Model::createCollisionRenderItemSet() {