starting improve entity updates pt 2

This commit is contained in:
HifiExperiments 2020-10-12 18:50:46 -07:00
parent 89c006d190
commit 5a8c1a0374
16 changed files with 433 additions and 624 deletions

View file

@ -431,13 +431,13 @@ void EntityRenderer::doRenderUpdateSynchronous(const ScenePointer& scene, Transa
_visible = entity->getVisible(); _visible = entity->getVisible();
setIsVisibleInSecondaryCamera(entity->isVisibleInSecondaryCamera()); setIsVisibleInSecondaryCamera(entity->isVisibleInSecondaryCamera());
setRenderLayer(entity->getRenderLayer()); setRenderLayer(entity->getRenderLayer());
setPrimitiveMode(entity->getPrimitiveMode()); _primitiveMode = entity->getPrimitiveMode();
_canCastShadow = entity->getCanCastShadow(); _canCastShadow = entity->getCanCastShadow();
setCullWithParent(entity->getCullWithParent()); setCullWithParent(entity->getCullWithParent());
_cauterized = entity->getCauterized(); _cauterized = entity->getCauterized();
if (entity->needsZoneOcclusionUpdate()) { if (entity->needsZoneOcclusionUpdate()) {
entity->resetNeedsZoneOcclusionUpdate(); entity->resetNeedsZoneOcclusionUpdate();
setRenderWithZones(entity->getRenderWithZones()); _renderWithZones = entity->getRenderWithZones();
} }
entity->setNeedsRenderUpdate(false); entity->setNeedsRenderUpdate(false);
}); });

View file

@ -108,18 +108,7 @@ protected:
virtual void setIsVisibleInSecondaryCamera(bool value) { _isVisibleInSecondaryCamera = value; } virtual void setIsVisibleInSecondaryCamera(bool value) { _isVisibleInSecondaryCamera = value; }
virtual void setRenderLayer(RenderLayer value) { _renderLayer = value; } virtual void setRenderLayer(RenderLayer value) { _renderLayer = value; }
virtual void setPrimitiveMode(PrimitiveMode value) { _primitiveMode = value; }
virtual void setCullWithParent(bool value) { _cullWithParent = value; } virtual void setCullWithParent(bool value) { _cullWithParent = value; }
virtual void setRenderWithZones(const QVector<QUuid>& renderWithZones) { _renderWithZones = renderWithZones; }
template <typename F, typename T>
T withReadLockResult(const std::function<T()>& f) {
T result;
withReadLock([&] {
result = f();
});
return result;
}
signals: signals:
void requestRenderUpdate(); void requestRenderUpdate();

View file

@ -52,14 +52,11 @@ void GizmoEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
void GizmoEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) { void GizmoEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
bool dirty = false; bool dirty = false;
RingGizmoPropertyGroup ringProperties = entity->getRingProperties(); RingGizmoPropertyGroup ringProperties = entity->getRingProperties();
withWriteLock([&] { _gizmoType = entity->getGizmoType();
_gizmoType = entity->getGizmoType(); if (_ringProperties != ringProperties) {
if (_ringProperties != ringProperties) { _ringProperties = ringProperties;
_ringProperties = ringProperties; dirty = true;
dirty = true; }
}
});
if (dirty || _prevPrimitiveMode != _primitiveMode || !_ringGeometryID || !_majorTicksGeometryID || !_minorTicksGeometryID) { if (dirty || _prevPrimitiveMode != _primitiveMode || !_ringGeometryID || !_majorTicksGeometryID || !_minorTicksGeometryID) {
_prevPrimitiveMode = _primitiveMode; _prevPrimitiveMode = _primitiveMode;
@ -242,19 +239,20 @@ void GizmoEntityRenderer::doRender(RenderArgs* args) {
if (_gizmoType == GizmoType::RING) { if (_gizmoType == GizmoType::RING) {
Transform transform; Transform transform;
bool hasTickMarks; bool hasTickMarks = _ringProperties.getHasTickMarks();
glm::vec4 tickProperties; glm::vec4 tickProperties = glm::vec4(_ringProperties.getMajorTickMarksAngle(), _ringProperties.getMajorTickMarksLength(),
_ringProperties.getMinorTickMarksAngle(), _ringProperties.getMinorTickMarksLength());
bool forward; bool forward;
bool wireframe;
bool transparent;
withReadLock([&] { withReadLock([&] {
transform = _renderTransform; transform = _renderTransform;
hasTickMarks = _ringProperties.getHasTickMarks(); transparent = isTransparent();
tickProperties = glm::vec4(_ringProperties.getMajorTickMarksAngle(), _ringProperties.getMajorTickMarksLength(), wireframe = render::ShapeKey(args->_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES;
_ringProperties.getMinorTickMarksAngle(), _ringProperties.getMinorTickMarksLength());
forward = _renderLayer != RenderLayer::WORLD || args->_renderMethod == Args::RenderMethod::FORWARD; forward = _renderLayer != RenderLayer::WORLD || args->_renderMethod == Args::RenderMethod::FORWARD;
}); });
bool wireframe = render::ShapeKey(args->_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES; geometryCache->bindSimpleProgram(batch, false, transparent, wireframe, true, true, forward, graphics::MaterialKey::CULL_NONE);
geometryCache->bindSimpleProgram(batch, false, isTransparent(), wireframe, true, true, forward, graphics::MaterialKey::CULL_NONE);
batch.setModelTransform(transform); batch.setModelTransform(transform);

View file

@ -30,16 +30,6 @@ bool GridEntityRenderer::isTransparent() const {
} }
void GridEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) { void GridEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
withWriteLock([&] {
_color = entity->getColor();
_alpha = entity->getAlpha();
_pulseProperties = entity->getPulseProperties();
_followCamera = entity->getFollowCamera();
_majorGridEvery = entity->getMajorGridEvery();
_minorGridEvery = entity->getMinorGridEvery();
});
void* key = (void*)this; void* key = (void*)this;
AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this, entity] { AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this, entity] {
withWriteLock([&] { withWriteLock([&] {
@ -49,6 +39,16 @@ void GridEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scen
}); });
} }
void GridEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
_color = entity->getColor();
_alpha = entity->getAlpha();
_pulseProperties = entity->getPulseProperties();
_followCamera = entity->getFollowCamera();
_majorGridEvery = entity->getMajorGridEvery();
_minorGridEvery = entity->getMinorGridEvery();
}
Item::Bound GridEntityRenderer::getBound() { Item::Bound GridEntityRenderer::getBound() {
if (_followCamera) { if (_followCamera) {
// This is a UI element that should always be in view, lie to the octree to avoid culling // This is a UI element that should always be in view, lie to the octree to avoid culling
@ -73,13 +73,12 @@ ShapeKey GridEntityRenderer::getShapeKey() {
} }
void GridEntityRenderer::doRender(RenderArgs* args) { void GridEntityRenderer::doRender(RenderArgs* args) {
glm::vec4 color; glm::vec4 color = glm::vec4(toGlm(_color), _alpha);
color = EntityRenderer::calculatePulseColor(color, _pulseProperties, _created);
glm::vec3 dimensions; glm::vec3 dimensions;
Transform renderTransform; Transform renderTransform;
bool forward; bool forward;
withReadLock([&] { withReadLock([&] {
color = glm::vec4(toGlm(_color), _alpha);
color = EntityRenderer::calculatePulseColor(color, _pulseProperties, _created);
dimensions = _dimensions; dimensions = _dimensions;
renderTransform = _renderTransform; renderTransform = _renderTransform;
forward = _renderLayer != RenderLayer::WORLD || args->_renderMethod == Args::RenderMethod::FORWARD; forward = _renderLayer != RenderLayer::WORLD || args->_renderMethod == Args::RenderMethod::FORWARD;

View file

@ -30,10 +30,11 @@ protected:
private: private:
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override; virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
virtual void doRender(RenderArgs* args) override; virtual void doRender(RenderArgs* args) override;
glm::u8vec3 _color; glm::u8vec3 _color { NAN };
float _alpha; float _alpha { NAN };
PulsePropertyGroup _pulseProperties; PulsePropertyGroup _pulseProperties;
bool _followCamera; bool _followCamera;

View file

@ -29,44 +29,7 @@ bool ImageEntityRenderer::isTransparent() const {
return Parent::isTransparent() || (_textureIsLoaded && _texture->getGPUTexture() && _texture->getGPUTexture()->getUsage().isAlpha()) || _alpha < 1.0f || _pulseProperties.getAlphaMode() != PulseMode::NONE; return Parent::isTransparent() || (_textureIsLoaded && _texture->getGPUTexture() && _texture->getGPUTexture()->getUsage().isAlpha()) || _alpha < 1.0f || _pulseProperties.getAlphaMode() != PulseMode::NONE;
} }
bool ImageEntityRenderer::needsRenderUpdate() const {
if (resultWithReadLock<bool>([&] {
return !_textureIsLoaded;
})) {
return true;
}
return Parent::needsRenderUpdate();
}
void ImageEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) { void ImageEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
withWriteLock([&] {
auto imageURL = entity->getImageURL();
if (_imageURL != imageURL) {
_imageURL = imageURL;
if (imageURL.isEmpty()) {
_texture.reset();
} else {
_texture = DependencyManager::get<TextureCache>()->getTexture(_imageURL);
}
_textureIsLoaded = false;
}
_emissive = entity->getEmissive();
_keepAspectRatio = entity->getKeepAspectRatio();
_subImage = entity->getSubImage();
_color = entity->getColor();
_alpha = entity->getAlpha();
_pulseProperties = entity->getPulseProperties();
_billboardMode = entity->getBillboardMode();
if (!_textureIsLoaded) {
emit requestRenderUpdate();
}
_textureIsLoaded = _texture && (_texture->isLoaded() || _texture->isFailed());
});
void* key = (void*)this; void* key = (void*)this;
AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this, entity] { AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this, entity] {
withWriteLock([&] { withWriteLock([&] {
@ -76,6 +39,33 @@ void ImageEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
}); });
} }
void ImageEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
auto imageURL = entity->getImageURL();
if (_imageURL != imageURL) {
_imageURL = imageURL;
if (imageURL.isEmpty()) {
_texture.reset();
} else {
_texture = DependencyManager::get<TextureCache>()->getTexture(_imageURL);
}
_textureIsLoaded = false;
}
_emissive = entity->getEmissive();
_keepAspectRatio = entity->getKeepAspectRatio();
_subImage = entity->getSubImage();
_color = entity->getColor();
_alpha = entity->getAlpha();
_pulseProperties = entity->getPulseProperties();
_billboardMode = entity->getBillboardMode();
if (!_textureIsLoaded) {
emit requestRenderUpdate();
}
_textureIsLoaded = _texture && (_texture->isLoaded() || _texture->isFailed());
}
Item::Bound ImageEntityRenderer::getBound() { Item::Bound ImageEntityRenderer::getBound() {
auto bound = Parent::getBound(); auto bound = Parent::getBound();
if (_billboardMode != BillboardMode::NONE) { if (_billboardMode != BillboardMode::NONE) {
@ -93,33 +83,26 @@ ShapeKey ImageEntityRenderer::getShapeKey() {
builder.withTranslucent(); builder.withTranslucent();
} }
withReadLock([&] { if (_emissive) {
if (_emissive) { builder.withUnlit();
builder.withUnlit(); }
}
if (_primitiveMode == PrimitiveMode::LINES) { if (_primitiveMode == PrimitiveMode::LINES) {
builder.withWireframe(); builder.withWireframe();
} }
});
return builder.build(); return builder.build();
} }
void ImageEntityRenderer::doRender(RenderArgs* args) { void ImageEntityRenderer::doRender(RenderArgs* args) {
NetworkTexturePointer texture; glm::vec4 color = glm::vec4(toGlm(_color), _alpha);
QRect subImage; color = EntityRenderer::calculatePulseColor(color, _pulseProperties, _created);
glm::vec4 color;
Transform transform; Transform transform;
withReadLock([&] { withReadLock([&] {
texture = _texture;
subImage = _subImage;
color = glm::vec4(toGlm(_color), _alpha);
color = EntityRenderer::calculatePulseColor(color, _pulseProperties, _created);
transform = _renderTransform; transform = _renderTransform;
}); });
if (!_visible || !texture || !texture->isLoaded() || color.a == 0.0f) { if (!_visible || !_texture || !_texture->isLoaded() || color.a == 0.0f) {
return; return;
} }
@ -129,28 +112,28 @@ void ImageEntityRenderer::doRender(RenderArgs* args) {
transform.setRotation(EntityItem::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, args->getViewFrustum().getPosition())); transform.setRotation(EntityItem::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, args->getViewFrustum().getPosition()));
batch->setModelTransform(transform); batch->setModelTransform(transform);
batch->setResourceTexture(0, texture->getGPUTexture()); batch->setResourceTexture(0, _texture->getGPUTexture());
float imageWidth = texture->getWidth(); float imageWidth = _texture->getWidth();
float imageHeight = texture->getHeight(); float imageHeight = _texture->getHeight();
QRect fromImage; QRect fromImage;
if (subImage.width() <= 0) { if (_subImage.width() <= 0) {
fromImage.setX(0); fromImage.setX(0);
fromImage.setWidth(imageWidth); fromImage.setWidth(imageWidth);
} else { } else {
float scaleX = imageWidth / texture->getOriginalWidth(); float scaleX = imageWidth / _texture->getOriginalWidth();
fromImage.setX(scaleX * subImage.x()); fromImage.setX(scaleX * _subImage.x());
fromImage.setWidth(scaleX * subImage.width()); fromImage.setWidth(scaleX * _subImage.width());
} }
if (subImage.height() <= 0) { if (_subImage.height() <= 0) {
fromImage.setY(0); fromImage.setY(0);
fromImage.setHeight(imageHeight); fromImage.setHeight(imageHeight);
} else { } else {
float scaleY = imageHeight / texture->getOriginalHeight(); float scaleY = imageHeight / _texture->getOriginalHeight();
fromImage.setY(scaleY * subImage.y()); fromImage.setY(scaleY * _subImage.y());
fromImage.setHeight(scaleY * subImage.height()); fromImage.setHeight(scaleY * _subImage.height());
} }
float maxSize = glm::max(fromImage.width(), fromImage.height()); float maxSize = glm::max(fromImage.width(), fromImage.height());

View file

@ -29,8 +29,8 @@ protected:
bool isTransparent() const override; bool isTransparent() const override;
private: private:
virtual bool needsRenderUpdate() const override;
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override; virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
virtual void doRender(RenderArgs* args) override; virtual void doRender(RenderArgs* args) override;
QString _imageURL; QString _imageURL;

View file

@ -16,199 +16,186 @@
using namespace render; using namespace render;
using namespace render::entities; using namespace render::entities;
bool MaterialEntityRenderer::needsRenderUpdate() const {
if (_retryApply) {
return true;
}
if (!_texturesLoaded) {
return true;
}
return Parent::needsRenderUpdate();
}
bool MaterialEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const { bool MaterialEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
if (resultWithReadLock<bool>([&] { if (resultWithReadLock<bool>([&] {
if (entity->getTransform() != _transform) { return entity->getParentID() != _parentID;
return true;
}
if (entity->getUnscaledDimensions() != _dimensions) {
return true;
}
if (entity->getParentID() != _parentID) {
return true;
}
return false;
})) { })) {
return true; return true;
} }
return false; return false;
} }
void MaterialEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) { void MaterialEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
withWriteLock([&] { void* key = (void*)this;
bool deleteNeeded = false; AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this, entity] {
bool addNeeded = _retryApply; withWriteLock([&] {
bool transformChanged = false; _renderTransform = getModelTransform();
{ const float MATERIAL_ENTITY_SCALE = 0.5f;
MaterialMappingMode mode = entity->getMaterialMappingMode(); _renderTransform.postScale(MATERIAL_ENTITY_SCALE);
if (mode != _materialMappingMode) { _renderTransform.postScale(ENTITY_ITEM_DEFAULT_DIMENSIONS);
_materialMappingMode = mode; });
transformChanged = true;
}
}
{
bool repeat = entity->getMaterialRepeat();
if (repeat != _materialRepeat) {
_materialRepeat = repeat;
transformChanged = true;
}
}
{
glm::vec2 mappingPos = entity->getMaterialMappingPos();
glm::vec2 mappingScale = entity->getMaterialMappingScale();
float mappingRot = entity->getMaterialMappingRot();
if (mappingPos != _materialMappingPos || mappingScale != _materialMappingScale || mappingRot != _materialMappingRot) {
_materialMappingPos = mappingPos;
_materialMappingScale = mappingScale;
_materialMappingRot = mappingRot;
transformChanged |= _materialMappingMode == MaterialMappingMode::UV;
}
}
{
Transform transform = entity->getTransform();
glm::vec3 dimensions = entity->getUnscaledDimensions();
if (transform != _transform || dimensions != _dimensions) {
_transform = transform;
_dimensions = dimensions;
transformChanged |= _materialMappingMode == MaterialMappingMode::PROJECTED;
}
}
{
auto material = getMaterial();
// Update the old material regardless of if it's going to change
if (transformChanged && material && !_parentID.isNull()) {
deleteNeeded = true;
addNeeded = true;
applyTextureTransform(material);
}
}
bool urlChanged = false;
std::string newCurrentMaterialName = _currentMaterialName;
{
QString materialURL = entity->getMaterialURL();
if (materialURL != _materialURL) {
_materialURL = materialURL;
if (_materialURL.contains("#")) {
auto split = _materialURL.split("#");
newCurrentMaterialName = split.last().toStdString();
} else if (_materialURL.contains("?")) {
qDebug() << "DEPRECATED: Use # instead of ? for material URLS:" << _materialURL;
auto split = _materialURL.split("?");
newCurrentMaterialName = split.last().toStdString();
}
urlChanged = true;
}
}
bool usingMaterialData = _materialURL.startsWith("materialData");
bool materialDataChanged = false;
QUuid oldParentID = _parentID;
QString oldParentMaterialName = _parentMaterialName;
{
QString materialData = entity->getMaterialData();
if (materialData != _materialData) {
_materialData = materialData;
if (usingMaterialData) {
materialDataChanged = true;
}
}
}
{
QString parentMaterialName = entity->getParentMaterialName();
if (parentMaterialName != _parentMaterialName) {
_parentMaterialName = parentMaterialName;
deleteNeeded = true;
addNeeded = true;
}
}
{
QUuid parentID = entity->getParentID();
if (parentID != _parentID) {
_parentID = parentID;
deleteNeeded = true;
addNeeded = true;
}
}
{
quint16 priority = entity->getPriority();
if (priority != _priority) {
_priority = priority;
deleteNeeded = true;
addNeeded = true;
}
}
if (urlChanged && !usingMaterialData) {
_networkMaterial = DependencyManager::get<MaterialCache>()->getMaterial(_materialURL);
auto onMaterialRequestFinished = [this, entity, oldParentID, oldParentMaterialName, newCurrentMaterialName](bool success) {
if (success) {
deleteMaterial(oldParentID, oldParentMaterialName);
_texturesLoaded = false;
_parsedMaterials = _networkMaterial->parsedMaterials;
setCurrentMaterialName(newCurrentMaterialName);
applyMaterial(entity);
} else {
deleteMaterial(oldParentID, oldParentMaterialName);
_retryApply = false;
_texturesLoaded = true;
}
};
if (_networkMaterial) {
if (_networkMaterial->isLoaded()) {
onMaterialRequestFinished(!_networkMaterial->isFailed());
} else {
connect(_networkMaterial.data(), &Resource::finished, this, [this, onMaterialRequestFinished](bool success) {
withWriteLock([&] {
onMaterialRequestFinished(success);
});
});
}
}
} else if (materialDataChanged && usingMaterialData) {
deleteMaterial(oldParentID, oldParentMaterialName);
_texturesLoaded = false;
_parsedMaterials = NetworkMaterialResource::parseJSONMaterials(QJsonDocument::fromJson(_materialData.toUtf8()), _materialURL);
// Since our material changed, the current name might not be valid anymore, so we need to update
setCurrentMaterialName(newCurrentMaterialName);
applyMaterial(entity);
} else {
if (deleteNeeded) {
deleteMaterial(oldParentID, oldParentMaterialName);
}
if (addNeeded) {
applyMaterial(entity);
}
}
{
auto material = getMaterial();
bool newTexturesLoaded = material ? !material->isMissingTexture() : false;
if (!_texturesLoaded && newTexturesLoaded) {
material->checkResetOpacityMap();
}
_texturesLoaded = newTexturesLoaded;
}
_renderTransform = getModelTransform();
const float MATERIAL_ENTITY_SCALE = 0.5f;
_renderTransform.postScale(MATERIAL_ENTITY_SCALE);
_renderTransform.postScale(ENTITY_ITEM_DEFAULT_DIMENSIONS);
}); });
} }
void MaterialEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
bool deleteNeeded = false;
bool addNeeded = _retryApply;
bool transformChanged = false;
{
MaterialMappingMode mode = entity->getMaterialMappingMode();
if (mode != _materialMappingMode) {
_materialMappingMode = mode;
transformChanged = true;
}
}
{
bool repeat = entity->getMaterialRepeat();
if (repeat != _materialRepeat) {
_materialRepeat = repeat;
transformChanged = true;
}
}
{
glm::vec2 mappingPos = entity->getMaterialMappingPos();
glm::vec2 mappingScale = entity->getMaterialMappingScale();
float mappingRot = entity->getMaterialMappingRot();
if (mappingPos != _materialMappingPos || mappingScale != _materialMappingScale || mappingRot != _materialMappingRot) {
_materialMappingPos = mappingPos;
_materialMappingScale = mappingScale;
_materialMappingRot = mappingRot;
transformChanged |= _materialMappingMode == MaterialMappingMode::UV;
}
}
{
Transform transform = entity->getTransform();
glm::vec3 dimensions = entity->getUnscaledDimensions();
if (transform != _transform || dimensions != _dimensions) {
_transform = transform;
_dimensions = dimensions;
transformChanged |= _materialMappingMode == MaterialMappingMode::PROJECTED;
}
}
{
auto material = getMaterial();
// Update the old material regardless of if it's going to change
if (transformChanged && material && !_parentID.isNull()) {
deleteNeeded = true;
addNeeded = true;
applyTextureTransform(material);
}
}
bool urlChanged = false;
std::string newCurrentMaterialName = _currentMaterialName;
{
QString materialURL = entity->getMaterialURL();
if (materialURL != _materialURL) {
_materialURL = materialURL;
if (_materialURL.contains("#")) {
auto split = _materialURL.split("#");
newCurrentMaterialName = split.last().toStdString();
} else if (_materialURL.contains("?")) {
qDebug() << "DEPRECATED: Use # instead of ? for material URLS:" << _materialURL;
auto split = _materialURL.split("?");
newCurrentMaterialName = split.last().toStdString();
}
urlChanged = true;
}
}
bool usingMaterialData = _materialURL.startsWith("materialData");
bool materialDataChanged = false;
QUuid oldParentID = _parentID;
QString oldParentMaterialName = _parentMaterialName;
{
QString materialData = entity->getMaterialData();
if (materialData != _materialData) {
_materialData = materialData;
if (usingMaterialData) {
materialDataChanged = true;
}
}
}
{
QString parentMaterialName = entity->getParentMaterialName();
if (parentMaterialName != _parentMaterialName) {
_parentMaterialName = parentMaterialName;
deleteNeeded = true;
addNeeded = true;
}
}
{
QUuid parentID = entity->getParentID();
if (parentID != _parentID) {
_parentID = parentID;
deleteNeeded = true;
addNeeded = true;
}
}
{
quint16 priority = entity->getPriority();
if (priority != _priority) {
_priority = priority;
deleteNeeded = true;
addNeeded = true;
}
}
if (urlChanged && !usingMaterialData) {
_networkMaterial = DependencyManager::get<MaterialCache>()->getMaterial(_materialURL);
auto onMaterialRequestFinished = [this, entity, oldParentID, oldParentMaterialName, newCurrentMaterialName](bool success) {
deleteMaterial(oldParentID, oldParentMaterialName);
if (success) {
_texturesLoaded = false;
_parsedMaterials = _networkMaterial->parsedMaterials;
setCurrentMaterialName(newCurrentMaterialName);
applyMaterial(entity);
emit requestRenderUpdate();
} else {
_retryApply = false;
_texturesLoaded = true;
}
};
if (_networkMaterial) {
if (_networkMaterial->isLoaded()) {
onMaterialRequestFinished(!_networkMaterial->isFailed());
} else {
connect(_networkMaterial.data(), &Resource::finished, this, [this, onMaterialRequestFinished](bool success) {
onMaterialRequestFinished(success);
});
}
}
} else if (materialDataChanged && usingMaterialData) {
deleteMaterial(oldParentID, oldParentMaterialName);
_texturesLoaded = false;
_parsedMaterials = NetworkMaterialResource::parseJSONMaterials(QJsonDocument::fromJson(_materialData.toUtf8()), _materialURL);
// Since our material changed, the current name might not be valid anymore, so we need to update
setCurrentMaterialName(newCurrentMaterialName);
applyMaterial(entity);
} else {
if (deleteNeeded) {
deleteMaterial(oldParentID, oldParentMaterialName);
}
if (addNeeded) {
applyMaterial(entity);
}
}
{
auto material = getMaterial();
bool newTexturesLoaded = material ? !material->isMissingTexture() : false;
if (!_texturesLoaded && newTexturesLoaded) {
material->checkResetOpacityMap();
}
_texturesLoaded = newTexturesLoaded;
}
if (!_texturesLoaded || _retryApply) {
emit requestRenderUpdate();
}
}
ItemKey MaterialEntityRenderer::getKey() { ItemKey MaterialEntityRenderer::getKey() {
auto builder = ItemKey::Builder().withTypeShape().withTagBits(getTagMask()).withLayer(getHifiRenderLayer()); auto builder = ItemKey::Builder().withTypeShape().withTagBits(getTagMask()).withLayer(getHifiRenderLayer());
@ -276,25 +263,26 @@ void MaterialEntityRenderer::doRender(RenderArgs* args) {
return; return;
} }
Transform renderTransform; graphics::MaterialPointer drawMaterial = getMaterial();
graphics::MaterialPointer drawMaterial;
bool proceduralRender = false; bool proceduralRender = false;
Transform textureTransform; Transform textureTransform;
textureTransform.setTranslation(glm::vec3(_materialMappingPos, 0));
textureTransform.setRotation(glm::vec3(0, 0, glm::radians(_materialMappingRot)));
textureTransform.setScale(glm::vec3(_materialMappingScale, 1));
Transform renderTransform;
withReadLock([&] { withReadLock([&] {
renderTransform = _renderTransform; renderTransform = _renderTransform;
drawMaterial = getMaterial();
textureTransform.setTranslation(glm::vec3(_materialMappingPos, 0));
textureTransform.setRotation(glm::vec3(0, 0, glm::radians(_materialMappingRot)));
textureTransform.setScale(glm::vec3(_materialMappingScale, 1));
if (drawMaterial && drawMaterial->isProcedural() && drawMaterial->isReady()) {
proceduralRender = true;
}
}); });
if (!drawMaterial) { if (!drawMaterial) {
return; return;
} }
if (drawMaterial->isProcedural() && drawMaterial->isReady()) {
proceduralRender = true;
}
batch.setModelTransform(renderTransform); batch.setModelTransform(renderTransform);
if (!proceduralRender) { if (!proceduralRender) {

View file

@ -27,8 +27,8 @@ public:
~MaterialEntityRenderer() { deleteMaterial(_parentID, _parentMaterialName); } ~MaterialEntityRenderer() { deleteMaterial(_parentID, _parentMaterialName); }
private: private:
virtual bool needsRenderUpdate() const override;
virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override; virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override; virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
virtual void doRender(RenderArgs* args) override; virtual void doRender(RenderArgs* args) override;

View file

@ -53,7 +53,7 @@ ModelPointer ModelEntityWrapper::getModel() const {
bool ModelEntityWrapper::isModelLoaded() const { bool ModelEntityWrapper::isModelLoaded() const {
return resultWithReadLock<bool>([&] { return resultWithReadLock<bool>([&] {
return _model.operator bool() && _model->isLoaded(); return _model && _model->isLoaded();
}); });
} }
@ -69,8 +69,7 @@ EntityItemPointer RenderableModelEntityItem::factory(const EntityItemID& entityI
RenderableModelEntityItem::RenderableModelEntityItem(const EntityItemID& entityItemID, bool dimensionsInitialized) : RenderableModelEntityItem::RenderableModelEntityItem(const EntityItemID& entityItemID, bool dimensionsInitialized) :
ModelEntityWrapper(entityItemID), ModelEntityWrapper(entityItemID),
_dimensionsInitialized(dimensionsInitialized) { _dimensionsInitialized(dimensionsInitialized) {
} }
RenderableModelEntityItem::~RenderableModelEntityItem() { } RenderableModelEntityItem::~RenderableModelEntityItem() { }
@ -182,20 +181,24 @@ void RenderableModelEntityItem::updateModelBounds() {
} }
bool overridingModelTransform = model->isOverridingModelTransformAndOffset(); bool overridingModelTransform = model->isOverridingModelTransformAndOffset();
glm::vec3 scaledDimensions = getScaledDimensions();
glm::vec3 registrationPoint = getRegistrationPoint();
QString modelURL = getModelURL();
if (!overridingModelTransform && if (!overridingModelTransform &&
(model->getScaleToFitDimensions() != getScaledDimensions() || (model->getScaleToFitDimensions() != scaledDimensions ||
model->getRegistrationPoint() != getRegistrationPoint() || model->getRegistrationPoint() != registrationPoint ||
model->getURL() != modelURL ||
!model->getIsScaledToFit())) { !model->getIsScaledToFit())) {
// The machinery for updateModelBounds will give existing models the opportunity to fix their // The machinery for updateModelBounds will give existing models the opportunity to fix their
// translation/rotation/scale/registration. The first two are straightforward, but the latter two // translation/rotation/scale/registration. The first two are straightforward, but the latter two
// have guards to make sure they don't happen after they've already been set. Here we reset those guards. // have guards to make sure they don't happen after they've already been set. Here we reset those guards.
// This doesn't cause the entity values to change -- it just allows the model to match once it comes in. // This doesn't cause the entity values to change -- it just allows the model to match once it comes in.
model->setScaleToFit(false, getScaledDimensions()); model->setScaleToFit(false, scaledDimensions);
model->setSnapModelToRegistrationPoint(false, getRegistrationPoint()); model->setSnapModelToRegistrationPoint(false, registrationPoint);
// now recalculate the bounds and registration // now recalculate the bounds and registration
model->setScaleToFit(true, getScaledDimensions()); model->setScaleToFit(true, scaledDimensions);
model->setSnapModelToRegistrationPoint(true, getRegistrationPoint()); model->setSnapModelToRegistrationPoint(true, registrationPoint);
updateRenderItems = true; updateRenderItems = true;
model->scaleToFit(); model->scaleToFit();
} }
@ -248,8 +251,6 @@ EntityItemProperties RenderableModelEntityItem::getProperties(const EntityProper
} }
} }
return properties; return properties;
} }
@ -960,13 +961,13 @@ QStringList RenderableModelEntityItem::getJointNames() const {
} }
scriptable::ScriptableModelBase render::entities::ModelEntityRenderer::getScriptableModel() { scriptable::ScriptableModelBase render::entities::ModelEntityRenderer::getScriptableModel() {
auto model = resultWithReadLock<ModelPointer>([this]{ return _model; }); auto model = resultWithReadLock<ModelPointer>([&] { return _model; });
if (!model || !model->isLoaded()) { if (!model || !model->isLoaded()) {
return scriptable::ScriptableModelBase(); return scriptable::ScriptableModelBase();
} }
auto result = _model->getScriptableModel(); auto result = model->getScriptableModel();
result.objectID = getEntity()->getID(); result.objectID = getEntity()->getID();
{ {
std::lock_guard<std::mutex> lock(_materialsLock); std::lock_guard<std::mutex> lock(_materialsLock);
@ -1054,10 +1055,10 @@ ModelEntityRenderer::ModelEntityRenderer(const EntityItemPointer& entity) : Pare
} }
void ModelEntityRenderer::setKey(bool didVisualGeometryRequestSucceed) { void ModelEntityRenderer::setKey(bool didVisualGeometryRequestSucceed, const ModelPointer& model) {
auto builder = ItemKey::Builder().withTypeMeta().withTagBits(getTagMask()).withLayer(getHifiRenderLayer()); auto builder = ItemKey::Builder().withTypeMeta().withTagBits(getTagMask()).withLayer(getHifiRenderLayer());
if (!_cullWithParent && _model && _model->isGroupCulled()) { if (!_cullWithParent && model && model->isGroupCulled()) {
builder.withMetaCullGroup(); builder.withMetaCullGroup();
} else if (_cullWithParent) { } else if (_cullWithParent) {
builder.withSubMetaCulled(); builder.withSubMetaCulled();
@ -1075,8 +1076,9 @@ ItemKey ModelEntityRenderer::getKey() {
} }
uint32_t ModelEntityRenderer::metaFetchMetaSubItems(ItemIDs& subItems) const { uint32_t ModelEntityRenderer::metaFetchMetaSubItems(ItemIDs& subItems) const {
if (_model) { auto model = resultWithReadLock<ModelPointer>([&] { return _model; });
auto metaSubItems = _model->fetchRenderItemIDs(); if (model) {
auto metaSubItems = model->fetchRenderItemIDs();
subItems.insert(subItems.end(), metaSubItems.begin(), metaSubItems.end()); subItems.insert(subItems.end(), metaSubItems.begin(), metaSubItems.end());
return (uint32_t)metaSubItems.size(); return (uint32_t)metaSubItems.size();
} }
@ -1089,8 +1091,9 @@ void ModelEntityRenderer::handleBlendedVertices(int blendshapeNumber, const QVec
} }
void ModelEntityRenderer::removeFromScene(const ScenePointer& scene, Transaction& transaction) { void ModelEntityRenderer::removeFromScene(const ScenePointer& scene, Transaction& transaction) {
if (_model) { auto model = resultWithReadLock<ModelPointer>([&] { return _model; });
_model->removeFromScene(scene, transaction); if (model) {
model->removeFromScene(scene, transaction);
} }
Parent::removeFromScene(scene, transaction); Parent::removeFromScene(scene, transaction);
} }
@ -1099,7 +1102,7 @@ void ModelEntityRenderer::onRemoveFromSceneTyped(const TypedEntityPointer& entit
entity->setModel({}); entity->setModel({});
} }
void ModelEntityRenderer::animate(const TypedEntityPointer& entity) { void ModelEntityRenderer::animate(const TypedEntityPointer& entity, const ModelPointer& model) {
if (!_animation || !_animation->isLoaded()) { if (!_animation || !_animation->isLoaded()) {
return; return;
} }
@ -1124,17 +1127,17 @@ void ModelEntityRenderer::animate(const TypedEntityPointer& entity) {
_lastKnownCurrentFrame = currentIntegerFrame; _lastKnownCurrentFrame = currentIntegerFrame;
} }
if (_jointMapping.size() != _model->getJointStateCount()) { if (_jointMapping.size() != model->getJointStateCount()) {
qCWarning(entitiesrenderer) << "RenderableModelEntityItem::getAnimationFrame -- joint count mismatch" qCWarning(entitiesrenderer) << "RenderableModelEntityItem::getAnimationFrame -- joint count mismatch"
<< _jointMapping.size() << _model->getJointStateCount(); << _jointMapping.size() << model->getJointStateCount();
return; return;
} }
QStringList animationJointNames = _animation->getHFMModel().getJointNames(); QStringList animationJointNames = _animation->getHFMModel().getJointNames();
auto& hfmJoints = _animation->getHFMModel().joints; auto& hfmJoints = _animation->getHFMModel().joints;
auto& originalHFMJoints = _model->getHFMModel().joints; auto& originalHFMJoints = model->getHFMModel().joints;
auto& originalHFMIndices = _model->getHFMModel().jointIndices; auto& originalHFMIndices = model->getHFMModel().jointIndices;
bool allowTranslation = entity->getAnimationAllowTranslation(); bool allowTranslation = entity->getAnimationAllowTranslation();
@ -1183,90 +1186,39 @@ void ModelEntityRenderer::animate(const TypedEntityPointer& entity) {
} }
bool ModelEntityRenderer::needsRenderUpdate() const { bool ModelEntityRenderer::needsRenderUpdate() const {
if (resultWithReadLock<bool>([&] { //ModelPointer model = resultWithReadLock<ModelPointer>([&] {
if (_moving || _animating) { // return _model;
return true; //});
}
if (!_texturesLoaded) { //if (model) {
return true; // // When the individual mesh parts of a model finish fading, they will mark their Model as needing updating
} // // we will watch for that and ask the model to update it's render items
// if (model->needsReload()) {
// return true;
// }
if (!_prevModelLoaded) { // if (model->needsFixupInScene()) {
return true; // return true;
} // }
//}
return false;
})) {
return true;
}
ModelPointer model;
QUrl parsedModelURL;
withReadLock([&] {
model = _model;
parsedModelURL = _parsedModelURL;
});
if (model) {
// When the individual mesh parts of a model finish fading, they will mark their Model as needing updating
// we will watch for that and ask the model to update it's render items
if (parsedModelURL != model->getURL()) {
return true;
}
if (model->needsReload()) {
return true;
}
if (model->needsFixupInScene()) {
return true;
}
if (model->getRenderItemsNeedUpdate()) {
return true;
}
}
return Parent::needsRenderUpdate(); return Parent::needsRenderUpdate();
} }
bool ModelEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const { bool ModelEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
if (resultWithReadLock<bool>([&] { if (entity->blendshapesChanged()) {
if (entity->hasModel() != _hasModel) { return true;
return true; }
}
// No model to render, early exit // Check to see if we need to update the model bounds
if (!_hasModel) { if (entity->needsUpdateModelBounds()) {
return false; return true;
} }
if (_animating != entity->isAnimatingSomething()) { ModelPointer model = resultWithReadLock<ModelPointer>([&] {
return true; return _model;
}
return false;
})) { return true; }
ModelPointer model;
withReadLock([&] {
model = _model;
}); });
if (model && model->isLoaded()) { if (model && model->isLoaded()) {
if (!entity->_dimensionsInitialized || entity->_needsInitialSimulation || !entity->_originalTexturesRead) {
return true;
}
if (entity->blendshapesChanged()) {
return true;
}
// Check to see if we need to update the model bounds
if (entity->needsUpdateModelBounds()) {
return true;
}
// Check to see if we need to update the model bounds // Check to see if we need to update the model bounds
auto transform = entity->getTransform(); auto transform = entity->getTransform();
if (model->getTranslation() != transform.getTranslation() || if (model->getTranslation() != transform.getTranslation() ||
@ -1280,48 +1232,38 @@ bool ModelEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoin
} }
} }
return false; return Parent::needsRenderUpdateFromTypedEntity(entity);
} }
void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) { void ModelEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
DETAILED_PROFILE_RANGE(simulation_physics, __FUNCTION__); DETAILED_PROFILE_RANGE(simulation_physics, __FUNCTION__);
if (_hasModel != entity->hasModel()) {
withWriteLock([&] { _hasModel = entity->hasModel();
_hasModel = entity->hasModel(); if (_parsedModelURL != entity->getModelURL()) {
}); _parsedModelURL = QUrl(entity->getModelURL());
} }
withWriteLock([&] { ModelPointer model = resultWithReadLock<ModelPointer>([&] {
_animating = entity->isAnimatingSomething(); return _model;
if (_parsedModelURL != entity->getModelURL()) {
_parsedModelURL = QUrl(entity->getModelURL());
}
}); });
ModelPointer model; bool visuallyReady = model && model->isLoaded() && _didLastVisualGeometryRequestSucceed && _texturesLoaded;
withReadLock([&] { model = _model; }); entity->setVisuallyReady(visuallyReady);
withWriteLock([&] { const render::ScenePointer& scene = AbstractViewStateInterface::instance()->getMain3DScene();
bool visuallyReady = true; render::Transaction transaction;
if (_hasModel) {
if (model && _didLastVisualGeometryRequestSucceed) {
visuallyReady = (_prevModelLoaded && _texturesLoaded);
}
}
entity->setVisuallyReady(visuallyReady);
});
// Check for removal // Check for removal
if (!_hasModel) { if (!_hasModel) {
if (model) { if (model) {
model->removeFromScene(scene, transaction); model->removeFromScene(scene, transaction);
entity->bumpAncestorChainRenderableVersion(); entity->bumpAncestorChainRenderableVersion();
withWriteLock([&] { _model.reset(); });
emit DependencyManager::get<scriptable::ModelProviderFactory>()-> emit DependencyManager::get<scriptable::ModelProviderFactory>()->
modelRemovedFromScene(entity->getEntityItemID(), NestableType::Entity, _model); modelRemovedFromScene(entity->getEntityItemID(), NestableType::Entity, model);
withWriteLock([&] { model.reset(); });
} }
setKey(false);
_didLastVisualGeometryRequestSucceed = false; _didLastVisualGeometryRequestSucceed = false;
setKey(_didLastVisualGeometryRequestSucceed, model);
return; return;
} }
@ -1330,18 +1272,28 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
model = std::make_shared<Model>(nullptr, entity.get(), _created); model = std::make_shared<Model>(nullptr, entity.get(), _created);
connect(model.get(), &Model::requestRenderUpdate, this, &ModelEntityRenderer::requestRenderUpdate); connect(model.get(), &Model::requestRenderUpdate, this, &ModelEntityRenderer::requestRenderUpdate);
connect(model.get(), &Model::setURLFinished, this, [&](bool didVisualGeometryRequestSucceed) { connect(model.get(), &Model::setURLFinished, this, [&](bool didVisualGeometryRequestSucceed) {
setKey(didVisualGeometryRequestSucceed); const render::ScenePointer& scene = AbstractViewStateInterface::instance()->getMain3DScene();
_model->setTagMask(getTagMask()); withWriteLock([&] {
_model->setHifiRenderLayer(getHifiRenderLayer()); setKey(didVisualGeometryRequestSucceed, _model);
_model->setPrimitiveMode(_primitiveMode); _model->setVisibleInScene(_visible, scene);
_model->setCullWithParent(_cullWithParent); _model->setCauterized(_cauterized, scene);
_model->setRenderWithZones(_renderWithZones); _model->setCanCastShadow(_canCastShadow, scene);
emit requestRenderUpdate(); _model->setGroupCulled(entity->getGroupCulled(), scene);
_model->setTagMask(getTagMask(), scene);
_model->setHifiRenderLayer(getHifiRenderLayer(), scene);
_model->setPrimitiveMode(_primitiveMode, scene);
_model->setCullWithParent(_cullWithParent, scene);
_model->setRenderWithZones(_renderWithZones, scene);
});
if (didVisualGeometryRequestSucceed) { if (didVisualGeometryRequestSucceed) {
emit DependencyManager::get<scriptable::ModelProviderFactory>()-> emit DependencyManager::get<scriptable::ModelProviderFactory>()->
modelAddedToScene(entity->getEntityItemID(), NestableType::Entity, _model); modelAddedToScene(entity->getEntityItemID(), NestableType::Entity, model);
} }
_didLastVisualGeometryRequestSucceed = didVisualGeometryRequestSucceed; _didLastVisualGeometryRequestSucceed = didVisualGeometryRequestSucceed;
entity->_dimensionsInitialized = false;
entity->_originalTexturesRead = false;
entity->_needsJointSimulation = true;
emit requestRenderUpdate();
}); });
model->setLoadingPriority(EntityTreeRenderer::getEntityLoadingPriority(*entity)); model->setLoadingPriority(EntityTreeRenderer::getEntityLoadingPriority(*entity));
entity->setModel(model); entity->setModel(model);
@ -1350,24 +1302,15 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
// From here on, we are guaranteed a populated model // From here on, we are guaranteed a populated model
if (_parsedModelURL != model->getURL()) { if (_parsedModelURL != model->getURL()) {
withWriteLock([&] { _texturesLoaded = false;
_texturesLoaded = false; _jointMappingCompleted = false;
_jointMappingCompleted = false; model->setURL(_parsedModelURL);
model->setURL(_parsedModelURL);
});
} }
// Nothing else to do unless the model is loaded // Nothing else to do unless the model is loaded
if (!model->isLoaded()) { if (!model->isLoaded()) {
withWriteLock([&] {
_prevModelLoaded = false;
});
emit requestRenderUpdate(); emit requestRenderUpdate();
return; return;
} else if (!_prevModelLoaded) {
withWriteLock([&] {
_prevModelLoaded = true;
});
} }
// Check for initializing the model // Check for initializing the model
@ -1383,6 +1326,7 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
QMetaObject::invokeMethod(DependencyManager::get<EntityScriptingInterface>().data(), "editEntity", QMetaObject::invokeMethod(DependencyManager::get<EntityScriptingInterface>().data(), "editEntity",
Qt::QueuedConnection, Q_ARG(QUuid, entity->getEntityItemID()), Q_ARG(EntityItemProperties, properties)); Qt::QueuedConnection, Q_ARG(QUuid, entity->getEntityItemID()), Q_ARG(EntityItemProperties, properties));
entity->_dimensionsInitialized = true;
} }
if (!entity->_originalTexturesRead) { if (!entity->_originalTexturesRead) {
@ -1393,51 +1337,34 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
if (_textures != entity->getTextures()) { if (_textures != entity->getTextures()) {
QVariantMap newTextures; QVariantMap newTextures;
withWriteLock([&] { _texturesLoaded = false;
_texturesLoaded = false; _textures = entity->getTextures();
_textures = entity->getTextures(); newTextures = parseTexturesToMap(_textures, entity->_originalTextures);
newTextures = parseTexturesToMap(_textures, entity->_originalTextures);
});
model->setTextures(newTextures); model->setTextures(newTextures);
} }
if (entity->_needsJointSimulation) { if (entity->_needsJointSimulation) {
entity->copyAnimationJointDataToModel(); entity->copyAnimationJointDataToModel();
} }
entity->updateModelBounds(); entity->updateModelBounds();
entity->stopModelOverrideIfNoParent(); entity->stopModelOverrideIfNoParent();
if (model->isVisible() != _visible) { setKey(_didLastVisualGeometryRequestSucceed, model);
model->setVisibleInScene(_visible, scene); model->setVisibleInScene(_visible, scene);
} model->setCauterized(_cauterized, scene);
model->setCanCastShadow(_canCastShadow, scene);
if (model->isCauterized() != _cauterized) { model->setGroupCulled(entity->getGroupCulled(), scene);
model->setCauterized(_cauterized, scene); model->setTagMask(getTagMask(), scene);
} model->setHifiRenderLayer(getHifiRenderLayer(), scene);
model->setPrimitiveMode(_primitiveMode, scene);
render::hifi::Tag tagMask = getTagMask(); model->setCullWithParent(_cullWithParent, scene);
if (model->getTagMask() != tagMask) { model->setRenderWithZones(_renderWithZones, scene);
model->setTagMask(tagMask, scene);
}
if (entity->blendshapesChanged()) { if (entity->blendshapesChanged()) {
model->setBlendshapeCoefficients(entity->getBlendshapeCoefficientVector()); model->setBlendshapeCoefficients(entity->getBlendshapeCoefficientVector());
model->updateBlendshapes(); model->updateBlendshapes();
} }
// TODO? early exit here when not visible?
if (model->canCastShadow() != _canCastShadow) {
model->setCanCastShadow(_canCastShadow, scene);
}
{
bool groupCulled = entity->getGroupCulled();
if (model->isGroupCulled() != groupCulled) {
model->setGroupCulled(groupCulled);
setKey(_didLastVisualGeometryRequestSucceed);
}
}
{ {
DETAILED_PROFILE_RANGE(simulation_physics, "Fixup"); DETAILED_PROFILE_RANGE(simulation_physics, "Fixup");
if (model->needsFixupInScene()) { if (model->needsFixupInScene()) {
@ -1452,9 +1379,7 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
} }
if (!_texturesLoaded && model->getGeometry() && model->getGeometry()->areTexturesLoaded()) { if (!_texturesLoaded && model->getGeometry() && model->getGeometry()->areTexturesLoaded()) {
withWriteLock([&] { _texturesLoaded = true;
_texturesLoaded = true;
});
model->updateRenderItems(); model->updateRenderItems();
} else if (!_texturesLoaded) { } else if (!_texturesLoaded) {
emit requestRenderUpdate(); emit requestRenderUpdate();
@ -1491,9 +1416,13 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
model->updateRenderItems(); model->updateRenderItems();
} }
scene->enqueueTransaction(transaction);
}
void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
// The code to deal with the change of properties is now in ModelEntityItem.cpp // The code to deal with the change of properties is now in ModelEntityItem.cpp
// That is where _currentFrame and _lastAnimated were updated. // That is where _currentFrame and _lastAnimated were updated.
if (_animating) { if (entity->isAnimatingSomething()) {
DETAILED_PROFILE_RANGE(simulation_physics, "Animate"); DETAILED_PROFILE_RANGE(simulation_physics, "Animate");
auto animationURL = entity->getAnimationURL(); auto animationURL = entity->getAnimationURL();
@ -1502,18 +1431,20 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
_animationURL = animationURL; _animationURL = animationURL;
if (_animation) { if (_animation) {
//(_animation->getURL().toString() != entity->getAnimationURL())) { // bad check
// the joints have been mapped before but we have a new animation to load // the joints have been mapped before but we have a new animation to load
_animation.reset(); _animation.reset();
_jointMappingCompleted = false; _jointMappingCompleted = false;
} }
} }
ModelPointer model = resultWithReadLock<ModelPointer>([&] {
return _model;
});
if (!_jointMappingCompleted) { if (!_jointMappingCompleted) {
mapJoints(entity, model); mapJoints(entity, model);
} }
if (entity->readyToAnimate()) { if (entity->readyToAnimate() && model && model->isLoaded()) {
animate(entity); animate(entity, model);
} }
emit requestRenderUpdate(); emit requestRenderUpdate();
} }
@ -1521,40 +1452,20 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
void ModelEntityRenderer::setIsVisibleInSecondaryCamera(bool value) { void ModelEntityRenderer::setIsVisibleInSecondaryCamera(bool value) {
Parent::setIsVisibleInSecondaryCamera(value); Parent::setIsVisibleInSecondaryCamera(value);
setKey(_didLastVisualGeometryRequestSucceed); // called within a lock so no need to lock for _model
if (_model) { setKey(_didLastVisualGeometryRequestSucceed, _model);
_model->setTagMask(getTagMask());
}
} }
void ModelEntityRenderer::setRenderLayer(RenderLayer value) { void ModelEntityRenderer::setRenderLayer(RenderLayer value) {
Parent::setRenderLayer(value); Parent::setRenderLayer(value);
setKey(_didLastVisualGeometryRequestSucceed); // called within a lock so no need to lock for _model
if (_model) { setKey(_didLastVisualGeometryRequestSucceed, _model);
_model->setHifiRenderLayer(getHifiRenderLayer());
}
}
void ModelEntityRenderer::setPrimitiveMode(PrimitiveMode value) {
Parent::setPrimitiveMode(value);
if (_model) {
_model->setPrimitiveMode(_primitiveMode);
}
} }
void ModelEntityRenderer::setCullWithParent(bool value) { void ModelEntityRenderer::setCullWithParent(bool value) {
Parent::setCullWithParent(value); Parent::setCullWithParent(value);
setKey(_didLastVisualGeometryRequestSucceed); // called within a lock so no need to lock for _model
if (_model) { setKey(_didLastVisualGeometryRequestSucceed, _model);
_model->setCullWithParent(_cullWithParent);
}
}
void ModelEntityRenderer::setRenderWithZones(const QVector<QUuid>& renderWithZones) {
Parent::setRenderWithZones(renderWithZones);
if (_model) {
_model->setRenderWithZones(renderWithZones);
}
} }
// 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
@ -1570,9 +1481,8 @@ void ModelEntityRenderer::doRender(RenderArgs* args) {
geometryCache->renderWireCubeInstance(args, batch, greenColor, geometryCache->getShapePipelinePointer(false, false, args->_renderMethod == Args::RenderMethod::FORWARD)); geometryCache->renderWireCubeInstance(args, batch, greenColor, geometryCache->getShapePipelinePointer(false, false, args->_renderMethod == Args::RenderMethod::FORWARD));
#if WANT_EXTRA_DEBUGGING #if WANT_EXTRA_DEBUGGING
ModelPointer model; ModelPointer model = resultWithReadLock<ModelPointer>([&] {
withReadLock([&] { return _model;
model = _model;
}); });
if (model) { if (model) {
model->renderDebugMeshBoxes(batch, args->_renderMethod == Args::RenderMethod::FORWARD); model->renderDebugMeshBoxes(batch, args->_renderMethod == Args::RenderMethod::FORWARD);

View file

@ -153,25 +153,24 @@ protected:
virtual void removeFromScene(const ScenePointer& scene, Transaction& transaction) override; virtual void removeFromScene(const ScenePointer& scene, Transaction& transaction) override;
virtual void onRemoveFromSceneTyped(const TypedEntityPointer& entity) override; virtual void onRemoveFromSceneTyped(const TypedEntityPointer& entity) override;
void setKey(bool didVisualGeometryRequestSucceed); void setKey(bool didVisualGeometryRequestSucceed, const ModelPointer& model);
virtual ItemKey getKey() override; virtual ItemKey getKey() override;
virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) const override; virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) const override;
virtual void handleBlendedVertices(int blendshapeNumber, const QVector<BlendshapeOffset>& blendshapeOffsets, virtual void handleBlendedVertices(int blendshapeNumber, const QVector<BlendshapeOffset>& blendshapeOffsets,
const QVector<int>& blendedMeshSizes, const render::ItemIDs& subItemIDs) override; const QVector<int>& blendedMeshSizes, const render::ItemIDs& subItemIDs) override;
virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
virtual bool needsRenderUpdate() const override; virtual bool needsRenderUpdate() const override;
virtual void doRender(RenderArgs* args) override; virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override; virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
virtual void doRender(RenderArgs* args) override;
void setIsVisibleInSecondaryCamera(bool value) override; void setIsVisibleInSecondaryCamera(bool value) override;
void setRenderLayer(RenderLayer value) override; void setRenderLayer(RenderLayer value) override;
void setPrimitiveMode(PrimitiveMode value) override;
void setCullWithParent(bool value) override; void setCullWithParent(bool value) override;
void setRenderWithZones(const QVector<QUuid>& renderWithZones) override;
private: private:
void animate(const TypedEntityPointer& entity); void animate(const TypedEntityPointer& entity, const ModelPointer& model);
void mapJoints(const TypedEntityPointer& entity, const ModelPointer& model); void mapJoints(const TypedEntityPointer& entity, const ModelPointer& model);
// Transparency is handled in ModelMeshPartPayload // Transparency is handled in ModelMeshPartPayload
@ -192,14 +191,12 @@ private:
bool _jointMappingCompleted { false }; bool _jointMappingCompleted { false };
QVector<int> _jointMapping; // domain is index into model-joints, range is index into animation-joints QVector<int> _jointMapping; // domain is index into model-joints, range is index into animation-joints
AnimationPointer _animation; AnimationPointer _animation;
bool _animating { false };
QString _animationURL; QString _animationURL;
uint64_t _lastAnimated { 0 }; uint64_t _lastAnimated { 0 };
render::ItemKey _itemKey { render::ItemKey::Builder().withTypeMeta() }; render::ItemKey _itemKey { render::ItemKey::Builder().withTypeMeta() };
bool _didLastVisualGeometryRequestSucceed { true }; bool _didLastVisualGeometryRequestSucceed { true };
bool _prevModelLoaded { false };
void processMaterials(); void processMaterials();
bool _allProceduralMaterialsLoaded { false }; bool _allProceduralMaterialsLoaded { false };

View file

@ -78,7 +78,14 @@ void LightEntityItem::setFalloffRadius(float value) {
} }
void LightEntityItem::setIsSpotlight(bool value) { void LightEntityItem::setIsSpotlight(bool value) {
if (value == getIsSpotlight()) { bool needsRenderUpdate;
withWriteLock([&] {
needsRenderUpdate = value != _isSpotlight;
_needsRenderUpdate |= needsRenderUpdate;
_isSpotlight = value;
});
if (!needsRenderUpdate) {
return; return;
} }
@ -92,25 +99,25 @@ void LightEntityItem::setIsSpotlight(bool value) {
newDimensions = glm::vec3(glm::compMax(dimensions)); newDimensions = glm::vec3(glm::compMax(dimensions));
} }
withWriteLock([&] {
_needsRenderUpdate = true;
_isSpotlight = value;
});
setScaledDimensions(newDimensions); setScaledDimensions(newDimensions);
} }
void LightEntityItem::setCutoff(float value) { void LightEntityItem::setCutoff(float value) {
value = glm::clamp(value, MIN_CUTOFF, MAX_CUTOFF); value = glm::clamp(value, MIN_CUTOFF, MAX_CUTOFF);
if (value == getCutoff()) { bool needsRenderUpdate;
bool spotlight;
withWriteLock([&] {
needsRenderUpdate = value != _cutoff;
_needsRenderUpdate |= needsRenderUpdate;
_cutoff = value;
spotlight = _isSpotlight;
});
if (!needsRenderUpdate) {
return; return;
} }
withWriteLock([&] { if (spotlight) {
_needsRenderUpdate = true;
_cutoff = value;
});
if (getIsSpotlight()) {
// If we are a spotlight, adjusting the cutoff will affect the area we encapsulate, // If we are a spotlight, adjusting the cutoff will affect the area we encapsulate,
// so update the dimensions to reflect this. // so update the dimensions to reflect this.
const float length = getScaledDimensions().z; const float length = getScaledDimensions().z;

View file

@ -330,13 +330,6 @@ void ModelEntityItem::setCompoundShapeURL(const QString& url) {
}); });
} }
void ModelEntityItem::setAnimationURL(const QString& url) {
_flags |= Simulation::DIRTY_UPDATEABLE;
withWriteLock([&] {
_animationProperties.setURL(url);
});
}
void ModelEntityItem::setAnimationSettings(const QString& value) { void ModelEntityItem::setAnimationSettings(const QString& value) {
// NOTE: this method only called for old bitstream format // NOTE: this method only called for old bitstream format
@ -399,20 +392,6 @@ void ModelEntityItem::setAnimationSettings(const QString& value) {
}); });
} }
void ModelEntityItem::setAnimationIsPlaying(bool value) {
_flags |= Simulation::DIRTY_UPDATEABLE;
withWriteLock([&] {
_animationProperties.setRunning(value);
});
}
void ModelEntityItem::setAnimationFPS(float value) {
_flags |= Simulation::DIRTY_UPDATEABLE;
withWriteLock([&] {
_animationProperties.setFPS(value);
});
}
void ModelEntityItem::resizeJointArrays(int newSize) { void ModelEntityItem::resizeJointArrays(int newSize) {
if (newSize < 0) { if (newSize < 0) {
return; return;
@ -629,61 +608,18 @@ void ModelEntityItem::setAnimationCurrentFrame(float value) {
}); });
} }
void ModelEntityItem::setAnimationAllowTranslation(bool value) {
withWriteLock([&] {
_animationProperties.setAllowTranslation(value);
});
}
bool ModelEntityItem::getAnimationAllowTranslation() const { bool ModelEntityItem::getAnimationAllowTranslation() const {
return resultWithReadLock<bool>([&] { return resultWithReadLock<bool>([&] {
return _animationProperties.getAllowTranslation(); return _animationProperties.getAllowTranslation();
}); });
} }
void ModelEntityItem::setAnimationLoop(bool loop) {
withWriteLock([&] {
_animationProperties.setLoop(loop);
});
}
bool ModelEntityItem::getAnimationLoop() const {
return resultWithReadLock<bool>([&] {
return _animationProperties.getLoop();
});
}
void ModelEntityItem::setAnimationHold(bool hold) {
withWriteLock([&] {
_animationProperties.setHold(hold);
});
}
bool ModelEntityItem::getAnimationHold() const {
return resultWithReadLock<bool>([&] {
return _animationProperties.getHold();
});
}
bool ModelEntityItem::getAnimationIsPlaying() const {
return resultWithReadLock<bool>([&] {
return _animationProperties.getRunning();
});
}
float ModelEntityItem::getAnimationCurrentFrame() const { float ModelEntityItem::getAnimationCurrentFrame() const {
return resultWithReadLock<float>([&] { return resultWithReadLock<float>([&] {
return _animationProperties.getCurrentFrame(); return _animationProperties.getCurrentFrame();
}); });
} }
float ModelEntityItem::getAnimationFPS() const {
return resultWithReadLock<float>([&] {
return _animationProperties.getFPS();
});
}
bool ModelEntityItem::isAnimatingSomething() const { bool ModelEntityItem::isAnimatingSomething() const {
return resultWithReadLock<bool>([&] { return resultWithReadLock<bool>([&] {
return _animationProperties.isValidAndRunning(); return _animationProperties.isValidAndRunning();
@ -722,6 +658,7 @@ bool ModelEntityItem::applyNewAnimationProperties(AnimationPropertyGroup newProp
bool somethingChanged = newProperties != _animationProperties; bool somethingChanged = newProperties != _animationProperties;
if (somethingChanged) { if (somethingChanged) {
_animationProperties = newProperties; _animationProperties = newProperties;
_needsRenderUpdate = true;
_flags |= Simulation::DIRTY_UPDATEABLE; _flags |= Simulation::DIRTY_UPDATEABLE;
} }
return somethingChanged; return somethingChanged;

View file

@ -85,24 +85,12 @@ public:
// Animation related items... // Animation related items...
AnimationPropertyGroup getAnimationProperties() const; AnimationPropertyGroup getAnimationProperties() const;
// TODO: audit and remove unused Animation accessors
bool hasAnimation() const; bool hasAnimation() const;
QString getAnimationURL() const; QString getAnimationURL() const;
virtual void setAnimationURL(const QString& url);
void setAnimationCurrentFrame(float value); void setAnimationCurrentFrame(float value);
void setAnimationIsPlaying(bool value); float getAnimationCurrentFrame() const;
void setAnimationFPS(float value);
void setAnimationAllowTranslation(bool value);
bool getAnimationAllowTranslation() const; bool getAnimationAllowTranslation() const;
bool isAnimatingSomething() const;
void setAnimationLoop(bool loop);
bool getAnimationLoop() const;
void setAnimationHold(bool hold);
bool getAnimationHold() const;
void setRelayParentJoints(bool relayJoints); void setRelayParentJoints(bool relayJoints);
bool getRelayParentJoints() const; bool getRelayParentJoints() const;
@ -110,11 +98,6 @@ public:
void setGroupCulled(bool value); void setGroupCulled(bool value);
bool getGroupCulled() const; bool getGroupCulled() const;
bool getAnimationIsPlaying() const;
float getAnimationCurrentFrame() const;
float getAnimationFPS() const;
bool isAnimatingSomething() const;
static const QString DEFAULT_TEXTURES; static const QString DEFAULT_TEXTURES;
const QString getTextures() const; const QString getTextures() const;
void setTextures(const QString& textures); void setTextures(const QString& textures);

View file

@ -958,16 +958,20 @@ void Model::setCauterized(bool cauterized, const render::ScenePointer& scene) {
} }
} }
void Model::setPrimitiveMode(PrimitiveMode primitiveMode) { void Model::setPrimitiveMode(PrimitiveMode primitiveMode, const render::ScenePointer& scene) {
if (_primitiveMode != primitiveMode) { if (_primitiveMode != primitiveMode) {
_primitiveMode = primitiveMode; _primitiveMode = primitiveMode;
updateRenderItemsKey(nullptr); updateRenderItemsKey(scene);
} }
} }
void Model::setCullWithParent(bool cullWithParent) { void Model::setCullWithParent(bool cullWithParent, const render::ScenePointer& scene) {
if (_cullWithParent != cullWithParent) { if (_cullWithParent != cullWithParent) {
_cullWithParent = cullWithParent; _cullWithParent = cullWithParent;
if (!scene) {
_needsFixupInScene = true;
return;
}
render::Transaction transaction; render::Transaction transaction;
auto renderItemsKey = _renderItemKeyGlobalFlags; auto renderItemsKey = _renderItemKeyGlobalFlags;
@ -977,14 +981,27 @@ void Model::setCullWithParent(bool cullWithParent) {
data.updateKey(renderItemsKey); data.updateKey(renderItemsKey);
}); });
} }
AbstractViewStateInterface::instance()->getMain3DScene()->enqueueTransaction(transaction); scene->enqueueTransaction(transaction);
} }
} }
void Model::setRenderWithZones(const QVector<QUuid>& renderWithZones) { void Model::setRenderWithZones(const QVector<QUuid>& renderWithZones, const render::ScenePointer& scene) {
if (_renderWithZones != renderWithZones) { if (_renderWithZones != renderWithZones) {
_renderWithZones = renderWithZones; _renderWithZones = renderWithZones;
setRenderItemsNeedUpdate();
if (!scene) {
_needsFixupInScene = true;
return;
}
render::Transaction transaction;
auto renderItemsKey = _renderItemKeyGlobalFlags;
for (auto item : _modelMeshRenderItemIDs) {
transaction.updateItem<ModelMeshPartPayload>(item, [renderWithZones, renderItemsKey](ModelMeshPartPayload& data) {
data.setRenderWithZones(renderWithZones);
});
}
scene->enqueueTransaction(transaction);
} }
} }

View file

@ -116,14 +116,14 @@ public:
void setHifiRenderLayer(render::hifi::Layer layer, const render::ScenePointer& scene = nullptr); void setHifiRenderLayer(render::hifi::Layer layer, const render::ScenePointer& scene = nullptr);
bool isCauterized() const { return _cauterized; } bool isCauterized() const { return _cauterized; }
void setCauterized(bool value, const render::ScenePointer& scene); void setCauterized(bool value, const render::ScenePointer& scene = nullptr);
void setPrimitiveMode(PrimitiveMode primitiveMode); void setPrimitiveMode(PrimitiveMode primitiveMode, const render::ScenePointer& scene = nullptr);
PrimitiveMode getPrimitiveMode() const { return _primitiveMode; } PrimitiveMode getPrimitiveMode() const { return _primitiveMode; }
void setCullWithParent(bool value); void setCullWithParent(bool value, const render::ScenePointer& scene = nullptr);
void setRenderWithZones(const QVector<QUuid>& renderWithZones); void setRenderWithZones(const QVector<QUuid>& renderWithZones, const render::ScenePointer& scene = nullptr);
const QVector<QUuid>& getRenderWithZones() const { return _renderWithZones; } const QVector<QUuid>& getRenderWithZones() const { return _renderWithZones; }
// Access the current RenderItemKey Global Flags used by the model and applied to the render items representing the parts of the model. // Access the current RenderItemKey Global Flags used by the model and applied to the render items representing the parts of the model.