mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 05:37:17 +02:00
Merge pull request #7523 from zzmp/fix/tex-load-fixup
Render alpha textures immediately
This commit is contained in:
commit
1e7a69fb90
5 changed files with 108 additions and 119 deletions
|
@ -116,11 +116,18 @@ QVariantMap RenderableModelEntityItem::parseTexturesToMap(QString textures) {
|
||||||
|
|
||||||
QJsonParseError error;
|
QJsonParseError error;
|
||||||
QJsonDocument texturesJson = QJsonDocument::fromJson(textures.toUtf8(), &error);
|
QJsonDocument texturesJson = QJsonDocument::fromJson(textures.toUtf8(), &error);
|
||||||
|
// If textures are invalid, revert to original textures
|
||||||
if (error.error != QJsonParseError::NoError) {
|
if (error.error != QJsonParseError::NoError) {
|
||||||
qCWarning(entitiesrenderer) << "Could not evaluate textures property value:" << textures;
|
qCWarning(entitiesrenderer) << "Could not evaluate textures property value:" << textures;
|
||||||
return _originalTextures;
|
return _originalTextures;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVariantMap texturesMap = texturesJson.toVariant().toMap();
|
||||||
|
// If textures are unset, revert to original textures
|
||||||
|
if (texturesMap.isEmpty()) {
|
||||||
|
return _originalTextures;
|
||||||
|
}
|
||||||
|
|
||||||
return texturesJson.toVariant().toMap();
|
return texturesJson.toVariant().toMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,10 +140,8 @@ void RenderableModelEntityItem::remapTextures() {
|
||||||
return; // nothing to do if the model has not yet loaded
|
return; // nothing to do if the model has not yet loaded
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& geometry = _model->getGeometry()->getGeometry();
|
|
||||||
|
|
||||||
if (!_originalTexturesRead) {
|
if (!_originalTexturesRead) {
|
||||||
_originalTextures = geometry->getTextures();
|
_originalTextures = _model->getTextures();
|
||||||
_originalTexturesRead = true;
|
_originalTexturesRead = true;
|
||||||
|
|
||||||
// Default to _originalTextures to avoid remapping immediately and lagging on load
|
// Default to _originalTextures to avoid remapping immediately and lagging on load
|
||||||
|
@ -152,7 +157,7 @@ void RenderableModelEntityItem::remapTextures() {
|
||||||
auto newTextures = parseTexturesToMap(textures);
|
auto newTextures = parseTexturesToMap(textures);
|
||||||
|
|
||||||
if (newTextures != _currentTextures) {
|
if (newTextures != _currentTextures) {
|
||||||
geometry->setTextures(newTextures);
|
_model->setTextures(newTextures);
|
||||||
_currentTextures = newTextures;
|
_currentTextures = newTextures;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -366,41 +371,16 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
|
||||||
assert(getType() == EntityTypes::Model);
|
assert(getType() == EntityTypes::Model);
|
||||||
|
|
||||||
if (hasModel()) {
|
if (hasModel()) {
|
||||||
if (_model) {
|
// Prepare the current frame
|
||||||
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
|
|
||||||
|
|
||||||
// check to see if when we added our models to the scene they were ready, if they were not ready, then
|
|
||||||
// fix them up in the scene
|
|
||||||
bool shouldShowCollisionHull = (args->_debugFlags & (int)RenderArgs::RENDER_DEBUG_HULLS) > 0;
|
|
||||||
if (_model->needsFixupInScene() || _showCollisionHull != shouldShowCollisionHull) {
|
|
||||||
_showCollisionHull = shouldShowCollisionHull;
|
|
||||||
render::PendingChanges pendingChanges;
|
|
||||||
|
|
||||||
_model->removeFromScene(scene, pendingChanges);
|
|
||||||
|
|
||||||
render::Item::Status::Getters statusGetters;
|
|
||||||
makeEntityItemStatusGetters(getThisPointer(), statusGetters);
|
|
||||||
_model->addToScene(scene, pendingChanges, statusGetters, _showCollisionHull);
|
|
||||||
|
|
||||||
scene->enqueuePendingChanges(pendingChanges);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
// so most of the time we don't do anything in this function.
|
|
||||||
_model->setVisibleInScene(getVisible(), scene);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
remapTextures();
|
|
||||||
{
|
{
|
||||||
// float alpha = getLocalRenderAlpha();
|
|
||||||
|
|
||||||
if (!_model || _needsModelReload) {
|
if (!_model || _needsModelReload) {
|
||||||
// TODO: this getModel() appears to be about 3% of model render time. We should optimize
|
// TODO: this getModel() appears to be about 3% of model render time. We should optimize
|
||||||
PerformanceTimer perfTimer("getModel");
|
PerformanceTimer perfTimer("getModel");
|
||||||
EntityTreeRenderer* renderer = static_cast<EntityTreeRenderer*>(args->_renderer);
|
EntityTreeRenderer* renderer = static_cast<EntityTreeRenderer*>(args->_renderer);
|
||||||
getModel(renderer);
|
getModel(renderer);
|
||||||
|
|
||||||
|
// Remap textures immediately after loading to avoid flicker
|
||||||
|
remapTextures();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_model) {
|
if (_model) {
|
||||||
|
@ -431,15 +411,40 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
updateModelBounds();
|
updateModelBounds();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check if the URL has changed
|
// Enqueue updates for the next frame
|
||||||
// Do this last as the getModel is queued for the next frame,
|
if (_model) {
|
||||||
// and we need to keep state directing the model to reinitialize
|
|
||||||
auto& currentURL = getParsedModelURL();
|
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
|
||||||
if (currentURL != _model->getURL()) {
|
|
||||||
// Defer setting the url to the render thread
|
// FIXME: this seems like it could be optimized if we tracked our last known visible state in
|
||||||
getModel(_myRenderer);
|
// the renderable item. As it stands now the model checks it's visible/invisible state
|
||||||
}
|
// so most of the time we don't do anything in this function.
|
||||||
|
_model->setVisibleInScene(getVisible(), scene);
|
||||||
|
|
||||||
|
// Remap textures for the next frame to avoid flicker
|
||||||
|
remapTextures();
|
||||||
|
|
||||||
|
// check to see if when we added our models to the scene they were ready, if they were not ready, then
|
||||||
|
// fix them up in the scene
|
||||||
|
bool shouldShowCollisionHull = (args->_debugFlags & (int)RenderArgs::RENDER_DEBUG_HULLS) > 0;
|
||||||
|
if (_model->needsFixupInScene() || _showCollisionHull != shouldShowCollisionHull) {
|
||||||
|
_showCollisionHull = shouldShowCollisionHull;
|
||||||
|
render::PendingChanges pendingChanges;
|
||||||
|
|
||||||
|
render::Item::Status::Getters statusGetters;
|
||||||
|
makeEntityItemStatusGetters(getThisPointer(), statusGetters);
|
||||||
|
_model->addToScene(scene, pendingChanges, statusGetters, _showCollisionHull);
|
||||||
|
|
||||||
|
scene->enqueuePendingChanges(pendingChanges);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& currentURL = getParsedModelURL();
|
||||||
|
if (currentURL != _model->getURL()) {
|
||||||
|
// Defer setting the url to the render thread
|
||||||
|
getModel(_myRenderer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -279,6 +279,9 @@ void Geometry::setTextures(const QVariantMap& textureMap) {
|
||||||
|
|
||||||
material->setTextures(textureMap);
|
material->setTextures(textureMap);
|
||||||
_areTexturesLoaded = false;
|
_areTexturesLoaded = false;
|
||||||
|
|
||||||
|
// If we only use cached textures, they should all be loaded
|
||||||
|
areTexturesLoaded();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -288,8 +291,6 @@ void Geometry::setTextures(const QVariantMap& textureMap) {
|
||||||
|
|
||||||
bool Geometry::areTexturesLoaded() const {
|
bool Geometry::areTexturesLoaded() const {
|
||||||
if (!_areTexturesLoaded) {
|
if (!_areTexturesLoaded) {
|
||||||
_hasTransparentTextures = false;
|
|
||||||
|
|
||||||
for (auto& material : _materials) {
|
for (auto& material : _materials) {
|
||||||
// Check if material textures are loaded
|
// Check if material textures are loaded
|
||||||
if (std::any_of(material->_textures.cbegin(), material->_textures.cend(),
|
if (std::any_of(material->_textures.cbegin(), material->_textures.cend(),
|
||||||
|
@ -302,8 +303,6 @@ bool Geometry::areTexturesLoaded() const {
|
||||||
const auto albedoTexture = material->_textures[NetworkMaterial::MapChannel::ALBEDO_MAP];
|
const auto albedoTexture = material->_textures[NetworkMaterial::MapChannel::ALBEDO_MAP];
|
||||||
if (albedoTexture.texture && albedoTexture.texture->getGPUTexture()) {
|
if (albedoTexture.texture && albedoTexture.texture->getGPUTexture()) {
|
||||||
material->resetOpacityMap();
|
material->resetOpacityMap();
|
||||||
|
|
||||||
_hasTransparentTextures |= material->getKey().isTranslucent();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -74,9 +74,6 @@ public:
|
||||||
void setTextures(const QVariantMap& textureMap);
|
void setTextures(const QVariantMap& textureMap);
|
||||||
|
|
||||||
virtual bool areTexturesLoaded() const;
|
virtual bool areTexturesLoaded() const;
|
||||||
// Returns true if any albedo texture has a non-masking alpha channel.
|
|
||||||
// This can only be known after areTexturesLoaded().
|
|
||||||
bool hasTransparentTextures() const { return _hasTransparentTextures; }
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class GeometryMappingResource;
|
friend class GeometryMappingResource;
|
||||||
|
@ -91,7 +88,6 @@ protected:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
mutable bool _areTexturesLoaded { false };
|
mutable bool _areTexturesLoaded { false };
|
||||||
mutable bool _hasTransparentTextures { false };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A geometry loaded from the network.
|
/// A geometry loaded from the network.
|
||||||
|
|
|
@ -76,14 +76,9 @@ AbstractViewStateInterface* Model::_viewState = NULL;
|
||||||
|
|
||||||
bool Model::needsFixupInScene() const {
|
bool Model::needsFixupInScene() const {
|
||||||
if (readyToAddToScene()) {
|
if (readyToAddToScene()) {
|
||||||
// Once textures are loaded, fixup if they are now transparent
|
if (_needsUpdateTextures && _geometry->getGeometry()->areTexturesLoaded()) {
|
||||||
if (_needsUpdateTransparentTextures && _geometry->getGeometry()->areTexturesLoaded()) {
|
_needsUpdateTextures = false;
|
||||||
_needsUpdateTransparentTextures = false;
|
return true;
|
||||||
bool hasTransparentTextures = _geometry->getGeometry()->hasTransparentTextures();
|
|
||||||
if (_hasTransparentTextures != hasTransparentTextures) {
|
|
||||||
_hasTransparentTextures = hasTransparentTextures;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (!_readyWhenAdded) {
|
if (!_readyWhenAdded) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -546,43 +541,6 @@ void Model::setVisibleInScene(bool newValue, std::shared_ptr<render::Scene> scen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Model::addToScene(std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges, bool showCollisionHull) {
|
|
||||||
|
|
||||||
if ((!_meshGroupsKnown || showCollisionHull != _showCollisionHull) && isLoaded()) {
|
|
||||||
_showCollisionHull = showCollisionHull;
|
|
||||||
segregateMeshGroups();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool somethingAdded = false;
|
|
||||||
|
|
||||||
foreach (auto renderItem, _modelMeshRenderItemsSet) {
|
|
||||||
auto item = scene->allocateID();
|
|
||||||
auto renderPayload = std::make_shared<ModelMeshPartPayload::Payload>(renderItem);
|
|
||||||
pendingChanges.resetItem(item, renderPayload);
|
|
||||||
pendingChanges.updateItem<ModelMeshPartPayload>(item, [](ModelMeshPartPayload& data) {
|
|
||||||
data.notifyLocationChanged();
|
|
||||||
});
|
|
||||||
_modelMeshRenderItems.insert(item, renderPayload);
|
|
||||||
somethingAdded = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (auto renderItem, _collisionRenderItemsSet) {
|
|
||||||
auto item = scene->allocateID();
|
|
||||||
auto renderPayload = std::make_shared<MeshPartPayload::Payload>(renderItem);
|
|
||||||
pendingChanges.resetItem(item, renderPayload);
|
|
||||||
pendingChanges.updateItem<MeshPartPayload>(item, [](MeshPartPayload& data) {
|
|
||||||
data.notifyLocationChanged();
|
|
||||||
});
|
|
||||||
_collisionRenderItems.insert(item, renderPayload);
|
|
||||||
somethingAdded = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
_readyWhenAdded = readyToAddToScene();
|
|
||||||
|
|
||||||
return somethingAdded;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Model::addToScene(std::shared_ptr<render::Scene> scene,
|
bool Model::addToScene(std::shared_ptr<render::Scene> scene,
|
||||||
render::PendingChanges& pendingChanges,
|
render::PendingChanges& pendingChanges,
|
||||||
render::Item::Status::Getters& statusGetters,
|
render::Item::Status::Getters& statusGetters,
|
||||||
|
@ -594,28 +552,48 @@ bool Model::addToScene(std::shared_ptr<render::Scene> scene,
|
||||||
|
|
||||||
bool somethingAdded = false;
|
bool somethingAdded = false;
|
||||||
|
|
||||||
foreach (auto renderItem, _modelMeshRenderItemsSet) {
|
if (_modelMeshRenderItems.size()) {
|
||||||
auto item = scene->allocateID();
|
for (auto item : _modelMeshRenderItems.keys()) {
|
||||||
auto renderPayload = std::make_shared<ModelMeshPartPayload::Payload>(renderItem);
|
pendingChanges.updateItem<ModelMeshPartPayload>(item, [](ModelMeshPartPayload& data) {
|
||||||
renderPayload->addStatusGetters(statusGetters);
|
data.notifyLocationChanged();
|
||||||
pendingChanges.resetItem(item, renderPayload);
|
});
|
||||||
pendingChanges.updateItem<ModelMeshPartPayload>(item, [](ModelMeshPartPayload& data) {
|
}
|
||||||
data.notifyLocationChanged();
|
} else {
|
||||||
});
|
for (auto renderItem : _modelMeshRenderItemsSet) {
|
||||||
_modelMeshRenderItems.insert(item, renderPayload);
|
auto item = scene->allocateID();
|
||||||
somethingAdded = true;
|
auto renderPayload = std::make_shared<ModelMeshPartPayload::Payload>(renderItem);
|
||||||
|
if (statusGetters.size()) {
|
||||||
|
renderPayload->addStatusGetters(statusGetters);
|
||||||
|
}
|
||||||
|
pendingChanges.resetItem(item, renderPayload);
|
||||||
|
pendingChanges.updateItem<ModelMeshPartPayload>(item, [](ModelMeshPartPayload& data) {
|
||||||
|
data.notifyLocationChanged();
|
||||||
|
});
|
||||||
|
_modelMeshRenderItems.insert(item, renderPayload);
|
||||||
|
somethingAdded = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (auto renderItem, _collisionRenderItemsSet) {
|
if (_collisionRenderItems.size()) {
|
||||||
auto item = scene->allocateID();
|
for (auto item : _collisionRenderItems.keys()) {
|
||||||
auto renderPayload = std::make_shared<MeshPartPayload::Payload>(renderItem);
|
pendingChanges.updateItem<MeshPartPayload>(item, [](MeshPartPayload& data) {
|
||||||
renderPayload->addStatusGetters(statusGetters);
|
data.notifyLocationChanged();
|
||||||
pendingChanges.resetItem(item, renderPayload);
|
});
|
||||||
pendingChanges.updateItem<MeshPartPayload>(item, [](MeshPartPayload& data) {
|
}
|
||||||
data.notifyLocationChanged();
|
} else {
|
||||||
});
|
for (auto renderItem : _collisionRenderItemsSet) {
|
||||||
_collisionRenderItems.insert(item, renderPayload);
|
auto item = scene->allocateID();
|
||||||
somethingAdded = true;
|
auto renderPayload = std::make_shared<MeshPartPayload::Payload>(renderItem);
|
||||||
|
if (statusGetters.size()) {
|
||||||
|
renderPayload->addStatusGetters(statusGetters);
|
||||||
|
}
|
||||||
|
pendingChanges.resetItem(item, renderPayload);
|
||||||
|
pendingChanges.updateItem<MeshPartPayload>(item, [](MeshPartPayload& data) {
|
||||||
|
data.notifyLocationChanged();
|
||||||
|
});
|
||||||
|
_collisionRenderItems.insert(item, renderPayload);
|
||||||
|
somethingAdded = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_readyWhenAdded = readyToAddToScene();
|
_readyWhenAdded = readyToAddToScene();
|
||||||
|
@ -791,6 +769,13 @@ int Model::getLastFreeJointIndex(int jointIndex) const {
|
||||||
return (isActive() && jointIndex != -1) ? getFBXGeometry().joints.at(jointIndex).freeLineage.last() : -1;
|
return (isActive() && jointIndex != -1) ? getFBXGeometry().joints.at(jointIndex).freeLineage.last() : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Model::setTextures(const QVariantMap& textures) {
|
||||||
|
if (isLoaded()) {
|
||||||
|
_needsUpdateTextures = true;
|
||||||
|
_geometry->getGeometry()->setTextures(textures);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Model::setURL(const QUrl& url) {
|
void Model::setURL(const QUrl& url) {
|
||||||
// don't recreate the geometry if it's the same URL
|
// don't recreate the geometry if it's the same URL
|
||||||
if (_url == url && _geometry && _geometry->getURL() == url) {
|
if (_url == url && _geometry && _geometry->getURL() == url) {
|
||||||
|
@ -807,8 +792,7 @@ void Model::setURL(const QUrl& url) {
|
||||||
}
|
}
|
||||||
|
|
||||||
_needsReload = true;
|
_needsReload = true;
|
||||||
_needsUpdateTransparentTextures = true;
|
_needsUpdateTextures = true;
|
||||||
_hasTransparentTextures = false;
|
|
||||||
_meshGroupsKnown = false;
|
_meshGroupsKnown = false;
|
||||||
invalidCalculatedMeshBoxes();
|
invalidCalculatedMeshBoxes();
|
||||||
deleteGeometry();
|
deleteGeometry();
|
||||||
|
|
|
@ -87,7 +87,10 @@ public:
|
||||||
bool initWhenReady(render::ScenePointer scene);
|
bool initWhenReady(render::ScenePointer scene);
|
||||||
bool addToScene(std::shared_ptr<render::Scene> scene,
|
bool addToScene(std::shared_ptr<render::Scene> scene,
|
||||||
render::PendingChanges& pendingChanges,
|
render::PendingChanges& pendingChanges,
|
||||||
bool showCollisionHull = false);
|
bool showCollisionHull = false) {
|
||||||
|
auto getters = render::Item::Status::Getters(0);
|
||||||
|
return addToScene(scene, pendingChanges, getters, showCollisionHull);
|
||||||
|
}
|
||||||
bool addToScene(std::shared_ptr<render::Scene> scene,
|
bool addToScene(std::shared_ptr<render::Scene> scene,
|
||||||
render::PendingChanges& pendingChanges,
|
render::PendingChanges& pendingChanges,
|
||||||
render::Item::Status::Getters& statusGetters,
|
render::Item::Status::Getters& statusGetters,
|
||||||
|
@ -129,6 +132,9 @@ public:
|
||||||
/// Returns a reference to the shared collision geometry.
|
/// Returns a reference to the shared collision geometry.
|
||||||
const NetworkGeometry::Pointer& getCollisionGeometry() const { return _collisionGeometry; }
|
const NetworkGeometry::Pointer& getCollisionGeometry() const { return _collisionGeometry; }
|
||||||
|
|
||||||
|
const QVariantMap getTextures() const { assert(isLoaded()); return _geometry->getGeometry()->getTextures(); }
|
||||||
|
void setTextures(const QVariantMap& textures);
|
||||||
|
|
||||||
/// Provided as a convenience, will crash if !isLoaded()
|
/// Provided as a convenience, will crash if !isLoaded()
|
||||||
// And so that getGeometry() isn't chained everywhere
|
// And so that getGeometry() isn't chained everywhere
|
||||||
const FBXGeometry& getFBXGeometry() const { assert(isLoaded()); return getGeometry()->getGeometry()->getGeometry(); }
|
const FBXGeometry& getFBXGeometry() const { assert(isLoaded()); return getGeometry()->getGeometry()->getGeometry(); }
|
||||||
|
@ -385,9 +391,8 @@ protected:
|
||||||
bool _readyWhenAdded { false };
|
bool _readyWhenAdded { false };
|
||||||
bool _needsReload { true };
|
bool _needsReload { true };
|
||||||
bool _needsUpdateClusterMatrices { true };
|
bool _needsUpdateClusterMatrices { true };
|
||||||
mutable bool _needsUpdateTransparentTextures { true };
|
|
||||||
mutable bool _hasTransparentTextures { false };
|
|
||||||
bool _showCollisionHull { false };
|
bool _showCollisionHull { false };
|
||||||
|
mutable bool _needsUpdateTextures { true };
|
||||||
|
|
||||||
friend class ModelMeshPartPayload;
|
friend class ModelMeshPartPayload;
|
||||||
RigPointer _rig;
|
RigPointer _rig;
|
||||||
|
|
Loading…
Reference in a new issue