diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 21eed5f59f..3f7e0405d4 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -135,6 +135,8 @@ bool NetworkGeometry::isLoadedWithTextures() const { } if (!_isLoadedWithTextures) { + _hasTransparentTextures = true; + for (auto&& material : _materials) { if ((material->albedoTexture && !material->albedoTexture->isLoaded()) || (material->normalTexture && !material->normalTexture->isLoaded()) || @@ -145,7 +147,16 @@ bool NetworkGeometry::isLoadedWithTextures() const { (material->lightmapTexture && !material->lightmapTexture->isLoaded())) { return false; } + if (material->albedoTexture) { + // Reset the materialKey transparentTexture key only, as it is albedoTexture-dependent + const auto& usage = material->albedoTexture->getGPUTexture()->getUsage(); + bool isTransparentTexture = usage.isAlpha() && !usage.isAlphaMask(); + material->_material->setTransparentTexture(isTransparentTexture); + // FIXME: Materials with *some* transparent textures seem to give all *other* textures alphas of 0. + _hasTransparentTextures = isTransparentTexture && _hasTransparentTextures; + } } + _isLoadedWithTextures = true; } return true; diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index 60f185f691..7f01bdafaa 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -75,6 +75,10 @@ public: // true when the requested geometry and its textures are loaded. bool isLoadedWithTextures() const; + // true if the albedo texture has a non-masking alpha channel. + // This can only be known after isLoadedWithTextures(). + bool hasTransparentTextures() const { return _hasTransparentTextures; } + // WARNING: only valid when isLoaded returns true. const FBXGeometry& getFBXGeometry() const { return *_geometry; } const std::vector>& getMeshes() const { return _meshes; } @@ -151,6 +155,7 @@ protected: // cache for isLoadedWithTextures() mutable bool _isLoadedWithTextures = false; + mutable bool _hasTransparentTextures = false; }; /// Reads geometry in a worker thread. diff --git a/libraries/model/src/model/Material.cpp b/libraries/model/src/model/Material.cpp index 10fa15edd5..306867c204 100755 --- a/libraries/model/src/model/Material.cpp +++ b/libraries/model/src/model/Material.cpp @@ -80,6 +80,10 @@ void Material::setMetallic(float metallic) { _schemaBuffer.edit()._metallic = metallic; } +void Material::setTransparentTexture(bool isTransparent) { + _key.setTransparentTexture(isTransparent); + _schemaBuffer.edit()._key = (uint32)_key._flags.to_ulong(); +} void Material::setTextureMap(MapChannel channel, const TextureMapPointer& textureMap) { if (textureMap) { @@ -92,6 +96,3 @@ void Material::setTextureMap(MapChannel channel, const TextureMapPointer& textur _textureMaps.erase(channel); } } - - - diff --git a/libraries/model/src/model/Material.h b/libraries/model/src/model/Material.h index b22f8a3f42..078fc6499a 100755 --- a/libraries/model/src/model/Material.h +++ b/libraries/model/src/model/Material.h @@ -32,6 +32,7 @@ public: METALLIC_VAL_BIT, GLOSSY_VAL_BIT, TRANSPARENT_VAL_BIT, + TRANSPARENT_TEX_VAL_BIT, EMISSIVE_MAP_BIT, ALBEDO_MAP_BIT, @@ -101,6 +102,9 @@ public: void setAlbedo(bool value) { _flags.set(ALBEDO_VAL_BIT, value); } bool isAlbedo() const { return _flags[ALBEDO_VAL_BIT]; } + void setTransparentTexture(bool value) { _flags.set(TRANSPARENT_TEX_VAL_BIT, value); } + bool isTransparentTexture() const { return _flags[TRANSPARENT_TEX_VAL_BIT]; } + void setAlbedoMap(bool value) { _flags.set(ALBEDO_MAP_BIT, value); } bool isAlbedoMap() const { return _flags[ALBEDO_MAP_BIT]; } @@ -164,6 +168,9 @@ public: Builder& withoutAlbedo() { _value.reset(MaterialKey::ALBEDO_VAL_BIT); _mask.set(MaterialKey::ALBEDO_VAL_BIT); return (*this); } Builder& withAlbedo() { _value.set(MaterialKey::ALBEDO_VAL_BIT); _mask.set(MaterialKey::ALBEDO_VAL_BIT); return (*this); } + Builder& withoutTransparentTexture() { _value.reset(MaterialKey::TRANSPARENT_TEX_VAL_BIT); _mask.set(MaterialKey::TRANSPARENT_TEX_VAL_BIT); return (*this); } + Builder& withTransparentTexture() { _value.set(MaterialKey::TRANSPARENT_TEX_VAL_BIT); _mask.set(MaterialKey::TRANSPARENT_TEX_VAL_BIT); return (*this); } + Builder& withoutAlbedoMap() { _value.reset(MaterialKey::ALBEDO_MAP_BIT); _mask.set(MaterialKey::ALBEDO_MAP_BIT); return (*this); } Builder& withAlbedoMap() { _value.set(MaterialKey::ALBEDO_MAP_BIT); _mask.set(MaterialKey::ALBEDO_MAP_BIT); return (*this); } @@ -248,6 +255,8 @@ public: void setRoughness(float roughness); float getRoughness() const { return _schemaBuffer.get()._roughness; } + void setTransparentTexture(bool isTransparent); + // Schema to access the attribute values of the material class Schema { public: @@ -260,8 +269,7 @@ public: glm::vec3 _fresnel{ 0.03f }; // Fresnel value for a default non metallic float _metallic{ 0.0f }; // Not Metallic - - glm::vec3 _spare0{ 0.0f }; + glm::vec3 _spare{ 0.0f }; uint32_t _key{ 0 }; // a copy of the materialKey diff --git a/libraries/model/src/model/Material.slh b/libraries/model/src/model/Material.slh index d75f3df5e0..da185ddf0b 100644 --- a/libraries/model/src/model/Material.slh +++ b/libraries/model/src/model/Material.slh @@ -15,7 +15,7 @@ struct Material { vec4 _emissiveOpacity; vec4 _albedoRoughness; vec4 _fresnelMetallic; - vec4 _spare; + vec4 _spareKey; }; uniform materialBuffer { @@ -37,25 +37,23 @@ float getMaterialMetallic(Material m) { return m._fresnelMetallic.a; } float getMaterialShininess(Material m) { return 1.0 - getMaterialRoughness(m); } -int getMaterialKey(Material m) { return floatBitsToInt(m._spare.w); } +int getMaterialKey(Material m) { return floatBitsToInt(m._spareKey.w); } const int EMISSIVE_VAL_BIT = 0x00000001; const int ALBEDO_VAL_BIT = 0x00000002; const int METALLIC_VAL_BIT = 0x00000004; const int GLOSSY_VAL_BIT = 0x00000008; const int TRANSPARENT_VAL_BIT = 0x00000010; +const int TRANSPARENT_TEX_VAL_BIT = 0x00000020; +const int EMISSIVE_MAP_BIT = 0x00000040; +const int ALBEDO_MAP_BIT = 0x00000080; +const int METALLIC_MAP_BIT = 0x00000100; +const int ROUGHNESS_MAP_BIT = 0x00000200; +const int TRANSPARENT_MAP_BIT = 0x00000400; +const int NORMAL_MAP_BIT = 0x00000800; +const int OCCLUSION_MAP_BIT = 0x00001000; -const int EMISSIVE_MAP_BIT = 0x00000020; -const int ALBEDO_MAP_BIT = 0x00000040; -const int METALLIC_MAP_BIT = 0x00000080; -const int ROUGHNESS_MAP_BIT = 0x00000100; -const int TRANSPARENT_MAP_BIT = 0x00000200; -const int NORMAL_MAP_BIT = 0x00000400; -const int OCCLUSION_MAP_BIT = 0x00000800; - -const int LIGHTMAP_MAP_BIT = 0x00001000; - - +const int LIGHTMAP_MAP_BIT = 0x00002000; <@endif@> diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 166b14333f..4ae5b4532a 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -81,7 +81,7 @@ ItemKey MeshPartPayload::getKey() const { if (_drawMaterial) { auto matKey = _drawMaterial->getKey(); - if (matKey.isTransparent() || matKey.isTransparentMap()) { + if (matKey.isTransparent() || matKey.isTransparentTexture() || matKey.isTransparentMap()) { builder.withTransparent(); } } @@ -100,7 +100,7 @@ ShapeKey MeshPartPayload::getShapeKey() const { } ShapeKey::Builder builder; - if (drawMaterialKey.isTransparent() || drawMaterialKey.isTransparentMap()) { + if (drawMaterialKey.isTransparent() || drawMaterialKey.isTransparentTexture() || drawMaterialKey.isTransparentMap()) { builder.withTranslucent(); } if (drawMaterialKey.isNormalMap()) { @@ -365,7 +365,7 @@ ItemKey ModelMeshPartPayload::getKey() const { if (_drawMaterial) { auto matKey = _drawMaterial->getKey(); - if (matKey.isTransparent() || matKey.isTransparentMap()) { + if (matKey.isTransparent() || matKey.isTransparentTexture() || matKey.isTransparentMap()) { builder.withTransparent(); } } @@ -412,7 +412,8 @@ ShapeKey ModelMeshPartPayload::getShapeKey() const { drawMaterialKey = _drawMaterial->getKey(); } - bool isTranslucent = drawMaterialKey.isTransparent() || drawMaterialKey.isTransparentMap(); + bool isTranslucent = + drawMaterialKey.isTransparent() || drawMaterialKey.isTransparentTexture() || drawMaterialKey.isTransparentMap(); bool hasTangents = drawMaterialKey.isNormalMap() && !mesh.tangents.isEmpty(); bool hasSpecular = drawMaterialKey.isMetallicMap(); bool hasLightmap = drawMaterialKey.isLightmapMap(); diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index ce6dfd6849..8b6cc41f35 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -74,6 +74,21 @@ Model::~Model() { AbstractViewStateInterface* Model::_viewState = NULL; +bool Model::needsFixupInScene() { + if (readyToAddToScene()) { + // Once textures are loaded, fixup if they are now transparent + if (!_needsReload && _needsUpdateTransparentTextures && _geometry->isLoadedWithTextures()) { + _needsUpdateTransparentTextures = false; + if (_hasTransparentTextures != _geometry->hasTransparentTextures()) { + return true; + } + } + if (!_readyWhenAdded) { + return true; + } + } + return false; +} void Model::setTranslation(const glm::vec3& translation) { _translation = translation; @@ -728,6 +743,8 @@ void Model::setURL(const QUrl& url) { } _needsReload = true; + _needsUpdateTransparentTextures = true; + _hasTransparentTextures = false; _meshGroupsKnown = false; invalidCalculatedMeshBoxes(); deleteGeometry(); diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 424eed1e66..e90d51813b 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -70,7 +70,7 @@ public: // new Scene/Engine rendering support void setVisibleInScene(bool newValue, std::shared_ptr scene); - bool needsFixupInScene() { return !_readyWhenAdded && readyToAddToScene(); } + bool needsFixupInScene(); bool readyToAddToScene(RenderArgs* renderArgs = nullptr) { return !_needsReload && isRenderable() && isActive() && isLoaded(); } @@ -365,10 +365,12 @@ protected: QSet> _renderItemsSet; QMap _renderItems; - bool _readyWhenAdded = false; - bool _needsReload = true; - bool _needsUpdateClusterMatrices = true; - bool _showCollisionHull = false; + bool _readyWhenAdded { false }; + bool _needsReload { true }; + bool _needsUpdateClusterMatrices { true }; + bool _needsUpdateTransparentTextures { true }; + bool _hasTransparentTextures { false }; + bool _showCollisionHull { false }; friend class ModelMeshPartPayload; RigPointer _rig;