Merge pull request #11436 from SamGondelman/missingModels

Fix missing models
This commit is contained in:
Brad Hefta-Gaub 2017-09-23 13:56:50 -07:00 committed by GitHub
commit bafb59e691
8 changed files with 92 additions and 22 deletions

View file

@ -222,6 +222,16 @@ void EntityTreeRenderer::updateChangedEntities(const render::ScenePointer& scene
_renderablesToUpdate.insert({ entityId, renderable }); _renderablesToUpdate.insert({ entityId, renderable });
} }
// 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()) { if (!_renderablesToUpdate.empty()) {
for (const auto& entry : _renderablesToUpdate) { for (const auto& entry : _renderablesToUpdate) {
const auto& renderable = entry.second; const auto& renderable = entry.second;

View file

@ -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 // Internal methods
// //
@ -304,6 +316,11 @@ bool EntityRenderer::needsRenderUpdate() const {
return needsRenderUpdateFromEntity(_entity); 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 // 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 EntityRenderer::needsRenderUpdateFromEntity(const EntityItemPointer& entity) const {
bool success = false; bool success = false;

View file

@ -49,6 +49,8 @@ public:
virtual bool addToScene(const ScenePointer& scene, Transaction& transaction) final; virtual bool addToScene(const ScenePointer& scene, Transaction& transaction) final;
virtual void removeFromScene(const ScenePointer& scene, Transaction& transaction); virtual void removeFromScene(const ScenePointer& scene, Transaction& transaction);
virtual void update(const ScenePointer& scene, Transaction& transaction);
protected: protected:
virtual bool needsRenderUpdateFromEntity() const final { return needsRenderUpdateFromEntity(_entity); } virtual bool needsRenderUpdateFromEntity() const final { return needsRenderUpdateFromEntity(_entity); }
virtual void onAddToScene(const EntityItemPointer& 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 // 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; 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 // 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 // network textures or model geometry from resource caches
virtual void doRenderUpdateSynchronous(const ScenePointer& scene, Transaction& transaction, const EntityItemPointer& entity) { } 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 // data in this method if using multi-threaded rendering
virtual void doRenderUpdateAsynchronous(const EntityItemPointer& entity); virtual void doRenderUpdateAsynchronous(const EntityItemPointer& entity);
virtual void doUpdate(const ScenePointer& scene, Transaction& transaction, const EntityItemPointer& entity) { }
// Called by the `render` method after `needsRenderUpdate` // Called by the `render` method after `needsRenderUpdate`
virtual void doRender(RenderArgs* args) = 0; virtual void doRender(RenderArgs* args) = 0;
@ -148,6 +158,15 @@ protected:
onRemoveFromSceneTyped(_typedEntity); 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; using Parent::needsRenderUpdateFromEntity;
// Returns true if the item in question needs to have updateInScene called because of changes in the entity // 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 { virtual bool needsRenderUpdateFromEntity(const EntityItemPointer& entity) const override final {
@ -162,6 +181,11 @@ protected:
doRenderUpdateSynchronousTyped(scene, transaction, _typedEntity); 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 { virtual void doRenderUpdateAsynchronous(const EntityItemPointer& entity) override final {
Parent::doRenderUpdateAsynchronous(entity); Parent::doRenderUpdateAsynchronous(entity);
doRenderUpdateAsynchronousTyped(_typedEntity); doRenderUpdateAsynchronousTyped(_typedEntity);
@ -170,6 +194,8 @@ protected:
virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const { return false; } virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const { return false; }
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) { } virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) { }
virtual void doRenderUpdateAsynchronousTyped(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 onAddToSceneTyped(const TypedEntityPointer& entity) { }
virtual void onRemoveFromSceneTyped(const TypedEntityPointer& entity) { } virtual void onRemoveFromSceneTyped(const TypedEntityPointer& entity) { }

View file

@ -904,7 +904,7 @@ using namespace render;
using namespace render::entities; using namespace render::entities;
ItemKey ModelEntityRenderer::getKey() { ItemKey ModelEntityRenderer::getKey() {
return ItemKey::Builder::opaqueShape().withTypeMeta(); return ItemKey::Builder().withTypeMeta();
} }
uint32_t ModelEntityRenderer::metaFetchMetaSubItems(ItemIDs& subItems) { uint32_t ModelEntityRenderer::metaFetchMetaSubItems(ItemIDs& subItems) {
@ -1026,12 +1026,16 @@ void ModelEntityRenderer::animate(const TypedEntityPointer& entity) {
entity->copyAnimationJointDataToModel(); entity->copyAnimationJointDataToModel();
} }
bool ModelEntityRenderer::needsRenderUpdate() const { bool ModelEntityRenderer::needsUpdate() const {
ModelPointer model; ModelPointer model;
withReadLock([&] { withReadLock([&] {
model = _model; model = _model;
}); });
if (_modelJustLoaded) {
return true;
}
if (model) { if (model) {
if (_needsJointSimulation || _moving || _animating) { if (_needsJointSimulation || _moving || _animating) {
return true; return true;
@ -1057,10 +1061,10 @@ bool ModelEntityRenderer::needsRenderUpdate() const {
return true; return true;
} }
} }
return Parent::needsRenderUpdate(); return Parent::needsUpdate();
} }
bool ModelEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const { bool ModelEntityRenderer::needsUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
if (resultWithReadLock<bool>([&] { if (resultWithReadLock<bool>([&] {
if (entity->hasModel() != _hasModel) { if (entity->hasModel() != _hasModel) {
return true; return true;
@ -1122,7 +1126,7 @@ bool ModelEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoin
return false; 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()) { if (_hasModel != entity->hasModel()) {
_hasModel = entity->hasModel(); _hasModel = entity->hasModel();
} }
@ -1148,9 +1152,11 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
return; return;
} }
_modelJustLoaded = false;
// Check for addition // Check for addition
if (_hasModel && !(bool)_model) { if (_hasModel && !(bool)_model) {
model = std::make_shared<Model>(nullptr, entity.get()); model = std::make_shared<Model>(nullptr, entity.get());
connect(model.get(), &Model::setURLFinished, this, &ModelEntityRenderer::handleModelLoaded);
model->setLoadingPriority(EntityTreeRenderer::getEntityLoadingPriority(*entity)); model->setLoadingPriority(EntityTreeRenderer::getEntityLoadingPriority(*entity));
model->init(); model->init();
entity->setModel(model); entity->setModel(model);
@ -1175,8 +1181,8 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
properties.setLastEdited(usecTimestampNow()); // we must set the edit time since we're editing it properties.setLastEdited(usecTimestampNow()); // we must set the edit time since we're editing it
auto extents = model->getMeshExtents(); auto extents = model->getMeshExtents();
properties.setDimensions(extents.maximum - extents.minimum); properties.setDimensions(extents.maximum - extents.minimum);
qCDebug(entitiesrenderer) << "Autoresizing" qCDebug(entitiesrenderer) << "Autoresizing"
<< (!entity->getName().isEmpty() ? entity->getName() : entity->getModelURL()) << (!entity->getName().isEmpty() ? entity->getName() : entity->getModelURL())
<< "from mesh extents"; << "from mesh extents";
QMetaObject::invokeMethod(DependencyManager::get<EntityScriptingInterface>().data(), "editEntity", QMetaObject::invokeMethod(DependencyManager::get<EntityScriptingInterface>().data(), "editEntity",
@ -1203,7 +1209,6 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
entity->updateModelBounds(); entity->updateModelBounds();
} }
if (model->isVisible() != _visible) { if (model->isVisible() != _visible) {
// FIXME: this seems like it could be optimized if we tracked our last known visible state in // 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 // the renderable item. As it stands now the model checks it's visible/invisible state
@ -1234,7 +1239,6 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
}); });
} }
if (_animating) { if (_animating) {
if (!jointsMapped()) { if (!jointsMapped()) {
mapJoints(entity, model->getJointNames()); mapJoints(entity, model->getJointNames());
@ -1243,6 +1247,12 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
} }
} }
void ModelEntityRenderer::handleModelLoaded(bool success) {
if (success) {
_modelJustLoaded = true;
}
}
// NOTE: this only renders the "meta" portion of the Model, namely it renders debugging items // NOTE: this only renders the "meta" portion of the Model, namely it renders debugging items
void ModelEntityRenderer::doRender(RenderArgs* args) { void ModelEntityRenderer::doRender(RenderArgs* args) {
PROFILE_RANGE(render_detail, "MetaModelRender"); PROFILE_RANGE(render_detail, "MetaModelRender");

View file

@ -138,10 +138,10 @@ protected:
virtual ItemKey getKey() override; virtual ItemKey getKey() override;
virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) override; virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) override;
virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override; virtual bool needsUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
virtual bool needsRenderUpdate() const override; virtual bool needsUpdate() const override;
virtual void doRender(RenderArgs* args) 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: private:
void animate(const TypedEntityPointer& entity); void animate(const TypedEntityPointer& entity);
@ -151,6 +151,7 @@ private:
// Transparency is handled in ModelMeshPartPayload // Transparency is handled in ModelMeshPartPayload
virtual bool isTransparent() const override { return false; } virtual bool isTransparent() const override { return false; }
bool _modelJustLoaded { false };
bool _hasModel { false }; bool _hasModel { false };
::ModelPointer _model; ::ModelPointer _model;
GeometryResource::Pointer _compoundShapeResource; GeometryResource::Pointer _compoundShapeResource;
@ -178,6 +179,9 @@ private:
bool _animating { false }; bool _animating { false };
uint64_t _lastAnimated { 0 }; uint64_t _lastAnimated { 0 };
float _currentFrame { 0 }; float _currentFrame { 0 };
private slots:
void handleModelLoaded(bool success);
}; };
} } // namespace } } // namespace

View file

@ -464,7 +464,7 @@ void GeometryResourceWatcher::setResource(GeometryResource::Pointer resource) {
_resource = resource; _resource = resource;
if (_resource) { if (_resource) {
if (_resource->isLoaded()) { if (_resource->isLoaded()) {
_geometryRef = std::make_shared<Geometry>(*_resource); resourceFinished(true);
} else { } else {
startWatching(); startWatching();
} }

View file

@ -321,17 +321,25 @@ template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, Ren
} }
ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int _meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform) : ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform) :
_meshIndex(_meshIndex), _meshIndex(meshIndex),
_shapeID(shapeIndex) { _shapeID(shapeIndex) {
assert(model && model->isLoaded()); assert(model && model->isLoaded());
_model = model; _model = model;
auto& modelMesh = model->getGeometry()->getMeshes().at(_meshIndex); auto& modelMesh = model->getGeometry()->getMeshes().at(_meshIndex);
const Model::MeshState& state = model->getMeshState(_meshIndex);
updateMeshPart(modelMesh, partIndex); updateMeshPart(modelMesh, partIndex);
computeAdjustedLocalBound(state.clusterMatrices);
updateTransform(transform, offsetTransform); updateTransform(transform, offsetTransform);
Transform renderTransform = transform;
if (state.clusterMatrices.size() == 1) {
renderTransform = transform.worldTransform(Transform(state.clusterMatrices[0]));
}
updateTransformForSkinnedMesh(renderTransform, transform, state.clusterBuffer);
initCache(); initCache();
} }

View file

@ -209,11 +209,6 @@ void Model::updateRenderItems() {
return; return;
} }
glm::vec3 scale = getScale();
if (_collisionGeometry) {
// _collisionGeometry is already scaled
scale = glm::vec3(1.0f);
}
_needsUpdateClusterMatrices = true; _needsUpdateClusterMatrices = true;
_renderItemsNeedUpdate = false; _renderItemsNeedUpdate = false;
@ -221,7 +216,7 @@ void Model::updateRenderItems() {
// the application will ensure only the last lambda is actually invoked. // the application will ensure only the last lambda is actually invoked.
void* key = (void*)this; void* key = (void*)this;
std::weak_ptr<Model> weakSelf = shared_from_this(); std::weak_ptr<Model> weakSelf = shared_from_this();
AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [weakSelf, scale]() { AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [weakSelf]() {
// do nothing, if the model has already been destroyed. // do nothing, if the model has already been destroyed.
auto self = weakSelf.lock(); auto self = weakSelf.lock();
@ -1219,6 +1214,7 @@ const render::ItemIDs& Model::fetchRenderItemIDs() const {
} }
void Model::createRenderItemSet() { void Model::createRenderItemSet() {
updateClusterMatrices();
if (_collisionGeometry) { if (_collisionGeometry) {
if (_collisionRenderItems.empty()) { if (_collisionRenderItems.empty()) {
createCollisionRenderItemSet(); createCollisionRenderItemSet();
@ -1269,7 +1265,6 @@ void Model::createVisibleRenderItemSet() {
shapeID++; shapeID++;
} }
} }
computeMeshPartLocalBounds();
} }
void Model::createCollisionRenderItemSet() { void Model::createCollisionRenderItemSet() {