diff --git a/libraries/entities/src/MaterialEntityItem.cpp b/libraries/entities/src/MaterialEntityItem.cpp index 1ebaa4f21a..fcca2d9803 100644 --- a/libraries/entities/src/MaterialEntityItem.cpp +++ b/libraries/entities/src/MaterialEntityItem.cpp @@ -346,8 +346,12 @@ void MaterialEntityItem::applyMaterial() { } void MaterialEntityItem::postAdd() { - removeMaterial(); - applyMaterial(); + // postAdd is called every time we are added to a new octree cell, but we only need to update the material the first time + if (!_hasBeenAddedToOctree) { + removeMaterial(); + applyMaterial(); + _hasBeenAddedToOctree = true; + } } void MaterialEntityItem::preDelete() { diff --git a/libraries/entities/src/MaterialEntityItem.h b/libraries/entities/src/MaterialEntityItem.h index dde9b60da9..d015bae681 100644 --- a/libraries/entities/src/MaterialEntityItem.h +++ b/libraries/entities/src/MaterialEntityItem.h @@ -19,7 +19,7 @@ class MaterialEntityItem : public EntityItem { using Pointer = std::shared_ptr; public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - + MaterialEntityItem(const EntityItemID& entityItemID); ALLOW_INSTANTIATION // This class can be instantiated @@ -44,9 +44,9 @@ public: virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, - ReadBitstreamToTreeParams& args, - EntityPropertyFlags& propertyFlags, bool overwriteLocalData, - bool& somethingChanged) override; + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, + bool& somethingChanged) override; void debugDump() const override; @@ -89,20 +89,39 @@ public: void postParentFixup() override; private: + // URL for this material. Currently, only JSON format is supported. Set to "userData" to use the user data to live edit a material. + // The following fields are supported in the JSON: + // strings: + // name (NOT YET USED) + // floats: + // opacity, roughness, metallic, scattering + // colors (arrays of 3 floats 0-1. Optional fourth value in array can be a boolean isSRGB): + // emissive, albedo, fresnel + // urls to textures: + // emissiveMap, albedoMap, metallicMap, roughnessMap, normalMap, occlusionMap, lightmapMap, scatteringMap QString _materialURL; + // Type of material. "uv" or "projected". NOT YET IMPLEMENTED, only UV is used MaterialMode _materialMode { UV }; + // Priority for this material when applying it to its parent. Only the highest priority material will be used. Materials with the same priority are (essentially) randomly sorted. + // Base materials that come with models always have priority 0. quint16 _priority { 0 }; + // An identifier for choosing a submesh or submeshes within a parent. If in the format "mat::", all submeshes with material name "" will be replaced. Otherwise, + // parentMaterialID will be parsed as an unsigned int (strings not starting with "mat::" will parse to 0), representing the mesh index to modify. QString _parentMaterialID { "0" }; + // Offset position in UV-space of top left of material, (0, 0) to (1, 1) glm::vec2 _materialPos { 0, 0 }; + // How much to scale this material within its parent's UV-space glm::vec2 _materialScale { 1, 1 }; + // How much to rotate this material within its parent's UV-space (degrees) float _materialRot { 0 }; - + NetworkMaterialResourcePointer _networkMaterial; QHash> _materials; std::vector _materialNames; QString _currentMaterialName; bool _retryApply { false }; + bool _hasBeenAddedToOctree { false }; }; diff --git a/libraries/graphics/src/graphics/Material.cpp b/libraries/graphics/src/graphics/Material.cpp index 7c66c8ab07..2bf58bc6fb 100755 --- a/libraries/graphics/src/graphics/Material.cpp +++ b/libraries/graphics/src/graphics/Material.cpp @@ -34,6 +34,7 @@ Material::Material() : } Material::Material(const Material& material) : + _name(material._name), _key(material._key), _textureMaps(material._textureMaps) { @@ -50,6 +51,8 @@ Material::Material(const Material& material) : Material& Material::operator= (const Material& material) { QMutexLocker locker(&_textureMapsMutex); + _name = material._name; + _key = (material._key); _textureMaps = (material._textureMaps); _hasCalculatedTextureInfo = false; diff --git a/libraries/graphics/src/graphics/Material.h b/libraries/graphics/src/graphics/Material.h index 5b3396dfc5..5abc090be3 100755 --- a/libraries/graphics/src/graphics/Material.h +++ b/libraries/graphics/src/graphics/Material.h @@ -359,6 +359,11 @@ public: void setTextureTransforms(const Transform& transform); + const QString& getName() { return _name; } + +protected: + QString _name { "" }; + private: mutable MaterialKey _key; mutable UniformBufferView _schemaBuffer; diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 739f401ee7..19ee05d1e2 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -619,6 +619,7 @@ NetworkMaterial::NetworkMaterial(const FBXMaterial& material, const QUrl& textur graphics::Material(*material._material), _textures(MapChannel::NUM_MAP_CHANNELS) { + _name = material.name; if (!material.albedoTexture.filename.isEmpty()) { auto map = fetchTextureMap(textureBaseUrl, material.albedoTexture, image::TextureUsage::ALBEDO_TEXTURE, MapChannel::ALBEDO_MAP); _albedoTransform = material.albedoTexture.transform; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 3a9ea45d77..84687a46d0 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -828,6 +828,7 @@ void Model::removeFromScene(const render::ScenePointer& scene, render::Transacti _modelMeshRenderItemIDs.clear(); _modelMeshRenderItemsMap.clear(); _modelMeshRenderItems.clear(); + _modelMeshMaterialNames.clear(); _modelMeshRenderItemShapes.clear(); foreach(auto item, _collisionRenderItemsMap.keys()) { @@ -1456,6 +1457,7 @@ void Model::createVisibleRenderItemSet() { Q_ASSERT(_modelMeshRenderItems.isEmpty()); _modelMeshRenderItems.clear(); + _modelMeshMaterialNames.clear(); _modelMeshRenderItemShapes.clear(); Transform transform; @@ -1479,6 +1481,7 @@ void Model::createVisibleRenderItemSet() { int numParts = (int)mesh->getNumParts(); for (int partIndex = 0; partIndex < numParts; partIndex++) { _modelMeshRenderItems << std::make_shared(shared_from_this(), i, partIndex, shapeID, transform, offset); + _modelMeshMaterialNames.push_back(getGeometry()->getShapeMaterial(shapeID)->getName()); _modelMeshRenderItemShapes.emplace_back(ShapeInfo{ (int)i }); shapeID++; } @@ -1524,11 +1527,24 @@ bool Model::isRenderable() const { return !_meshStates.empty() || (isLoaded() && _renderGeometry->getMeshes().empty()); } -std::vector Model::getMeshIDsFromMaterialID(const QString& parentMaterialID) { - std::vector toReturn; - // TODO: first, try to find all meshes with materials that match parentMaterialID as a string +std::vector Model::getMeshIDsFromMaterialID(QString parentMaterialID) { + // try to find all meshes with materials that match parentMaterialID as a string // if none, return parentMaterialID as a uint - toReturn.push_back(parentMaterialID.toUInt()); + std::vector toReturn; + const QString MATERIAL_NAME_PREFIX = "mat::"; + if (parentMaterialID.startsWith(MATERIAL_NAME_PREFIX)) { + parentMaterialID.replace(0, MATERIAL_NAME_PREFIX.size(), QString("")); + for (int i = 0; i < _modelMeshMaterialNames.size(); i++) { + if (_modelMeshMaterialNames[i] == parentMaterialID) { + toReturn.push_back(i); + } + } + } + + if (toReturn.empty()) { + toReturn.push_back(parentMaterialID.toUInt()); + } + return toReturn; } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index b4152324bc..67bc646473 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -438,6 +438,7 @@ protected: render::ItemIDs _modelMeshRenderItemIDs; using ShapeInfo = struct { int meshIndex; }; std::vector _modelMeshRenderItemShapes; + std::vector _modelMeshMaterialNames; bool _addedToScene { false }; // has been added to scene bool _needsFixupInScene { true }; // needs to be removed/re-added to scene @@ -472,7 +473,7 @@ private: void calculateTextureInfo(); - std::vector getMeshIDsFromMaterialID(const QString& parentMaterialID); + std::vector getMeshIDsFromMaterialID(QString parentMaterialID); }; Q_DECLARE_METATYPE(ModelPointer) diff --git a/scripts/system/html/entityProperties.html b/scripts/system/html/entityProperties.html index 5eedd1c7e4..a70e42a7e1 100644 --- a/scripts/system/html/entityProperties.html +++ b/scripts/system/html/entityProperties.html @@ -772,12 +772,19 @@
-