From 8f27a4bf2bff33789f702f3edbccbce748a09ce6 Mon Sep 17 00:00:00 2001 From: HifiExperiments Date: Sun, 14 Apr 2024 16:23:45 -0700 Subject: [PATCH 1/2] support VRMC_materials_mtoon and KHR_materials_unlit --- interface/src/avatar/AvatarDoctor.cpp | 8 + interface/src/avatar/AvatarProject.cpp | 8 + libraries/baking/src/MaterialBaker.cpp | 29 ++- libraries/graphics/src/graphics/Material.h | 3 +- libraries/hfm/src/hfm/HFM.cpp | 31 +++ libraries/hfm/src/hfm/HFM.h | 8 + .../src/model-networking/ModelCache.cpp | 26 ++- libraries/model-serializers/CMakeLists.txt | 2 +- .../model-serializers/src/GLTFSerializer.cpp | 177 ++++++++++++++---- .../procedural/ProceduralMaterialCache.cpp | 125 +++++++++++++ .../src/procedural/ProceduralMaterialCache.h | 15 +- 11 files changed, 379 insertions(+), 53 deletions(-) diff --git a/interface/src/avatar/AvatarDoctor.cpp b/interface/src/avatar/AvatarDoctor.cpp index 5c2fc01911..a46652c7d9 100644 --- a/interface/src/avatar/AvatarDoctor.cpp +++ b/interface/src/avatar/AvatarDoctor.cpp @@ -333,6 +333,14 @@ void AvatarDoctor::diagnoseTextures() { addTextureToList(material.occlusionTexture); addTextureToList(material.scatteringTexture); addTextureToList(material.lightmapTexture); + + if (material.isMToonMaterial) { + addTextureToList(material.shadeTexture); + addTextureToList(material.shadingShiftTexture); + addTextureToList(material.matcapTexture); + addTextureToList(material.rimTexture); + addTextureToList(material.uvAnimationTexture); + } } for (const auto& materialMapping : model->getMaterialMapping()) { diff --git a/interface/src/avatar/AvatarProject.cpp b/interface/src/avatar/AvatarProject.cpp index 466db613f6..cf41c0a040 100644 --- a/interface/src/avatar/AvatarProject.cpp +++ b/interface/src/avatar/AvatarProject.cpp @@ -136,6 +136,14 @@ AvatarProject* AvatarProject::createAvatarProject(const QString& projectsFolder, addTextureToList(material.occlusionTexture); addTextureToList(material.scatteringTexture); addTextureToList(material.lightmapTexture); + + if (material.isMToonMaterial) { + addTextureToList(material.shadeTexture); + addTextureToList(material.shadingShiftTexture); + addTextureToList(material.matcapTexture); + addTextureToList(material.rimTexture); + addTextureToList(material.uvAnimationTexture); + } } QDir textureDir(textureFolder.isEmpty() ? fbxInfo.absoluteDir() : textureFolder); diff --git a/libraries/baking/src/MaterialBaker.cpp b/libraries/baking/src/MaterialBaker.cpp index 48718cd6c3..5cb108721d 100644 --- a/libraries/baking/src/MaterialBaker.cpp +++ b/libraries/baking/src/MaterialBaker.cpp @@ -269,19 +269,32 @@ void MaterialBaker::setMaterials(const QHash& materials, _materialResource = NetworkMaterialResourcePointer(new NetworkMaterialResource(), [](NetworkMaterialResource* ptr) { ptr->deleteLater(); }); for (auto& material : materials) { _materialResource->parsedMaterials.names.push_back(material.name.toStdString()); - _materialResource->parsedMaterials.networkMaterials[material.name.toStdString()] = std::make_shared(material, baseURL); + if (!material.isMToonMaterial) { + _materialResource->parsedMaterials.networkMaterials[material.name.toStdString()] = std::make_shared(material, baseURL); + } else { + _materialResource->parsedMaterials.networkMaterials[material.name.toStdString()] = std::make_shared(material, baseURL); + } // Store any embedded texture content addTexture(material.name, image::TextureUsage::NORMAL_TEXTURE, material.normalTexture); addTexture(material.name, image::TextureUsage::ALBEDO_TEXTURE, material.albedoTexture); - addTexture(material.name, image::TextureUsage::GLOSS_TEXTURE, material.glossTexture); - addTexture(material.name, image::TextureUsage::ROUGHNESS_TEXTURE, material.roughnessTexture); - addTexture(material.name, image::TextureUsage::SPECULAR_TEXTURE, material.specularTexture); - addTexture(material.name, image::TextureUsage::METALLIC_TEXTURE, material.metallicTexture); addTexture(material.name, image::TextureUsage::EMISSIVE_TEXTURE, material.emissiveTexture); - addTexture(material.name, image::TextureUsage::OCCLUSION_TEXTURE, material.occlusionTexture); - addTexture(material.name, image::TextureUsage::SCATTERING_TEXTURE, material.scatteringTexture); - addTexture(material.name, image::TextureUsage::LIGHTMAP_TEXTURE, material.lightmapTexture); + + if (!material.isMToonMaterial) { + addTexture(material.name, image::TextureUsage::GLOSS_TEXTURE, material.glossTexture); + addTexture(material.name, image::TextureUsage::ROUGHNESS_TEXTURE, material.roughnessTexture); + addTexture(material.name, image::TextureUsage::SPECULAR_TEXTURE, material.specularTexture); + addTexture(material.name, image::TextureUsage::METALLIC_TEXTURE, material.metallicTexture); + addTexture(material.name, image::TextureUsage::OCCLUSION_TEXTURE, material.occlusionTexture); + addTexture(material.name, image::TextureUsage::SCATTERING_TEXTURE, material.scatteringTexture); + addTexture(material.name, image::TextureUsage::LIGHTMAP_TEXTURE, material.lightmapTexture); + } else { + addTexture(material.name, image::TextureUsage::ALBEDO_TEXTURE, material.shadeTexture); + addTexture(material.name, image::TextureUsage::ROUGHNESS_TEXTURE, material.shadingShiftTexture); + addTexture(material.name, image::TextureUsage::EMISSIVE_TEXTURE, material.matcapTexture); + addTexture(material.name, image::TextureUsage::ALBEDO_TEXTURE, material.rimTexture); + addTexture(material.name, image::TextureUsage::ROUGHNESS_TEXTURE, material.uvAnimationTexture); + } } } diff --git a/libraries/graphics/src/graphics/Material.h b/libraries/graphics/src/graphics/Material.h index 8c67fc19a6..fd9c76dd97 100644 --- a/libraries/graphics/src/graphics/Material.h +++ b/libraries/graphics/src/graphics/Material.h @@ -478,10 +478,9 @@ public: protected: std::string _name { "" }; mutable MaterialKey _key { 0 }; - -private: std::string _model { HIFI_PBR }; +private: // Material properties glm::vec3 _emissive { DEFAULT_EMISSIVE }; float _opacity { DEFAULT_OPACITY }; diff --git a/libraries/hfm/src/hfm/HFM.cpp b/libraries/hfm/src/hfm/HFM.cpp index dd13d6d4f3..53c3ec18dd 100644 --- a/libraries/hfm/src/hfm/HFM.cpp +++ b/libraries/hfm/src/hfm/HFM.cpp @@ -47,6 +47,24 @@ void HFMMaterial::getTextureNames(QSet& textureList) const { if (!lightmapTexture.isNull()) { textureList.insert(lightmapTexture.name); } + + if (isMToonMaterial) { + if (!shadeTexture.isNull()) { + textureList.insert(shadeTexture.name); + } + if (!shadingShiftTexture.isNull()) { + textureList.insert(shadingShiftTexture.name); + } + if (!matcapTexture.isNull()) { + textureList.insert(matcapTexture.name); + } + if (!rimTexture.isNull()) { + textureList.insert(rimTexture.name); + } + if (!uvAnimationTexture.isNull()) { + textureList.insert(uvAnimationTexture.name); + } + } } void HFMMaterial::setMaxNumPixelsPerTexture(int maxNumPixels) { @@ -61,6 +79,12 @@ void HFMMaterial::setMaxNumPixelsPerTexture(int maxNumPixels) { occlusionTexture.maxNumPixels = maxNumPixels; scatteringTexture.maxNumPixels = maxNumPixels; lightmapTexture.maxNumPixels = maxNumPixels; + + shadeTexture.maxNumPixels = maxNumPixels; + shadingShiftTexture.maxNumPixels = maxNumPixels; + matcapTexture.maxNumPixels = maxNumPixels; + rimTexture.maxNumPixels = maxNumPixels; + uvAnimationTexture.maxNumPixels = maxNumPixels; } bool HFMMaterial::needTangentSpace() const { @@ -312,6 +336,13 @@ void HFMModel::debugDump() { qCDebug(modelformat) << " useMetallicMap =" << mat.useMetallicMap; qCDebug(modelformat) << " useEmissiveMap =" << mat.useEmissiveMap; qCDebug(modelformat) << " useOcclusionMap =" << mat.useOcclusionMap; + + qCDebug(modelformat) << " isMToonMaterial =" << mat.isMToonMaterial; + qCDebug(modelformat) << " shadeTexture =" << mat.shadeTexture.filename; + qCDebug(modelformat) << " shadingShiftTexture =" << mat.shadingShiftTexture.filename; + qCDebug(modelformat) << " matcapTexture =" << mat.matcapTexture.filename; + qCDebug(modelformat) << " rimTexture =" << mat.rimTexture.filename; + qCDebug(modelformat) << " uvAnimationTexture =" << mat.uvAnimationTexture.filename; } qCDebug(modelformat) << "---------------- Joints ----------------"; diff --git a/libraries/hfm/src/hfm/HFM.h b/libraries/hfm/src/hfm/HFM.h index d082f30dc5..6932572b1d 100644 --- a/libraries/hfm/src/hfm/HFM.h +++ b/libraries/hfm/src/hfm/HFM.h @@ -224,6 +224,14 @@ public: bool useEmissiveMap { false }; bool useOcclusionMap { false }; + + bool isMToonMaterial { false }; + Texture shadeTexture; + Texture shadingShiftTexture; + Texture matcapTexture; + Texture rimTexture; + Texture uvAnimationTexture; + bool needTangentSpace() const; }; diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index a488098b1b..ddfdeb79d1 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -325,7 +325,11 @@ void GeometryResource::setGeometryDefinition(HFMModel::Pointer hfmModel, const M QHash materialIDAtlas; for (const HFMMaterial& material : _hfmModel->materials) { materialIDAtlas[material.materialID] = _materials.size(); - _materials.push_back(std::make_shared(material, _textureBaseURL)); + if (!material.isMToonMaterial) { + _materials.push_back(std::make_shared(material, _textureBaseURL)); + } else { + _materials.push_back(std::make_shared(material, _textureBaseURL)); + } } std::shared_ptr meshes = std::make_shared(); @@ -357,7 +361,11 @@ void GeometryResource::setTextures() { if (_hfmModel) { if (DependencyManager::get()) { for (const HFMMaterial& material : _hfmModel->materials) { - _materials.push_back(std::make_shared(material, _textureBaseURL)); + if (!material.isMToonMaterial) { + _materials.push_back(std::make_shared(material, _textureBaseURL)); + } else { + _materials.push_back(std::make_shared(material, _textureBaseURL)); + } } } else { qDebug() << "GeometryResource::setTextures: TextureCache dependency not available, skipping textures"; @@ -436,7 +444,11 @@ Geometry::Geometry(const Geometry& geometry) { _materials.reserve(geometry._materials.size()); for (const auto& material : geometry._materials) { - _materials.push_back(std::make_shared(*material)); + if (!material->isMToon()) { + _materials.push_back(std::make_shared(*material)); + } else if (auto mToonMaterial = std::static_pointer_cast(material)) { + _materials.push_back(std::make_shared(*mToonMaterial)); + } } _animGraphOverrideUrl = geometry._animGraphOverrideUrl; @@ -452,9 +464,13 @@ void Geometry::setTextures(const QVariantMap& textureMap) { // FIXME: The Model currently caches the materials (waste of space!) // so they must be copied in the Geometry copy-ctor - // if (material->isOriginal()) { + //if (material->isOriginal()) { // // Copy the material to avoid mutating the cached version - // material = std::make_shared(*material); + // if (!material->isMToon()) { + // material = std::make_shared(*material); + // } else { + // material = std::make_shared(*material); + // } //} material->setTextures(textureMap); diff --git a/libraries/model-serializers/CMakeLists.txt b/libraries/model-serializers/CMakeLists.txt index 76775896dc..b0b0dd6344 100644 --- a/libraries/model-serializers/CMakeLists.txt +++ b/libraries/model-serializers/CMakeLists.txt @@ -1,7 +1,7 @@ set(TARGET_NAME model-serializers) setup_hifi_library() -link_hifi_libraries(shared graphics networking image hfm) +link_hifi_libraries(shared graphics networking image hfm procedural material-networking ktx shaders) include_hifi_library_headers(gpu image) target_draco() diff --git a/libraries/model-serializers/src/GLTFSerializer.cpp b/libraries/model-serializers/src/GLTFSerializer.cpp index 1c6076809f..3896c0577d 100644 --- a/libraries/model-serializers/src/GLTFSerializer.cpp +++ b/libraries/model-serializers/src/GLTFSerializer.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include "FBXSerializer.h" @@ -109,7 +110,7 @@ bool GLTFSerializer::getSkinInverseBindMatrices(std::vector>& if (matricesAccessor.type != cgltf_type_mat4) { return false; } - matrices.resize(matricesAccessor.count * 16); + matrices.resize((int)matricesAccessor.count * 16); size_t numFloats = cgltf_accessor_unpack_floats(&matricesAccessor, matrices.data(), matricesAccessor.count * 16); Q_ASSERT(numFloats == matricesAccessor.count * 16); inverseBindMatrixValues.push_back(std::vector(matrices.begin(), matrices.end())); @@ -125,7 +126,7 @@ bool GLTFSerializer::generateTargetData(cgltf_accessor *accessor, float weight, if (accessor->type != cgltf_type_vec3) { return false; } - storedValues.resize(accessor->count * 3); + storedValues.resize((int)accessor->count * 3); size_t numFloats = cgltf_accessor_unpack_floats(accessor, storedValues.data(), accessor->count * 3); if (numFloats != accessor->count * 3) { return false; @@ -147,8 +148,8 @@ bool findNodeInPointerArray(const cgltf_node *nodePointer, cgltf_node **nodes, s return false; } -template bool findPointerInArray(const T *pointer, const T *array, size_t arraySize, size_t &index) { - for (size_t i = 0; i < arraySize; i++) { +template bool findPointerInArray(const T *pointer, const T *array, size_t arraySize, int &index) { + for (int i = 0; i < arraySize; i++) { if (&array[i] == pointer) { index = i; return true; @@ -175,18 +176,18 @@ bool findAttribute(const QString &name, const cgltf_attribute *attributes, size_ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& mapping, const hifi::URL& url) { hfmModel.originalURL = url.toString(); - size_t numNodes = _data->nodes_count; + int numNodes = (int)_data->nodes_count; //Build dependencies QVector parents; QVector sortedNodes; parents.fill(-1, numNodes); sortedNodes.reserve(numNodes); - for(size_t index = 0; index < numNodes; index++) { + for(int index = 0; index < numNodes; index++) { auto &node = _data->nodes[index]; for(size_t childIndexInParent = 0; childIndexInParent < node.children_count; childIndexInParent++) { cgltf_node *child = node.children[childIndexInParent]; - size_t childIndex = 0; + int childIndex = 0; if (!findPointerInArray(child, _data->nodes, _data->nodes_count, childIndex)) { qDebug(modelformat) << "findPointerInArray failed for model: " << _url; hfmModel.loadErrorCount++; @@ -201,7 +202,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& typedef QVector NodeTransforms; QVector transforms; transforms.resize(numNodes); - for (size_t index = 0; index < numNodes; index++) { + for (int index = 0; index < numNodes; index++) { // collect node transform auto &node = _data->nodes[index]; transforms[index].push_back(getModelTransform(node)); @@ -219,7 +220,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& QVector hasBeenSorted; hasBeenSorted.fill(false, numNodes); { - size_t i = 0; // initial index + int i = 0; // initial index while (i < numNodes) { int currentNode = sortedNodes[i]; int parentIndex = parents[currentNode]; @@ -227,7 +228,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& hasBeenSorted[currentNode] = true; ++i; } else { - size_t j = i + 1; // index of node to be sorted + int j = i + 1; // index of node to be sorted while (j < numNodes) { int nextNode = sortedNodes[j]; parentIndex = parents[nextNode]; @@ -249,7 +250,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& // Build map from original to new indices QVector originalToNewNodeIndexMap; originalToNewNodeIndexMap.fill(-1, numNodes); - for (size_t i = 0; i < numNodes; ++i) { + for (int i = 0; i < numNodes; ++i) { originalToNewNodeIndexMap[sortedNodes[i]] = i; } @@ -311,7 +312,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& return false; } - for (size_t jointIndex = 0; jointIndex < numNodes; ++jointIndex) { + for (int jointIndex = 0; jointIndex < numNodes; ++jointIndex) { int nodeIndex = sortedNodes[jointIndex]; auto joint = hfmModel.joints[jointIndex]; @@ -365,18 +366,17 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& materialIDs.push_back(mid); } - for (size_t i = 0; i < (size_t)materialIDs.size(); ++i) { + for (int i = 0; i < materialIDs.size(); ++i) { QString& matid = materialIDs[i]; hfmModel.materials[matid] = HFMMaterial(); HFMMaterial& hfmMaterial = hfmModel.materials[matid]; - hfmMaterial._material = std::make_shared(); hfmMaterial.name = hfmMaterial.materialID = matid; setHFMMaterial(hfmMaterial, _data->materials[i]); } // Build meshes - size_t nodeCount = 0; + int nodeCount = 0; hfmModel.meshExtents.reset(); for (int nodeIndex : sortedNodes) { auto& node = _data->nodes[nodeIndex]; @@ -394,7 +394,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& cluster.inverseBindTransform = Transform(cluster.inverseBindMatrix); mesh.clusters.append(cluster); } else { // skinned model - for (size_t j = 0; j < numNodes; ++j) { + for (int j = 0; j < numNodes; ++j) { HFMCluster cluster; cluster.jointIndex = j; cluster.inverseBindMatrix = jointInverseBindTransforms[j]; @@ -450,7 +450,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& QVector weights; int weightStride = 4; - indices.resize(indicesAccessor->count); + indices.resize((int)indicesAccessor->count); size_t readIndicesCount = cgltf_accessor_unpack_indices(indicesAccessor, indices.data(), sizeof(unsigned int), indicesAccessor->count); if (readIndicesCount != indicesAccessor->count) { @@ -480,6 +480,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& return false; } auto accessor = primitive.attributes[attributeIndex].data; + int accessorCount = (int)accessor->count; if (key == "POSITION") { if (accessor->type != cgltf_type_vec3) { @@ -488,7 +489,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& continue; } - vertices.resize(accessor->count * 3); + vertices.resize(accessorCount * 3); size_t floatCount = cgltf_accessor_unpack_floats(accessor, vertices.data(), accessor->count * 3); if (floatCount != accessor->count * 3) { qWarning(modelformat) << "There was a problem reading glTF POSITION data for model " << _url; @@ -502,7 +503,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& continue; } - normals.resize(accessor->count * 3); + normals.resize(accessorCount * 3); size_t floatCount = cgltf_accessor_unpack_floats(accessor, normals.data(), accessor->count * 3); if (floatCount != accessor->count * 3) { qWarning(modelformat) << "There was a problem reading glTF NORMAL data for model " << _url; @@ -520,7 +521,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& continue; } - tangents.resize(accessor->count * tangentStride); + tangents.resize(accessorCount * tangentStride); size_t floatCount = cgltf_accessor_unpack_floats(accessor, tangents.data(), accessor->count * tangentStride); if (floatCount != accessor->count * tangentStride) { qWarning(modelformat) << "There was a problem reading glTF TANGENT data for model " << _url; @@ -535,7 +536,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& continue; } - texcoords.resize(accessor->count * 2); + texcoords.resize(accessorCount * 2); size_t floatCount = cgltf_accessor_unpack_floats(accessor, texcoords.data(), accessor->count * 2); if (floatCount != accessor->count * 2) { qWarning(modelformat) << "There was a problem reading glTF TEXCOORD_0 data for model " << _url; @@ -549,7 +550,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& continue; } - texcoords2.resize(accessor->count * 2); + texcoords2.resize(accessorCount * 2); size_t floatCount = cgltf_accessor_unpack_floats(accessor, texcoords2.data(), accessor->count * 2); if (floatCount != accessor->count * 2) { qWarning(modelformat) << "There was a problem reading glTF TEXCOORD_1 data for model " << _url; @@ -567,7 +568,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& continue; } - colors.resize(accessor->count * colorStride); + colors.resize(accessorCount * colorStride); size_t floatCount = cgltf_accessor_unpack_floats(accessor, colors.data(), accessor->count * colorStride); if (floatCount != accessor->count * colorStride) { qWarning(modelformat) << "There was a problem reading glTF COLOR_0 data for model " << _url; @@ -589,12 +590,12 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& continue; } - joints.resize(accessor->count * jointStride); + joints.resize(accessorCount * jointStride); cgltf_uint jointIndices[4]; for (size_t i = 0; i < accessor->count; i++) { cgltf_accessor_read_uint(accessor, i, jointIndices, jointStride); for (int component = 0; component < jointStride; component++) { - joints[i * jointStride + component] = (uint16_t)jointIndices[component]; + joints[(int)i * jointStride + component] = (uint16_t)jointIndices[component]; } } @@ -613,7 +614,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& continue; } - weights.resize(accessor->count * weightStride); + weights.resize(accessorCount * weightStride); size_t floatCount = cgltf_accessor_unpack_floats(accessor, weights.data(), accessor->count * weightStride); if (floatCount != accessor->count * weightStride) { qWarning(modelformat) << "There was a problem reading glTF WEIGHTS_0 data for model " << _url; @@ -917,7 +918,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& continue; } - size_t jointIndex = 0; + int jointIndex = 0; if (!findPointerInArray(node.skin->joints[clusterJoints[c]], _data->nodes, _data->nodes_count, jointIndex)) { qCWarning(modelformat) << "Cannot find the joint " << node.skin->joints[clusterJoints[c]]->name <<" in joint array"; hfmModel.loadErrorCount++; @@ -960,7 +961,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& } } - size_t materialIndex = 0; + int materialIndex = 0; if (primitive.material != nullptr && !findPointerInArray(primitive.material, _data->materials, _data->materials_count, materialIndex)) { qCWarning(modelformat) << "GLTFSerializer::buildGeometry: Invalid material pointer"; hfmModel.loadErrorCount++; @@ -1012,7 +1013,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& // If an FST isn't being used and the model is likely from ReadyPlayerMe, add blendshape synonyms. QVector fileTargetNames; - fileTargetNames.reserve(node.mesh->target_names_count); + fileTargetNames.reserve((int)node.mesh->target_names_count); for (size_t i = 0; i < node.mesh->target_names_count; i++) { fileTargetNames.push_back(QString(node.mesh->target_names[i])); } @@ -1048,7 +1049,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& auto keys = blendshapeIndices.keys(); auto values = blendshapeIndices.values(); QVector names; - names.reserve(node.mesh->target_names_count); + names.reserve((int)node.mesh->target_names_count); for (size_t i = 0; i < node.mesh->target_names_count; i++) { names.push_back(QString(node.mesh->target_names[i])); } @@ -1303,9 +1304,9 @@ HFMTexture GLTFSerializer::getHFMTexture(const cgltf_texture *texture) { cgltf_buffer_view *bufferView = image->buffer_view; size_t offset = bufferView->offset; - size_t length = bufferView->size; + int length = (int)bufferView->size; - size_t imageIndex = 0; + int imageIndex = 0; if (!findPointerInArray(image, _data->images, _data->images_count, imageIndex)) { // This should never happen. It would mean a bug in cgltf library. qDebug(modelformat) << "GLTFSerializer::getHFMTexture: can't find texture in the array"; @@ -1328,6 +1329,113 @@ HFMTexture GLTFSerializer::getHFMTexture(const cgltf_texture *texture) { } void GLTFSerializer::setHFMMaterial(HFMMaterial& hfmMat, const cgltf_material& material) { + hfmMat._material = std::make_shared(); + for (size_t i = 0; i < material.extensions_count; i++) { + auto& extension = material.extensions[i]; + if (extension.name != nullptr) { + if (strcmp(extension.name, "VRMC_materials_mtoon") == 0 && extension.data != nullptr) { + hfmMat.isMToonMaterial = true; + auto mToonMaterial = std::make_shared(); + QJsonDocument mToonExtension = QJsonDocument::fromJson(extension.data); + if (!mToonExtension.isNull()) { + if (mToonExtension["shadeColorFactor"].isArray()) { + auto array = mToonExtension["shadeColorFactor"].toArray(); + glm::vec3 shadeLinear = glm::vec3(array[0].toDouble(), array[1].toDouble(), array[2].toDouble()); + glm::vec3 shade = ColorUtils::tosRGBVec3(shadeLinear); + mToonMaterial->setShade(shade); + } + if (mToonExtension["shadeMultiplyTexture"].isObject()) { + QJsonObject object = mToonExtension["shadeMultiplyTexture"].toObject(); + if (object["index"].isDouble() && object["index"].toInt() < _data->textures_count) { + hfmMat.shadeTexture = getHFMTexture(&_data->textures[object["index"].toInt()]); + } + } + if (mToonExtension["shadingShiftFactor"].isDouble()) { + mToonMaterial->setShadingShift(mToonExtension["shadingShiftFactor"].toDouble()); + } + if (mToonExtension["shadingShiftTexture"].isObject()) { + QJsonObject object = mToonExtension["shadingShiftTexture"].toObject(); + if (object["index"].isDouble() && object["index"].toInt() < _data->textures_count) { + hfmMat.shadingShiftTexture = getHFMTexture(&_data->textures[object["index"].toInt()]); + } + } + if (mToonExtension["shadingToonyFactor"].isDouble()) { + mToonMaterial->setShadingToony(mToonExtension["shadingToonyFactor"].toDouble()); + } + if (mToonExtension["matcapFactor"].isArray()) { + auto array = mToonExtension["matcapFactor"].toArray(); + glm::vec3 matcapLinear = glm::vec3(array[0].toDouble(), array[1].toDouble(), array[2].toDouble()); + glm::vec3 matcap = ColorUtils::tosRGBVec3(matcapLinear); + mToonMaterial->setMatcap(matcap); + } + if (mToonExtension["matcapTexture"].isObject()) { + QJsonObject object = mToonExtension["matcapTexture"].toObject(); + if (object["index"].isDouble() && object["index"].toInt() < _data->textures_count) { + hfmMat.matcapTexture = getHFMTexture(&_data->textures[object["index"].toInt()]); + } + } + if (mToonExtension["parametricRimColorFactor"].isArray()) { + auto array = mToonExtension["parametricRimColorFactor"].toArray(); + glm::vec3 parametricRimLinear = glm::vec3(array[0].toDouble(), array[1].toDouble(), array[2].toDouble()); + glm::vec3 parametricRim = ColorUtils::tosRGBVec3(parametricRimLinear); + mToonMaterial->setParametricRim(parametricRim); + } + if (mToonExtension["parametricRimFresnelPowerFactor"].isDouble()) { + mToonMaterial->setParametricRimFresnelPower(mToonExtension["parametricRimFresnelPowerFactor"].toDouble()); + } + if (mToonExtension["parametricRimLiftFactor"].isDouble()) { + mToonMaterial->setParametricRimLift(mToonExtension["parametricRimLiftFactor"].toDouble()); + } + if (mToonExtension["rimMultiplyTexture"].isObject()) { + QJsonObject object = mToonExtension["rimMultiplyTexture"].toObject(); + if (object["index"].isDouble() && object["index"].toInt() < _data->textures_count) { + hfmMat.rimTexture = getHFMTexture(&_data->textures[object["index"].toInt()]); + } + } + if (mToonExtension["rimLightingMixFactor"].isDouble()) { + mToonMaterial->setRimLightingMix(mToonExtension["rimLightingMixFactor"].toDouble()); + } + // FIXME: Outlines are currently disabled because they're buggy + //if (mToonExtension["outlineWidthMode"].isString()) { + // QString outlineWidthMode = mToonExtension["outlineWidthMode"].toString(); + // if (outlineWidthMode == "none") { + // mToonMaterial->setOutlineWidthMode(NetworkMToonMaterial::OutlineWidthMode::OUTLINE_NONE); + // } else if (outlineWidthMode == "worldCoordinates") { + // mToonMaterial->setOutlineWidthMode(NetworkMToonMaterial::OutlineWidthMode::OUTLINE_WORLD); + // } else if (outlineWidthMode == "screenCoordinates") { + // mToonMaterial->setOutlineWidthMode(NetworkMToonMaterial::OutlineWidthMode::OUTLINE_SCREEN); + // } + //} + if (mToonExtension["outlineWidthFactor"].isDouble()) { + mToonMaterial->setOutlineWidth(mToonExtension["outlineWidthFactor"].toDouble()); + } + if (mToonExtension["outlineColorFactor"].isArray()) { + auto array = mToonExtension["outlineColorFactor"].toArray(); + glm::vec3 outlineLinear = glm::vec3(array[0].toDouble(), array[1].toDouble(), array[2].toDouble()); + glm::vec3 outline = ColorUtils::tosRGBVec3(outlineLinear); + mToonMaterial->setOutline(outline); + } + if (mToonExtension["uvAnimationMaskTexture"].isObject()) { + QJsonObject object = mToonExtension["uvAnimationMaskTexture"].toObject(); + if (object["index"].isDouble() && object["index"].toInt() < _data->textures_count) { + hfmMat.uvAnimationTexture = getHFMTexture(&_data->textures[object["index"].toInt()]); + } + } + if (mToonExtension["uvAnimationScrollXSpeedFactor"].isDouble()) { + mToonMaterial->setUVAnimationScrollXSpeed(mToonExtension["uvAnimationScrollXSpeedFactor"].toDouble()); + } + if (mToonExtension["uvAnimationScrollYSpeedFactor"].isDouble()) { + mToonMaterial->setUVAnimationScrollYSpeed(mToonExtension["uvAnimationScrollYSpeedFactor"].toDouble()); + } + if (mToonExtension["uvAnimationRotationSpeedFactor"].isDouble()) { + mToonMaterial->setUVAnimationRotationSpeed(mToonExtension["uvAnimationRotationSpeedFactor"].toDouble()); + } + } + hfmMat._material = mToonMaterial; + } + } + } + if (material.alpha_mode == cgltf_alpha_mode_opaque) { hfmMat._material->setOpacityMapMode(graphics::MaterialKey::OPACITY_MAP_OPAQUE); } else if (material.alpha_mode == cgltf_alpha_mode_mask) { @@ -1340,6 +1448,11 @@ void GLTFSerializer::setHFMMaterial(HFMMaterial& hfmMat, const cgltf_material& m hfmMat._material->setOpacityCutoff(material.alpha_cutoff); + // VRMC_materials_mtoon takes precedence over KHR_materials_unlit + if (!hfmMat.isMToonMaterial) { + hfmMat._material->setUnlit(material.unlit); + } + if (material.double_sided) { hfmMat._material->setCullFaceMode(graphics::MaterialKey::CullFaceMode::CULL_NONE); } diff --git a/libraries/procedural/src/procedural/ProceduralMaterialCache.cpp b/libraries/procedural/src/procedural/ProceduralMaterialCache.cpp index f1dc8eedd4..40044bed43 100644 --- a/libraries/procedural/src/procedural/ProceduralMaterialCache.cpp +++ b/libraries/procedural/src/procedural/ProceduralMaterialCache.cpp @@ -1134,6 +1134,65 @@ bool NetworkMaterial::checkResetOpacityMap() { return false; } +NetworkMToonMaterial::NetworkMToonMaterial(const HFMMaterial& material, const QUrl& textureBaseUrl) : + NetworkMaterial(*material._material) +{ + _name = material.name.toStdString(); + if (!material.albedoTexture.filename.isEmpty()) { + auto map = fetchTextureMap(textureBaseUrl, material.albedoTexture, image::TextureUsage::ALBEDO_TEXTURE, MapChannel::ALBEDO_MAP); + if (map) { + _albedoTransform = material.albedoTexture.transform; + map->setTextureTransform(_albedoTransform); + + if (!material.opacityTexture.filename.isEmpty()) { + if (material.albedoTexture.filename == material.opacityTexture.filename) { + // Best case scenario, just indicating that the albedo map contains transparency + // TODO: Different albedo/opacity maps are not currently supported + map->setUseAlphaChannel(true); + } + } + } + + setTextureMap(MapChannel::ALBEDO_MAP, map); + } + + if (!material.normalTexture.filename.isEmpty()) { + auto type = (material.normalTexture.isBumpmap ? image::TextureUsage::BUMP_TEXTURE : image::TextureUsage::NORMAL_TEXTURE); + auto map = fetchTextureMap(textureBaseUrl, material.normalTexture, type, MapChannel::NORMAL_MAP); + setTextureMap(MapChannel::NORMAL_MAP, map); + } + + if (!material.emissiveTexture.filename.isEmpty()) { + auto map = fetchTextureMap(textureBaseUrl, material.emissiveTexture, image::TextureUsage::EMISSIVE_TEXTURE, MapChannel::EMISSIVE_MAP); + setTextureMap(MapChannel::EMISSIVE_MAP, map); + } + + if (!material.shadeTexture.filename.isEmpty()) { + auto map = fetchTextureMap(textureBaseUrl, material.shadeTexture, image::TextureUsage::ALBEDO_TEXTURE, (MapChannel)MToonMapChannel::SHADE_MAP); + setTextureMap((MapChannel)MToonMapChannel::SHADE_MAP, map); + } + + if (!material.shadingShiftTexture.filename.isEmpty()) { + auto map = fetchTextureMap(textureBaseUrl, material.shadingShiftTexture, image::TextureUsage::ROUGHNESS_TEXTURE, (MapChannel)MToonMapChannel::SHADING_SHIFT_MAP); + setTextureMap((MapChannel)MToonMapChannel::SHADING_SHIFT_MAP, map); + } + + if (!material.matcapTexture.filename.isEmpty()) { + auto map = fetchTextureMap(textureBaseUrl, material.matcapTexture, image::TextureUsage::EMISSIVE_TEXTURE, (MapChannel)MToonMapChannel::MATCAP_MAP); + setTextureMap((MapChannel)MToonMapChannel::MATCAP_MAP, map); + } + + if (!material.rimTexture.filename.isEmpty()) { + auto map = fetchTextureMap(textureBaseUrl, material.rimTexture, image::TextureUsage::ALBEDO_TEXTURE, (MapChannel)MToonMapChannel::RIM_MAP); + setTextureMap((MapChannel)MToonMapChannel::RIM_MAP, map); + } + + if (!material.uvAnimationTexture.filename.isEmpty()) { + auto map = fetchTextureMap(textureBaseUrl, material.uvAnimationTexture, image::TextureUsage::ROUGHNESS_TEXTURE, (MapChannel)MToonMapChannel::UV_ANIMATION_MASK_MAP); + setTextureMap((MapChannel)MToonMapChannel::UV_ANIMATION_MASK_MAP, map); + } +} + NetworkMToonMaterial::NetworkMToonMaterial(const NetworkMToonMaterial& material) : NetworkMaterial(material), _shade(material._shade), @@ -1152,6 +1211,72 @@ NetworkMToonMaterial::NetworkMToonMaterial(const NetworkMToonMaterial& material) _outline(material._outline) {} +void NetworkMToonMaterial::setTextures(const QVariantMap& textureMap) { + _isOriginal = false; + + const auto& albedoName = getTextureName(MapChannel::ALBEDO_MAP); + const auto& normalName = getTextureName(MapChannel::NORMAL_MAP); + const auto& emissiveName = getTextureName(MapChannel::EMISSIVE_MAP); + const auto& shadeName = getTextureName((MapChannel)MToonMapChannel::SHADE_MAP); + const auto& shadingShiftName = getTextureName((MapChannel)MToonMapChannel::SHADING_SHIFT_MAP); + const auto& matcapName = getTextureName((MapChannel)MToonMapChannel::MATCAP_MAP); + const auto& rimName = getTextureName((MapChannel)MToonMapChannel::RIM_MAP); + const auto& uvAnimationMaskName = getTextureName((MapChannel)MToonMapChannel::UV_ANIMATION_MASK_MAP); + + if (!albedoName.isEmpty()) { + auto url = textureMap.contains(albedoName) ? textureMap[albedoName].toUrl() : QUrl(); + auto map = fetchTextureMap(url, image::TextureUsage::ALBEDO_TEXTURE, MapChannel::ALBEDO_MAP); + if (map) { + map->setTextureTransform(_albedoTransform); + // when reassigning the albedo texture we also check for the alpha channel used as opacity + map->setUseAlphaChannel(true); + } + setTextureMap(MapChannel::ALBEDO_MAP, map); + } + + if (!normalName.isEmpty()) { + auto url = textureMap.contains(normalName) ? textureMap[normalName].toUrl() : QUrl(); + auto map = fetchTextureMap(url, image::TextureUsage::NORMAL_TEXTURE, MapChannel::NORMAL_MAP); + setTextureMap(MapChannel::NORMAL_MAP, map); + } + + if (!emissiveName.isEmpty()) { + auto url = textureMap.contains(emissiveName) ? textureMap[emissiveName].toUrl() : QUrl(); + auto map = fetchTextureMap(url, image::TextureUsage::EMISSIVE_TEXTURE, MapChannel::EMISSIVE_MAP); + setTextureMap(MapChannel::EMISSIVE_MAP, map); + } + + if (!shadeName.isEmpty()) { + auto url = textureMap.contains(shadeName) ? textureMap[shadeName].toUrl() : QUrl(); + auto map = fetchTextureMap(url, image::TextureUsage::ALBEDO_TEXTURE, (MapChannel)MToonMapChannel::SHADE_MAP); + setTextureMap((MapChannel)MToonMapChannel::SHADE_MAP, map); + } + + if (!shadingShiftName.isEmpty()) { + auto url = textureMap.contains(shadingShiftName) ? textureMap[shadingShiftName].toUrl() : QUrl(); + auto map = fetchTextureMap(url, image::TextureUsage::ROUGHNESS_TEXTURE, (MapChannel)MToonMapChannel::SHADING_SHIFT_MAP); + setTextureMap((MapChannel)MToonMapChannel::SHADING_SHIFT_MAP, map); + } + + if (!matcapName.isEmpty()) { + auto url = textureMap.contains(matcapName) ? textureMap[matcapName].toUrl() : QUrl(); + auto map = fetchTextureMap(url, image::TextureUsage::EMISSIVE_TEXTURE, (MapChannel)MToonMapChannel::MATCAP_MAP); + setTextureMap((MapChannel)MToonMapChannel::MATCAP_MAP, map); + } + + if (!rimName.isEmpty()) { + auto url = textureMap.contains(rimName) ? textureMap[rimName].toUrl() : QUrl(); + auto map = fetchTextureMap(url, image::TextureUsage::ALBEDO_TEXTURE, (MapChannel)MToonMapChannel::RIM_MAP); + setTextureMap((MapChannel)MToonMapChannel::RIM_MAP, map); + } + + if (!uvAnimationMaskName.isEmpty()) { + auto url = textureMap.contains(uvAnimationMaskName) ? textureMap[uvAnimationMaskName].toUrl() : QUrl(); + auto map = fetchTextureMap(url, image::TextureUsage::ROUGHNESS_TEXTURE, (MapChannel)MToonMapChannel::UV_ANIMATION_MASK_MAP); + setTextureMap((MapChannel)MToonMapChannel::UV_ANIMATION_MASK_MAP, map); + } +} + std::string NetworkMToonMaterial::getOutlineWidthModeName(OutlineWidthMode mode) { const std::string names[3] = { "none", "worldCoordinates", "screenCoordinates" }; return names[mode]; diff --git a/libraries/procedural/src/procedural/ProceduralMaterialCache.h b/libraries/procedural/src/procedural/ProceduralMaterialCache.h index bdc4c9c583..ec64d8d77f 100644 --- a/libraries/procedural/src/procedural/ProceduralMaterialCache.h +++ b/libraries/procedural/src/procedural/ProceduralMaterialCache.h @@ -26,6 +26,7 @@ public: NetworkMaterial() : _textures(MapChannel::NUM_MAP_CHANNELS) {} NetworkMaterial(const HFMMaterial& material, const QUrl& textureBaseUrl); NetworkMaterial(const NetworkMaterial& material); + NetworkMaterial(const graphics::Material material) : graphics::Material(material) {} void setAlbedoMap(const QUrl& url, bool useAlphaChannel); void setNormalMap(const QUrl& url, bool isBumpmap); @@ -60,7 +61,7 @@ protected: static const QString NO_TEXTURE; const QString& getTextureName(MapChannel channel); - void setTextures(const QVariantMap& textureMap); + virtual void setTextures(const QVariantMap& textureMap); const bool& isOriginal() const { return _isOriginal; } @@ -68,22 +69,26 @@ protected: image::TextureUsage::Type type, MapChannel channel); graphics::TextureMapPointer fetchTextureMap(const QUrl& url, image::TextureUsage::Type type, MapChannel channel); + Transform _albedoTransform; + + bool _isOriginal{ true }; + private: // Helpers for the ctors QUrl getTextureUrl(const QUrl& baseUrl, const HFMTexture& hfmTexture); - Transform _albedoTransform; Transform _lightmapTransform; vec2 _lightmapParams; - - bool _isOriginal { true }; }; class NetworkMToonMaterial : public NetworkMaterial { public: - NetworkMToonMaterial() : NetworkMaterial() {} + NetworkMToonMaterial() : NetworkMaterial() { _model = VRM_MTOON; } + NetworkMToonMaterial(const HFMMaterial& material, const QUrl& textureBaseUrl); NetworkMToonMaterial(const NetworkMToonMaterial& material); + void setTextures(const QVariantMap& textureMap) override; + enum MToonMapChannel { // Keep aligned with graphics/ShaderConstants.h and graphics-scripting/ScriptableModel.cpp SHADE_MAP = MapChannel::ROUGHNESS_MAP, From 74002b47385d8c80e086f2a7dbf68bea16380253 Mon Sep 17 00:00:00 2001 From: HifiExperiments Date: Fri, 19 Apr 2024 16:05:59 -0700 Subject: [PATCH 2/2] simplify constructors --- .../procedural/ProceduralMaterialCache.cpp | 36 +++---------------- .../src/procedural/ProceduralMaterialCache.h | 3 +- 2 files changed, 5 insertions(+), 34 deletions(-) diff --git a/libraries/procedural/src/procedural/ProceduralMaterialCache.cpp b/libraries/procedural/src/procedural/ProceduralMaterialCache.cpp index 40044bed43..f76200ea57 100644 --- a/libraries/procedural/src/procedural/ProceduralMaterialCache.cpp +++ b/libraries/procedural/src/procedural/ProceduralMaterialCache.cpp @@ -826,9 +826,9 @@ NetworkMaterial::NetworkMaterial(const NetworkMaterial& m) : Material(m), _textures(m._textures), _albedoTransform(m._albedoTransform), + _isOriginal(m._isOriginal), _lightmapTransform(m._lightmapTransform), - _lightmapParams(m._lightmapParams), - _isOriginal(m._isOriginal) + _lightmapParams(m._lightmapParams) {} const QString NetworkMaterial::NO_TEXTURE = QString(); @@ -1135,37 +1135,9 @@ bool NetworkMaterial::checkResetOpacityMap() { } NetworkMToonMaterial::NetworkMToonMaterial(const HFMMaterial& material, const QUrl& textureBaseUrl) : - NetworkMaterial(*material._material) + NetworkMaterial(material, textureBaseUrl) // handles _name, albedoMap, normalMap, and emissiveMap { - _name = material.name.toStdString(); - if (!material.albedoTexture.filename.isEmpty()) { - auto map = fetchTextureMap(textureBaseUrl, material.albedoTexture, image::TextureUsage::ALBEDO_TEXTURE, MapChannel::ALBEDO_MAP); - if (map) { - _albedoTransform = material.albedoTexture.transform; - map->setTextureTransform(_albedoTransform); - - if (!material.opacityTexture.filename.isEmpty()) { - if (material.albedoTexture.filename == material.opacityTexture.filename) { - // Best case scenario, just indicating that the albedo map contains transparency - // TODO: Different albedo/opacity maps are not currently supported - map->setUseAlphaChannel(true); - } - } - } - - setTextureMap(MapChannel::ALBEDO_MAP, map); - } - - if (!material.normalTexture.filename.isEmpty()) { - auto type = (material.normalTexture.isBumpmap ? image::TextureUsage::BUMP_TEXTURE : image::TextureUsage::NORMAL_TEXTURE); - auto map = fetchTextureMap(textureBaseUrl, material.normalTexture, type, MapChannel::NORMAL_MAP); - setTextureMap(MapChannel::NORMAL_MAP, map); - } - - if (!material.emissiveTexture.filename.isEmpty()) { - auto map = fetchTextureMap(textureBaseUrl, material.emissiveTexture, image::TextureUsage::EMISSIVE_TEXTURE, MapChannel::EMISSIVE_MAP); - setTextureMap(MapChannel::EMISSIVE_MAP, map); - } + _model = VRM_MTOON; if (!material.shadeTexture.filename.isEmpty()) { auto map = fetchTextureMap(textureBaseUrl, material.shadeTexture, image::TextureUsage::ALBEDO_TEXTURE, (MapChannel)MToonMapChannel::SHADE_MAP); diff --git a/libraries/procedural/src/procedural/ProceduralMaterialCache.h b/libraries/procedural/src/procedural/ProceduralMaterialCache.h index ec64d8d77f..a7c5baa011 100644 --- a/libraries/procedural/src/procedural/ProceduralMaterialCache.h +++ b/libraries/procedural/src/procedural/ProceduralMaterialCache.h @@ -26,7 +26,6 @@ public: NetworkMaterial() : _textures(MapChannel::NUM_MAP_CHANNELS) {} NetworkMaterial(const HFMMaterial& material, const QUrl& textureBaseUrl); NetworkMaterial(const NetworkMaterial& material); - NetworkMaterial(const graphics::Material material) : graphics::Material(material) {} void setAlbedoMap(const QUrl& url, bool useAlphaChannel); void setNormalMap(const QUrl& url, bool isBumpmap); @@ -71,7 +70,7 @@ protected: Transform _albedoTransform; - bool _isOriginal{ true }; + bool _isOriginal { true }; private: // Helpers for the ctors