diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index 0ea3d492a6..c45f91d6ff 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -42,10 +42,23 @@ ShapeEntityRenderer::ShapeEntityRenderer(const EntityItemPointer& entity) : Pare // TODO: move into Procedural.cpp PrepareStencil::testMaskDrawShape(*_procedural._opaqueState); PrepareStencil::testMask(*_procedural._transparentState); + + addMaterial(graphics::MaterialLayer(_material, 0), "0"); } bool ShapeEntityRenderer::needsRenderUpdate() const { - if (_procedural.isEnabled() && _procedural.isFading()) { + if (resultWithReadLock<bool>([&] { + if (_procedural.isEnabled() && _procedural.isFading()) { + return true; + } + + auto mat = _materials.find("0"); + if (mat != _materials.end() && mat->second.needsUpdate()) { + return true; + } + + return false; + })) { return true; } @@ -56,7 +69,11 @@ bool ShapeEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoin if (_lastUserData != entity->getUserData()) { return true; } - if (_material != entity->getMaterial()) { + + if (_color != entity->getColor()) { + return true; + } + if (_alpha != entity->getAlpha()) { return true; } @@ -79,10 +96,6 @@ void ShapeEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce _procedural.setProceduralData(ProceduralData::parse(_lastUserData)); } - removeMaterial(_material, "0"); - _material = entity->getMaterial(); - addMaterial(graphics::MaterialLayer(_material, 0), "0"); - _shape = entity->getShape(); }); @@ -111,6 +124,15 @@ void ShapeEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPoint _procedural.setIsFading(isFading); } }); + + _color = entity->getColor(); + _alpha = entity->getAlpha(); + _material->setAlbedo(toGlm(_color)); + _material->setOpacity(_alpha); + auto materials = _materials.find("0"); + if (materials != _materials.end()) { + materials->second.setNeedsUpdate(true); + } } bool ShapeEntityRenderer::isTransparent() const { @@ -120,11 +142,8 @@ bool ShapeEntityRenderer::isTransparent() const { auto mat = _materials.find("0"); if (mat != _materials.end()) { - if (mat->second.top().material) { - auto matKey = mat->second.top().material->getKey(); - if (matKey.isTranslucent()) { - return true; - } + if (mat->second.getMaterialKey().isTranslucent()) { + return true; } } @@ -146,7 +165,7 @@ ItemKey ShapeEntityRenderer::getKey() { return builder.build(); } -bool ShapeEntityRenderer::useMaterialPipeline() const { +bool ShapeEntityRenderer::useMaterialPipeline(const graphics::MultiMaterial& materials) const { bool proceduralReady = resultWithReadLock<bool>([&] { return _procedural.isReady(); }); @@ -154,12 +173,7 @@ bool ShapeEntityRenderer::useMaterialPipeline() const { return false; } - graphics::MaterialKey drawMaterialKey; - auto mat = _materials.find("0"); - if (mat != _materials.end() && mat->second.top().material) { - drawMaterialKey = mat->second.top().material->getKey(); - } - + graphics::MaterialKey drawMaterialKey = materials.getMaterialKey(); if (drawMaterialKey.isEmissive() || drawMaterialKey.isUnlit() || drawMaterialKey.isMetallic() || drawMaterialKey.isScattering()) { return true; } @@ -174,11 +188,13 @@ bool ShapeEntityRenderer::useMaterialPipeline() const { } ShapeKey ShapeEntityRenderer::getShapeKey() { - if (useMaterialPipeline()) { - graphics::MaterialKey drawMaterialKey; - if (_materials["0"].top().material) { - drawMaterialKey = _materials["0"].top().material->getKey(); - } + auto mat = _materials.find("0"); + if (mat != _materials.end() && mat->second.needsUpdate()) { + RenderPipelines::updateMultiMaterial(mat->second); + } + + if (mat != _materials.end() && useMaterialPipeline(mat->second)) { + graphics::MaterialKey drawMaterialKey = mat->second.getMaterialKey(); bool isTranslucent = drawMaterialKey.isTranslucent(); bool hasTangents = drawMaterialKey.isNormalMap(); @@ -232,16 +248,13 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) { geometryShape = geometryCache->getShapeForEntityShape(_shape); batch.setModelTransform(_renderTransform); // use a transform with scale, rotation, registration point and translation materials = _materials["0"]; - auto topMat = materials.top().material; - if (topMat) { - // FIXME: fallthrough to get proper albedo and opacity? - outColor = glm::vec4(topMat->getAlbedo(), topMat->getOpacity()); - if (_procedural.isReady()) { - outColor = _procedural.getColor(outColor); - outColor.a *= _procedural.isFading() ? Interpolate::calculateFadeRatio(_procedural.getFadeStartTime()) : 1.0f; - _procedural.prepare(batch, _position, _dimensions, _orientation, ProceduralProgramKey(outColor.a < 1.0f)); - proceduralRender = true; - } + auto& schema = materials.getSchemaBuffer().get<graphics::MultiMaterial::Schema>(); + outColor = glm::vec4(schema._albedo, schema._opacity); + if (_procedural.isReady()) { + outColor = _procedural.getColor(outColor); + outColor.a *= _procedural.isFading() ? Interpolate::calculateFadeRatio(_procedural.getFadeStartTime()) : 1.0f; + _procedural.prepare(batch, _position, _dimensions, _orientation, ProceduralProgramKey(outColor.a < 1.0f)); + proceduralRender = true; } }); @@ -251,7 +264,7 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) { } else { geometryCache->renderShape(batch, geometryShape, outColor); } - } else if (!useMaterialPipeline()) { + } else if (!useMaterialPipeline(materials)) { // FIXME, support instanced multi-shape rendering using multidraw indirect outColor.a *= _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f; auto pipeline = outColor.a < 1.0f ? geometryCache->getTransparentShapePipeline() : geometryCache->getOpaqueShapePipeline(); @@ -281,8 +294,9 @@ scriptable::ScriptableModelBase ShapeEntityRenderer::getScriptableModel() { { std::lock_guard<std::mutex> lock(_materialsLock); result.appendMaterials(_materials); - if (_materials["0"].top().material) { - vertexColor = _materials["0"].top().material->getAlbedo(); + auto& materials = _materials.find("0"); + if (materials != _materials.end()) { + vertexColor = materials->second.getSchemaBuffer().get<graphics::MultiMaterial::Schema>()._albedo; } } if (auto mesh = geometryCache->meshFromShape(geometryShape, vertexColor)) { diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.h b/libraries/entities-renderer/src/RenderableShapeEntityItem.h index 7700aa6ef0..09a1dd6742 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.h +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.h @@ -36,12 +36,14 @@ private: virtual void doRender(RenderArgs* args) override; virtual bool isTransparent() const override; - bool useMaterialPipeline() const; + bool useMaterialPipeline(const graphics::MultiMaterial& materials) const; Procedural _procedural; QString _lastUserData; entity::Shape _shape { entity::Sphere }; - std::shared_ptr<graphics::Material> _material; + std::shared_ptr<graphics::Material> _material { std::make_shared<graphics::Material>() }; + glm::u8vec3 _color; + float _alpha; glm::vec3 _position; glm::vec3 _dimensions; glm::quat _orientation; diff --git a/libraries/entities/src/ShapeEntityItem.cpp b/libraries/entities/src/ShapeEntityItem.cpp index 08af12a289..0aeb180cd2 100644 --- a/libraries/entities/src/ShapeEntityItem.cpp +++ b/libraries/entities/src/ShapeEntityItem.cpp @@ -112,7 +112,6 @@ EntityItemPointer ShapeEntityItem::sphereFactory(const EntityItemID& entityID, c ShapeEntityItem::ShapeEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) { _type = EntityTypes::Shape; _volumeMultiplier *= PI / 6.0f; - _material = std::make_shared<graphics::Material>(); } EntityItemProperties ShapeEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const { @@ -215,7 +214,6 @@ void ShapeEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit void ShapeEntityItem::setColor(const glm::u8vec3& value) { withWriteLock([&] { _color = value; - _material->setAlbedo(toGlm(_color)); }); } @@ -228,7 +226,6 @@ glm::u8vec3 ShapeEntityItem::getColor() const { void ShapeEntityItem::setAlpha(float alpha) { withWriteLock([&] { _alpha = alpha; - _material->setOpacity(alpha); }); } diff --git a/libraries/entities/src/ShapeEntityItem.h b/libraries/entities/src/ShapeEntityItem.h index c89a8934f8..601ff07237 100644 --- a/libraries/entities/src/ShapeEntityItem.h +++ b/libraries/entities/src/ShapeEntityItem.h @@ -99,8 +99,6 @@ public: virtual void computeShapeInfo(ShapeInfo& info) override; virtual ShapeType getShapeType() const override; - std::shared_ptr<graphics::Material> getMaterial() { return _material; } - protected: float _alpha { 1.0f }; @@ -111,8 +109,6 @@ protected: //! prior functionality where new or unsupported shapes are treated as //! ellipsoids. ShapeType _collisionShapeType{ ShapeType::SHAPE_TYPE_ELLIPSOID }; - - std::shared_ptr<graphics::Material> _material; }; #endif // hifi_ShapeEntityItem_h diff --git a/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.cpp b/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.cpp index f32c4f2e01..51d805a0a5 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.cpp +++ b/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.cpp @@ -380,22 +380,28 @@ namespace scriptable { obj.setProperty("scatteringMap", material.propertyFallthroughs.at(graphics::MaterialKey::SCATTERING_MAP_BIT) ? FALLTHROUGH : material.scatteringMap); // Only set one of each of these - if (!material.metallicMap.isEmpty()) { - obj.setProperty("metallicMap", material.propertyFallthroughs.at(graphics::MaterialKey::METALLIC_MAP_BIT) ? FALLTHROUGH : material.metallicMap); - } else { - obj.setProperty("specularMap", material.propertyFallthroughs.at(graphics::MaterialKey::METALLIC_MAP_BIT) ? FALLTHROUGH : material.specularMap); + if (material.propertyFallthroughs.at(graphics::MaterialKey::METALLIC_MAP_BIT)) { + obj.setProperty("metallicMap", FALLTHROUGH); + } else if (!material.metallicMap.isEmpty()) { + obj.setProperty("metallicMap", material.metallicMap); + } else if (!material.specularMap.isEmpty()) { + obj.setProperty("specularMap", material.specularMap); } - if (!material.roughnessMap.isEmpty()) { - obj.setProperty("roughnessMap", material.propertyFallthroughs.at(graphics::MaterialKey::ROUGHNESS_MAP_BIT) ? FALLTHROUGH : material.roughnessMap); - } else { - obj.setProperty("glossMap", material.propertyFallthroughs.at(graphics::MaterialKey::ROUGHNESS_MAP_BIT) ? FALLTHROUGH : material.glossMap); + if (material.propertyFallthroughs.at(graphics::MaterialKey::ROUGHNESS_MAP_BIT)) { + obj.setProperty("roughnessMap", FALLTHROUGH); + } else if (!material.roughnessMap.isEmpty()) { + obj.setProperty("roughnessMap", material.roughnessMap); + } else if (!material.glossMap.isEmpty()) { + obj.setProperty("glossMap", material.glossMap); } - if (!material.normalMap.isEmpty()) { - obj.setProperty("normalMap", material.propertyFallthroughs.at(graphics::MaterialKey::NORMAL_MAP_BIT) ? FALLTHROUGH : material.normalMap); - } else { - obj.setProperty("bumpMap", material.propertyFallthroughs.at(graphics::MaterialKey::NORMAL_MAP_BIT) ? FALLTHROUGH : material.bumpMap); + if (material.propertyFallthroughs.at(graphics::MaterialKey::NORMAL_MAP_BIT)) { + obj.setProperty("normalMap", FALLTHROUGH); + } else if (!material.normalMap.isEmpty()) { + obj.setProperty("normalMap", material.normalMap); + } else if (!material.bumpMap.isEmpty()) { + obj.setProperty("bumpMap", material.bumpMap); } obj.setProperty("defaultFallthrough", material.defaultFallthrough); diff --git a/libraries/graphics/src/graphics/Material.cpp b/libraries/graphics/src/graphics/Material.cpp index b6b759ec86..18f9c29a13 100755 --- a/libraries/graphics/src/graphics/Material.cpp +++ b/libraries/graphics/src/graphics/Material.cpp @@ -119,7 +119,6 @@ void Material::setTextureMap(MapChannel channel, const TextureMapPointer& textur _key.setMapChannel(channel, false); _textureMaps.erase(channel); } - _hasCalculatedTextureInfo = false; if (channel == MaterialKey::ALBEDO_MAP) { resetOpacityMap(); @@ -177,39 +176,6 @@ const TextureMapPointer Material::getTextureMap(MapChannel channel) const { } } -bool Material::calculateMaterialInfo() const { - if (!_hasCalculatedTextureInfo) { - QMutexLocker locker(&_textureMapsMutex); - - bool allTextures = true; // assume we got this... - _textureSize = 0; - _textureCount = 0; - - for (auto const &textureMapItem : _textureMaps) { - auto textureMap = textureMapItem.second; - if (textureMap) { - auto textureSoure = textureMap->getTextureSource(); - if (textureSoure) { - auto texture = textureSoure->getGPUTexture(); - if (texture) { - auto size = texture->getSize(); - _textureSize += size; - _textureCount++; - } else { - allTextures = false; - } - } else { - allTextures = false; - } - } else { - allTextures = false; - } - } - _hasCalculatedTextureInfo = allTextures; - } - return _hasCalculatedTextureInfo; -} - void Material::setTextureTransforms(const Transform& transform, MaterialMappingMode mode, bool repeat) { for (auto &textureMapItem : _textureMaps) { if (textureMapItem.second) { @@ -227,4 +193,24 @@ void Material::setTextureTransforms(const Transform& transform, MaterialMappingM MultiMaterial::MultiMaterial() { Schema schema; _schemaBuffer = gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(Schema), (const gpu::Byte*) &schema, sizeof(Schema))); +} + +void MultiMaterial::calculateMaterialInfo() const { + if (!_hasCalculatedTextureInfo) { + bool allTextures = true; // assume we got this... + _textureSize = 0; + _textureCount = 0; + + auto& textures = _textureTable->getTextures(); + for (auto const &texture : textures) { + if (texture && texture->isDefined()) { + auto size = texture->getSize(); + _textureSize += size; + _textureCount++; + } else { + allTextures = false; + } + } + _hasCalculatedTextureInfo = allTextures; + } } \ No newline at end of file diff --git a/libraries/graphics/src/graphics/Material.h b/libraries/graphics/src/graphics/Material.h index 91453bb259..3287bf7825 100755 --- a/libraries/graphics/src/graphics/Material.h +++ b/libraries/graphics/src/graphics/Material.h @@ -315,10 +315,6 @@ public: // conversion from legacy material properties to PBR equivalent static float shininessToRoughness(float shininess) { return 1.0f - shininess / 100.0f; } - int getTextureCount() const { calculateMaterialInfo(); return _textureCount; } - size_t getTextureSize() const { calculateMaterialInfo(); return _textureSize; } - bool hasTextureInfo() const { return _hasCalculatedTextureInfo; } - void setTextureTransforms(const Transform& transform, MaterialMappingMode mode, bool repeat); const std::string& getName() const { return _name; } @@ -355,14 +351,10 @@ private: std::unordered_map<MaterialKey::FlagBit, bool> _propertyFallthroughs; mutable QMutex _textureMapsMutex { QMutex::Recursive }; - mutable size_t _textureSize { 0 }; - mutable int _textureCount { 0 }; - mutable bool _hasCalculatedTextureInfo { false }; - bool calculateMaterialInfo() const; std::string _model { "hifi_pbr" }; }; -typedef std::shared_ptr< Material > MaterialPointer; +typedef std::shared_ptr<Material> MaterialPointer; class MaterialLayer { public: @@ -378,11 +370,18 @@ public: return left.priority < right.priority; } }; +typedef std::priority_queue<MaterialLayer, std::vector<MaterialLayer>, MaterialLayerCompare> MaterialLayerQueue; -class MultiMaterial : public std::priority_queue<MaterialLayer, std::vector<MaterialLayer>, MaterialLayerCompare> { +class MultiMaterial : public MaterialLayerQueue { public: MultiMaterial(); + void push(const MaterialLayer& value) { + MaterialLayerQueue::push(value); + _hasCalculatedTextureInfo = false; + _needsUpdate = true; + } + bool remove(const MaterialPointer& value) { auto it = c.begin(); while (it != c.end()) { @@ -394,6 +393,8 @@ public: if (it != c.end()) { c.erase(it); std::make_heap(c.begin(), c.end(), comp); + _hasCalculatedTextureInfo = false; + _needsUpdate = true; return true; } else { return false; @@ -437,11 +438,25 @@ public: }; gpu::BufferView& getSchemaBuffer() { return _schemaBuffer; } + graphics::MaterialKey getMaterialKey() const { return graphics::MaterialKey(_schemaBuffer.get<graphics::MultiMaterial::Schema>()._key); } const gpu::TextureTablePointer& getTextureTable() const { return _textureTable; } + bool needsUpdate() const { return _needsUpdate; } + void setNeedsUpdate(bool needsUpdate) { _needsUpdate = needsUpdate; } + + int getTextureCount() const { calculateMaterialInfo(); return _textureCount; } + size_t getTextureSize() const { calculateMaterialInfo(); return _textureSize; } + bool hasTextureInfo() const { return _hasCalculatedTextureInfo; } + private: gpu::BufferView _schemaBuffer; gpu::TextureTablePointer _textureTable { std::make_shared<gpu::TextureTable>() }; + bool _needsUpdate { false }; + + mutable size_t _textureSize { 0 }; + mutable int _textureCount { 0 }; + mutable bool _hasCalculatedTextureInfo { false }; + void calculateMaterialInfo() const; }; }; diff --git a/libraries/model-networking/src/model-networking/MaterialCache.cpp b/libraries/model-networking/src/model-networking/MaterialCache.cpp index ecaaf62fa7..46d0cc291a 100644 --- a/libraries/model-networking/src/model-networking/MaterialCache.cpp +++ b/libraries/model-networking/src/model-networking/MaterialCache.cpp @@ -160,13 +160,16 @@ NetworkMaterialResource::ParsedMaterials NetworkMaterialResource::parseJSONMater std::pair<std::string, std::shared_ptr<NetworkMaterial>> NetworkMaterialResource::parseJSONMaterial(const QJsonObject& materialJSON, const QUrl& baseUrl) { std::string name = ""; std::shared_ptr<NetworkMaterial> material = std::make_shared<NetworkMaterial>(); - std::string modelString = "hifi_pbr"; - auto modelJSON = materialJSON.value("model"); - if (modelJSON.isString()) { - modelString = modelJSON.toString().toStdString(); + + const std::string HIFI_PBR = "hifi_pbr"; + std::string modelString = HIFI_PBR; + auto modelJSONIter = materialJSON.find("model"); + if (modelJSONIter != materialJSON.end() && modelJSONIter.value().isString()) { + modelString = modelJSONIter.value().toString().toStdString(); material->setModel(modelString); } - if (modelString == "hifi_pbr") { + + if (modelString == HIFI_PBR) { const QString FALLTHROUGH("fallthrough"); for (auto& key : materialJSON.keys()) { if (key == "name") { diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 489fc5c331..b31f5d05f5 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -83,11 +83,13 @@ void MeshPartPayload::updateKey(const render::ItemKey& key) { ItemKey::Builder builder(key); builder.withTypeShape(); - if (topMaterialExists()) { - auto matKey = _drawMaterials.top().material->getKey(); - if (matKey.isTranslucent()) { - builder.withTransparent(); - } + if (_drawMaterials.needsUpdate()) { + RenderPipelines::updateMultiMaterial(_drawMaterials); + } + + auto matKey = _drawMaterials.getMaterialKey(); + if (matKey.isTranslucent()) { + builder.withTransparent(); } _itemKey = builder.build(); @@ -102,10 +104,7 @@ Item::Bound MeshPartPayload::getBound() const { } ShapeKey MeshPartPayload::getShapeKey() const { - graphics::MaterialKey drawMaterialKey; - if (topMaterialExists()) { - drawMaterialKey = _drawMaterials.top().material->getKey(); - } + graphics::MaterialKey drawMaterialKey = _drawMaterials.getMaterialKey(); ShapeKey::Builder builder; builder.withMaterial(); @@ -330,11 +329,13 @@ void ModelMeshPartPayload::updateKey(const render::ItemKey& key) { builder.withDeformed(); } - if (topMaterialExists()) { - auto matKey = _drawMaterials.top().material->getKey(); - if (matKey.isTranslucent()) { - builder.withTransparent(); - } + if (_drawMaterials.needsUpdate()) { + RenderPipelines::updateMultiMaterial(_drawMaterials); + } + + auto matKey = _drawMaterials.getMaterialKey(); + if (matKey.isTranslucent()) { + builder.withTransparent(); } _itemKey = builder.build(); @@ -346,10 +347,7 @@ void ModelMeshPartPayload::setShapeKey(bool invalidateShapeKey, bool isWireframe return; } - graphics::MaterialKey drawMaterialKey; - if (topMaterialExists()) { - drawMaterialKey = _drawMaterials.top().material->getKey(); - } + graphics::MaterialKey drawMaterialKey = _drawMaterials.getMaterialKey(); bool isTranslucent = drawMaterialKey.isTranslucent(); bool hasTangents = drawMaterialKey.isNormalMap() && _hasTangents; diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index 03145c981b..def8de7c77 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -66,17 +66,15 @@ public: graphics::Mesh::Part _drawPart; size_t getVerticesCount() const { return _drawMesh ? _drawMesh->getNumVertices() : 0; } - size_t getMaterialTextureSize() { return topMaterialExists() ? _drawMaterials.top().material->getTextureSize() : 0; } - int getMaterialTextureCount() { return topMaterialExists() ? _drawMaterials.top().material->getTextureCount() : 0; } - bool hasTextureInfo() const { return topMaterialExists() ? _drawMaterials.top().material->hasTextureInfo() : false; } + size_t getMaterialTextureSize() { return _drawMaterials.getTextureSize(); } + int getMaterialTextureCount() { return _drawMaterials.getTextureCount(); } + bool hasTextureInfo() const { return _drawMaterials.hasTextureInfo(); } void addMaterial(graphics::MaterialLayer material); void removeMaterial(graphics::MaterialPointer material); protected: render::ItemKey _itemKey{ render::ItemKey::Builder::opaqueShape().build() }; - - bool topMaterialExists() const { return !_drawMaterials.empty() && _drawMaterials.top().material; } }; namespace render { diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index 1af47b4321..0d8f6bdd40 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -376,23 +376,25 @@ void initZPassPipelines(ShapePlumber& shapePlumber, gpu::StatePointer state, con void RenderPipelines::bindMaterial(graphics::MaterialPointer& material, gpu::Batch& batch, bool enableTextures) { graphics::MultiMaterial multiMaterial; multiMaterial.push(graphics::MaterialLayer(material, 0)); + updateMultiMaterial(multiMaterial); bindMaterials(multiMaterial, batch, enableTextures); } -// FIXME find a better way to setup the default textures -void RenderPipelines::bindMaterials(graphics::MultiMaterial& multiMaterial, gpu::Batch& batch, bool enableTextures) { +void RenderPipelines::updateMultiMaterial(graphics::MultiMaterial& multiMaterial) { + auto& schemaBuffer = multiMaterial.getSchemaBuffer(); + if (multiMaterial.size() == 0) { + schemaBuffer.edit<graphics::MultiMaterial::Schema>() = graphics::MultiMaterial::Schema(); return; } auto textureCache = DependencyManager::get<TextureCache>(); auto& drawMaterialTextures = multiMaterial.getTextureTable(); - auto& schemaBuffer = multiMaterial.getSchemaBuffer(); // The total list of things we need to look for static std::set<graphics::MaterialKey::FlagBit> allFlagBits; static std::once_flag once; - std::call_once(once, [] { + std::call_once(once, [textureCache] { for (int i = 0; i < graphics::MaterialKey::NUM_FLAGS; i++) { auto flagBit = graphics::MaterialKey::FlagBit(i); // The opacity mask/map are derived from the albedo map @@ -472,16 +474,12 @@ void RenderPipelines::bindMaterials(graphics::MultiMaterial& multiMaterial, gpu: break; case graphics::MaterialKey::ALBEDO_MAP_BIT: if (materialKey.isAlbedoMap()) { - if (!enableTextures) { - forceDefault = true; + auto itr = textureMaps.find(graphics::MaterialKey::ALBEDO_MAP); + if (itr != textureMaps.end() && itr->second->isDefined()) { + drawMaterialTextures->setTexture(gr::Texture::MaterialAlbedo, itr->second->getTextureView()); + wasSet = true; } else { - auto itr = textureMaps.find(graphics::MaterialKey::ALBEDO_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { - drawMaterialTextures->setTexture(gr::Texture::MaterialAlbedo, itr->second->getTextureView()); - wasSet = true; - } else { - forceDefault = true; - } + forceDefault = true; } schemaKey.setAlbedoMap(true); schemaKey.setOpacityMaskMap(materialKey.isOpacityMaskMap()); @@ -490,80 +488,60 @@ void RenderPipelines::bindMaterials(graphics::MultiMaterial& multiMaterial, gpu: break; case graphics::MaterialKey::METALLIC_MAP_BIT: if (materialKey.isMetallicMap()) { - if (!enableTextures) { - forceDefault = true; + auto itr = textureMaps.find(graphics::MaterialKey::METALLIC_MAP); + if (itr != textureMaps.end() && itr->second->isDefined()) { + drawMaterialTextures->setTexture(gr::Texture::MaterialMetallic, itr->second->getTextureView()); + wasSet = true; } else { - auto itr = textureMaps.find(graphics::MaterialKey::METALLIC_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { - drawMaterialTextures->setTexture(gr::Texture::MaterialMetallic, itr->second->getTextureView()); - wasSet = true; - } else { - forceDefault = true; - } + forceDefault = true; } schemaKey.setMetallicMap(true); } break; case graphics::MaterialKey::ROUGHNESS_MAP_BIT: if (materialKey.isRoughnessMap()) { - if (!enableTextures) { - forceDefault = true; + auto itr = textureMaps.find(graphics::MaterialKey::ROUGHNESS_MAP); + if (itr != textureMaps.end() && itr->second->isDefined()) { + drawMaterialTextures->setTexture(gr::Texture::MaterialRoughness, itr->second->getTextureView()); + wasSet = true; } else { - auto itr = textureMaps.find(graphics::MaterialKey::ROUGHNESS_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { - drawMaterialTextures->setTexture(gr::Texture::MaterialRoughness, itr->second->getTextureView()); - wasSet = true; - } else { - forceDefault = true; - } + forceDefault = true; } schemaKey.setRoughnessMap(true); } break; case graphics::MaterialKey::NORMAL_MAP_BIT: if (materialKey.isNormalMap()) { - if (!enableTextures) { - forceDefault = true; + auto itr = textureMaps.find(graphics::MaterialKey::NORMAL_MAP); + if (itr != textureMaps.end() && itr->second->isDefined()) { + drawMaterialTextures->setTexture(gr::Texture::MaterialNormal, itr->second->getTextureView()); + wasSet = true; } else { - auto itr = textureMaps.find(graphics::MaterialKey::NORMAL_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { - drawMaterialTextures->setTexture(gr::Texture::MaterialNormal, itr->second->getTextureView()); - wasSet = true; - } else { - forceDefault = true; - } + forceDefault = true; } schemaKey.setNormalMap(true); } break; case graphics::MaterialKey::OCCLUSION_MAP_BIT: if (materialKey.isOcclusionMap()) { - if (!enableTextures) { - forceDefault = true; + auto itr = textureMaps.find(graphics::MaterialKey::OCCLUSION_MAP); + if (itr != textureMaps.end() && itr->second->isDefined()) { + drawMaterialTextures->setTexture(gr::Texture::MaterialOcclusion, itr->second->getTextureView()); + wasSet = true; } else { - auto itr = textureMaps.find(graphics::MaterialKey::OCCLUSION_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { - drawMaterialTextures->setTexture(gr::Texture::MaterialOcclusion, itr->second->getTextureView()); - wasSet = true; - } else { - forceDefault = true; - } + forceDefault = true; } schemaKey.setOcclusionMap(true); } break; case graphics::MaterialKey::SCATTERING_MAP_BIT: if (materialKey.isScatteringMap()) { - if (!enableTextures) { - forceDefault = true; + auto itr = textureMaps.find(graphics::MaterialKey::SCATTERING_MAP); + if (itr != textureMaps.end() && itr->second->isDefined()) { + drawMaterialTextures->setTexture(gr::Texture::MaterialScattering, itr->second->getTextureView()); + wasSet = true; } else { - auto itr = textureMaps.find(graphics::MaterialKey::SCATTERING_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { - drawMaterialTextures->setTexture(gr::Texture::MaterialScattering, itr->second->getTextureView()); - wasSet = true; - } else { - forceDefault = true; - } + forceDefault = true; } schemaKey.setScattering(true); } @@ -571,16 +549,12 @@ void RenderPipelines::bindMaterials(graphics::MultiMaterial& multiMaterial, gpu: case graphics::MaterialKey::EMISSIVE_MAP_BIT: // Lightmap takes precendence over emissive map for legacy reasons if (materialKey.isEmissiveMap() && !materialKey.isLightmapMap()) { - if (!enableTextures) { - forceDefault = true; + auto itr = textureMaps.find(graphics::MaterialKey::EMISSIVE_MAP); + if (itr != textureMaps.end() && itr->second->isDefined()) { + drawMaterialTextures->setTexture(gr::Texture::MaterialEmissiveLightmap, itr->second->getTextureView()); + wasSet = true; } else { - auto itr = textureMaps.find(graphics::MaterialKey::EMISSIVE_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { - drawMaterialTextures->setTexture(gr::Texture::MaterialEmissiveLightmap, itr->second->getTextureView()); - wasSet = true; - } else { - forceDefault = true; - } + forceDefault = true; } schemaKey.setEmissiveMap(true); } else if (materialKey.isLightmapMap()) { @@ -590,16 +564,12 @@ void RenderPipelines::bindMaterials(graphics::MultiMaterial& multiMaterial, gpu: break; case graphics::MaterialKey::LIGHTMAP_MAP_BIT: if (materialKey.isLightmapMap()) { - if (!enableTextures) { - forceDefault = true; + auto itr = textureMaps.find(graphics::MaterialKey::LIGHTMAP_MAP); + if (itr != textureMaps.end() && itr->second->isDefined()) { + drawMaterialTextures->setTexture(gr::Texture::MaterialEmissiveLightmap, itr->second->getTextureView()); + wasSet = true; } else { - auto itr = textureMaps.find(graphics::MaterialKey::LIGHTMAP_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { - drawMaterialTextures->setTexture(gr::Texture::MaterialEmissiveLightmap, itr->second->getTextureView()); - wasSet = true; - } else { - forceDefault = true; - } + forceDefault = true; } schemaKey.setLightmapMap(true); } @@ -608,9 +578,10 @@ void RenderPipelines::bindMaterials(graphics::MultiMaterial& multiMaterial, gpu: break; } + bool fallthrough = defaultFallthrough || material->getPropertyFallthrough(flagBit); if (wasSet) { flagBitsToCheck.erase(it++); - } else if (forceDefault || !defaultFallthrough || !material->getPropertyFallthrough(flagBit)) { + } else if (forceDefault || !fallthrough) { flagBitsToSetDefault.insert(flagBit); flagBitsToCheck.erase(it++); } else { @@ -687,8 +658,44 @@ void RenderPipelines::bindMaterials(graphics::MultiMaterial& multiMaterial, gpu: } } + // FIXME: + // set transforms and params + schema._key = (uint32_t)schemaKey._flags.to_ulong(); schemaBuffer.edit<graphics::MultiMaterial::Schema>() = schema; - batch.setUniformBuffer(gr::Buffer::Material, schemaBuffer); - batch.setResourceTextureTable(drawMaterialTextures); + multiMaterial.setNeedsUpdate(false); +} + +void RenderPipelines::bindMaterials(graphics::MultiMaterial& multiMaterial, gpu::Batch& batch, bool enableTextures) { + if (multiMaterial.size() == 0) { + return; + } + + auto textureCache = DependencyManager::get<TextureCache>(); + + static gpu::TextureTablePointer defaultMaterialTextures = std::make_shared<gpu::TextureTable>(); + static std::once_flag once; + std::call_once(once, [textureCache] { + defaultMaterialTextures->setTexture(gr::Texture::MaterialAlbedo, textureCache->getWhiteTexture()); + defaultMaterialTextures->setTexture(gr::Texture::MaterialMetallic, textureCache->getBlackTexture()); + defaultMaterialTextures->setTexture(gr::Texture::MaterialRoughness, textureCache->getWhiteTexture()); + defaultMaterialTextures->setTexture(gr::Texture::MaterialNormal, textureCache->getBlueTexture()); + defaultMaterialTextures->setTexture(gr::Texture::MaterialOcclusion, textureCache->getWhiteTexture()); + defaultMaterialTextures->setTexture(gr::Texture::MaterialScattering, textureCache->getWhiteTexture()); + // MaterialEmissiveLightmap has to be set later + }); + + auto& schemaBuffer = multiMaterial.getSchemaBuffer(); + batch.setUniformBuffer(gr::Buffer::Material, schemaBuffer); + if (enableTextures) { + batch.setResourceTextureTable(multiMaterial.getTextureTable()); + } else { + auto key = multiMaterial.getMaterialKey(); + if (key.isLightmapMap()) { + defaultMaterialTextures->setTexture(gr::Texture::MaterialEmissiveLightmap, textureCache->getBlackTexture()); + } else if (key.isEmissiveMap()) { + defaultMaterialTextures->setTexture(gr::Texture::MaterialEmissiveLightmap, textureCache->getGrayTexture()); + } + batch.setResourceTextureTable(defaultMaterialTextures); + } } diff --git a/libraries/render-utils/src/RenderPipelines.h b/libraries/render-utils/src/RenderPipelines.h index 49abe719c8..0f3d1160ef 100644 --- a/libraries/render-utils/src/RenderPipelines.h +++ b/libraries/render-utils/src/RenderPipelines.h @@ -16,6 +16,7 @@ class RenderPipelines { public: static void bindMaterial(graphics::MaterialPointer& material, gpu::Batch& batch, bool enableTextures); + static void updateMultiMaterial(graphics::MultiMaterial& multiMaterial); static void bindMaterials(graphics::MultiMaterial& multiMaterial, gpu::Batch& batch, bool enableTextures); };