From 4f03157f3989afb4d337bc951f1a2c8dfd70af19 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Mon, 11 Feb 2019 10:20:55 -0800 Subject: [PATCH] working on fst material mapping --- libraries/material-networking/CMakeLists.txt | 2 +- .../src/material-networking/MaterialCache.h | 2 + .../model-baker/ApplyMaterialMappingTask.cpp | 57 ----------------- .../model-baker/src/model-baker/Baker.cpp | 23 +++---- libraries/model-baker/src/model-baker/Baker.h | 3 + .../model-baker/ParseMaterialMappingTask.cpp | 63 +++++++++++++++++++ ...ppingTask.h => ParseMaterialMappingTask.h} | 14 +++-- .../src/model-networking/ModelCache.cpp | 3 + .../src/model-networking/ModelCache.h | 2 + libraries/networking/src/ResourceCache.h | 2 +- .../render-utils/src/CauterizedModel.cpp | 1 + libraries/render-utils/src/Model.cpp | 50 ++++++++++++++- libraries/render-utils/src/Model.h | 3 + 13 files changed, 146 insertions(+), 79 deletions(-) delete mode 100644 libraries/model-baker/src/model-baker/ApplyMaterialMappingTask.cpp create mode 100644 libraries/model-baker/src/model-baker/ParseMaterialMappingTask.cpp rename libraries/model-baker/src/model-baker/{ApplyMaterialMappingTask.h => ParseMaterialMappingTask.h} (62%) diff --git a/libraries/material-networking/CMakeLists.txt b/libraries/material-networking/CMakeLists.txt index 4ade61230a..2bf8ea213d 100644 --- a/libraries/material-networking/CMakeLists.txt +++ b/libraries/material-networking/CMakeLists.txt @@ -1,5 +1,5 @@ set(TARGET_NAME material-networking) setup_hifi_library() -link_hifi_libraries(shared shaders networking graphics fbx ktx image gl) +link_hifi_libraries(shared shaders networking graphics ktx image gl) include_hifi_library_headers(gpu) include_hifi_library_headers(hfm) \ No newline at end of file diff --git a/libraries/material-networking/src/material-networking/MaterialCache.h b/libraries/material-networking/src/material-networking/MaterialCache.h index 4e6805ca39..d327aedb22 100644 --- a/libraries/material-networking/src/material-networking/MaterialCache.h +++ b/libraries/material-networking/src/material-networking/MaterialCache.h @@ -71,6 +71,7 @@ private: class NetworkMaterialResource : public Resource { public: + NetworkMaterialResource() : Resource() {} NetworkMaterialResource(const QUrl& url); QString getType() const override { return "NetworkMaterial"; } @@ -100,6 +101,7 @@ private: }; using NetworkMaterialResourcePointer = QSharedPointer; +using MaterialMapping = std::vector>; class MaterialCache : public ResourceCache { public: diff --git a/libraries/model-baker/src/model-baker/ApplyMaterialMappingTask.cpp b/libraries/model-baker/src/model-baker/ApplyMaterialMappingTask.cpp deleted file mode 100644 index 37ea184360..0000000000 --- a/libraries/model-baker/src/model-baker/ApplyMaterialMappingTask.cpp +++ /dev/null @@ -1,57 +0,0 @@ -// -// Created by Sam Gondelman on 2/7/2019 -// Copyright 2019 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "ApplyMaterialMappingTask.h" - -#include "ModelBakerLogging.h" - -#include - -void ApplyMaterialMappingTask::run(const baker::BakeContextPointer& context, const Input& input, Output& output) { - const auto& materialsIn = input.get0(); - const auto& mapping = input.get1(); - - auto materialsOut = materialsIn; - - auto mappingIter = mapping.find("materialMap"); - if (mappingIter != mapping.end()) { - QByteArray materialMapValue = mappingIter.value().toByteArray(); - QJsonObject materialMap = QJsonDocument::fromJson(materialMapValue).object(); - if (materialMap.isEmpty()) { - qCDebug(model_baker) << "Material Map found but did not produce valid JSON:" << materialMapValue; - } else { - for (auto& material : materialsOut) { - auto materialMapIter = materialMap.find(material.name); - if (materialMapIter != materialMap.end()) { - QJsonObject materialOptions = materialMapIter.value().toObject(); - qCDebug(model_baker) << "Mapping material:" << material.name << " with HFMaterial: " << materialOptions; - - { - auto scatteringIter = materialOptions.find("scattering"); - if (scatteringIter != materialOptions.end()) { - float scattering = (float)scatteringIter.value().toDouble(); - material._material->setScattering(scattering); - } - } - - { - auto scatteringMapIter = materialOptions.find("scatteringMap"); - if (scatteringMapIter != materialOptions.end()) { - QByteArray scatteringMap = scatteringMapIter.value().toVariant().toByteArray(); - material.scatteringTexture = HFMTexture(); - material.scatteringTexture.name = material.name + ".scatteringMap"; - material.scatteringTexture.filename = scatteringMap; - } - } - } - } - } - } - - output = materialsOut; -} diff --git a/libraries/model-baker/src/model-baker/Baker.cpp b/libraries/model-baker/src/model-baker/Baker.cpp index 981d799f12..037cfb7912 100644 --- a/libraries/model-baker/src/model-baker/Baker.cpp +++ b/libraries/model-baker/src/model-baker/Baker.cpp @@ -20,7 +20,6 @@ #include "CalculateBlendshapeNormalsTask.h" #include "CalculateBlendshapeTangentsTask.h" #include "PrepareJointsTask.h" -#include "ApplyMaterialMappingTask.h" namespace baker { @@ -102,7 +101,7 @@ namespace baker { class BuildModelTask { public: - using Input = VaryingSet6, std::vector, QMap, QHash, QHash>; + using Input = VaryingSet5, std::vector, QMap, QHash>; using Output = hfm::Model::Pointer; using JobModel = Job::ModelIO; @@ -112,7 +111,6 @@ namespace baker { hfmModelOut->joints = QVector::fromStdVector(input.get2()); hfmModelOut->jointRotationOffsets = input.get3(); hfmModelOut->jointIndices = input.get4(); - hfmModelOut->materials = input.get5(); output = hfmModelOut; } }; @@ -120,9 +118,9 @@ namespace baker { class BakerEngineBuilder { public: using Input = VaryingSet2; - using Output = hfm::Model::Pointer; + using Output = VaryingSet2; using JobModel = Task::ModelIO; - void build(JobModel& model, const Varying& input, Varying& hfmModelOut) { + void build(JobModel& model, const Varying& input, Varying& output) { const auto& hfmModelIn = input.getN(0); const auto& mapping = input.getN(1); @@ -156,17 +154,19 @@ namespace baker { const auto jointRotationOffsets = jointInfoOut.getN(1); const auto jointIndices = jointInfoOut.getN(2); - // Apply material mapping - const auto materialMappingInputs = ApplyMaterialMappingTask::Input(materials, mapping).asVarying(); - const auto materialsOut = model.addJob("ApplyMaterialMapping", materialMappingInputs); + // Parse material mapping + const auto materialMappingInputs = ParseMaterialMappingTask::Input(materials, mapping).asVarying(); + const auto materialMapping = model.addJob("ParseMaterialMapping", materialMappingInputs); // Combine the outputs into a new hfm::Model const auto buildBlendshapesInputs = BuildBlendshapesTask::Input(blendshapesPerMeshIn, normalsPerBlendshapePerMesh, tangentsPerBlendshapePerMesh).asVarying(); const auto blendshapesPerMeshOut = model.addJob("BuildBlendshapes", buildBlendshapesInputs); const auto buildMeshesInputs = BuildMeshesTask::Input(meshesIn, graphicsMeshes, normalsPerMesh, tangentsPerMesh, blendshapesPerMeshOut).asVarying(); const auto meshesOut = model.addJob("BuildMeshes", buildMeshesInputs); - const auto buildModelInputs = BuildModelTask::Input(hfmModelIn, meshesOut, jointsOut, jointRotationOffsets, jointIndices, materialsOut).asVarying(); - hfmModelOut = model.addJob("BuildModel", buildModelInputs); + const auto buildModelInputs = BuildModelTask::Input(hfmModelIn, meshesOut, jointsOut, jointRotationOffsets, jointIndices).asVarying(); + const auto hfmModelOut = model.addJob("BuildModel", buildModelInputs); + + output = Output(hfmModelOut, materialMapping); } }; @@ -178,7 +178,8 @@ namespace baker { void Baker::run() { _engine->run(); - hfmModel = _engine->getOutput().get(); + hfmModel = _engine->getOutput().get().get0(); + materialMapping = _engine->getOutput().get().get1(); } }; diff --git a/libraries/model-baker/src/model-baker/Baker.h b/libraries/model-baker/src/model-baker/Baker.h index 41989d73df..542be0b559 100644 --- a/libraries/model-baker/src/model-baker/Baker.h +++ b/libraries/model-baker/src/model-baker/Baker.h @@ -18,6 +18,8 @@ #include "Engine.h" +#include "ParseMaterialMappingTask.h" + namespace baker { class Baker { public: @@ -27,6 +29,7 @@ namespace baker { // Outputs, available after run() is called hfm::Model::Pointer hfmModel; + MaterialMapping materialMapping; protected: EnginePointer _engine; diff --git a/libraries/model-baker/src/model-baker/ParseMaterialMappingTask.cpp b/libraries/model-baker/src/model-baker/ParseMaterialMappingTask.cpp new file mode 100644 index 0000000000..7a4acb595a --- /dev/null +++ b/libraries/model-baker/src/model-baker/ParseMaterialMappingTask.cpp @@ -0,0 +1,63 @@ +// +// Created by Sam Gondelman on 2/7/2019 +// Copyright 2019 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "ParseMaterialMappingTask.h" + +#include "ModelBakerLogging.h" + +void ParseMaterialMappingTask::run(const baker::BakeContextPointer& context, const Input& input, Output& output) { + const auto& materialsIn = input.get0(); + const auto& mapping = input.get1(); + + MaterialMapping materialMapping; + + auto mappingIter = mapping.find("materialMap"); + if (mappingIter != mapping.end()) { + QByteArray materialMapValue = mappingIter.value().toByteArray(); + QJsonObject materialMap = QJsonDocument::fromJson(materialMapValue).object(); + if (materialMap.isEmpty()) { + qCDebug(model_baker) << "Material Map found but did not produce valid JSON:" << materialMapValue; + } else { + auto mappingKeys = materialMap.keys(); + for (auto mapping : mappingKeys) { + auto mappingValue = materialMap[mapping].toObject(); + + // Old subsurface scattering mapping + { + auto scatteringIter = mappingValue.find("scattering"); + auto scatteringMapIter = mappingValue.find("scatteringMap"); + if (scatteringIter != mappingValue.end() || scatteringMapIter != mappingValue.end()) { + std::shared_ptr material = std::make_shared(); + + if (scatteringIter != mappingValue.end()) { + float scattering = (float)scatteringIter.value().toDouble(); + material->setScattering(scattering); + } + + if (scatteringMapIter != mappingValue.end()) { + QString scatteringMap = scatteringMapIter.value().toString(); + material->setScatteringMap(scatteringMap); + } + + material->setDefaultFallthrough(true); + + NetworkMaterialResourcePointer materialResource = NetworkMaterialResourcePointer(new NetworkMaterialResource(), [](NetworkMaterialResource* ptr) { ptr->deleteLater(); }); + materialResource->moveToThread(qApp->thread()); + materialResource->parsedMaterials.names.push_back("scattering"); + materialResource->parsedMaterials.networkMaterials["scattering"] = material; + + materialMapping.push_back(std::pair("mat::" + mapping.toStdString(), materialResource)); + continue; + } + } + } + } + } + + output = materialMapping; +} diff --git a/libraries/model-baker/src/model-baker/ApplyMaterialMappingTask.h b/libraries/model-baker/src/model-baker/ParseMaterialMappingTask.h similarity index 62% rename from libraries/model-baker/src/model-baker/ApplyMaterialMappingTask.h rename to libraries/model-baker/src/model-baker/ParseMaterialMappingTask.h index 271c80fe67..3e48c00acf 100644 --- a/libraries/model-baker/src/model-baker/ApplyMaterialMappingTask.h +++ b/libraries/model-baker/src/model-baker/ParseMaterialMappingTask.h @@ -6,8 +6,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#ifndef hifi_ApplyMaterialMappingTask_h -#define hifi_ApplyMaterialMappingTask_h +#ifndef hifi_ParseMaterialMappingTask_h +#define hifi_ParseMaterialMappingTask_h #include @@ -15,13 +15,15 @@ #include "Engine.h" -class ApplyMaterialMappingTask { +#include + +class ParseMaterialMappingTask { public: using Input = baker::VaryingSet2, QVariantHash>; - using Output = QHash; - using JobModel = baker::Job::ModelIO; + using Output = MaterialMapping; + using JobModel = baker::Job::ModelIO; void run(const baker::BakeContextPointer& context, const Input& input, Output& output); }; -#endif // hifi_ApplyMaterialMappingTask_h \ No newline at end of file +#endif // hifi_ParseMaterialMappingTask_h \ No newline at end of file diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 20ca97a681..0ed518937d 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -174,6 +174,7 @@ void GeometryMappingResource::downloadFinished(const QByteArray& data) { void GeometryMappingResource::onGeometryMappingLoaded(bool success) { if (success && _geometryResource) { _hfmModel = _geometryResource->_hfmModel; + _materialMapping = _geometryResource->_materialMapping; _meshParts = _geometryResource->_meshParts; _meshes = _geometryResource->_meshes; _materials = _geometryResource->_materials; @@ -341,6 +342,7 @@ void GeometryDefinitionResource::setGeometryDefinition(HFMModel::Pointer hfmMode // Assume ownership of the processed HFMModel _hfmModel = modelBaker.hfmModel; + _materialMapping = modelBaker.materialMapping; // Copy materials QHash materialIDAtlas; @@ -437,6 +439,7 @@ const QVariantMap Geometry::getTextures() const { // FIXME: The materials should only be copied when modified, but the Model currently caches the original Geometry::Geometry(const Geometry& geometry) { _hfmModel = geometry._hfmModel; + _materialMapping = geometry._materialMapping; _meshes = geometry._meshes; _meshParts = geometry._meshParts; diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index 59fd6a4b74..4cd7048dca 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -45,6 +45,7 @@ public: bool isHFMModelLoaded() const { return (bool)_hfmModel; } const HFMModel& getHFMModel() const { return *_hfmModel; } + const MaterialMapping& getMaterialMapping() const { return _materialMapping; } const GeometryMeshes& getMeshes() const { return *_meshes; } const std::shared_ptr getShapeMaterial(int shapeID) const; @@ -60,6 +61,7 @@ protected: // Shared across all geometries, constant throughout lifetime std::shared_ptr _hfmModel; + MaterialMapping _materialMapping; std::shared_ptr _meshes; std::shared_ptr _meshParts; diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index 740bdadc48..4693bc0613 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -359,7 +359,7 @@ class Resource : public QObject { Q_OBJECT public: - + Resource() : QObject(), _loaded(true) {} Resource(const Resource& other); Resource(const QUrl& url); virtual ~Resource(); diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp index 81a81c5602..691dae0339 100644 --- a/libraries/render-utils/src/CauterizedModel.cpp +++ b/libraries/render-utils/src/CauterizedModel.cpp @@ -97,6 +97,7 @@ void CauterizedModel::createRenderItemSet() { } } _blendshapeOffsetsInitialized = true; + applyMaterialMapping(); } else { Model::createRenderItemSet(); } diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 0206bd6963..722f12eceb 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1465,6 +1465,7 @@ void Model::createRenderItemSet() { } } _blendshapeOffsetsInitialized = true; + applyMaterialMapping(); } bool Model::isRenderable() const { @@ -1519,17 +1520,60 @@ std::set Model::getMeshIDsFromMaterialID(QString parentMaterialNam return toReturn; } +void Model::applyMaterialMapping() { + auto renderItemsKey = _renderItemKeyGlobalFlags; + PrimitiveMode primitiveMode = getPrimitiveMode(); + bool useDualQuaternionSkinning = _useDualQuaternionSkinning; + + render::Transaction transaction; + std::unordered_map priorityMap; + auto& materialMapping = getMaterialMapping(); + qDebug() << "boop" << materialMapping.size(); + for (auto& mapping : materialMapping) { + std::set shapeIDs = getMeshIDsFromMaterialID(QString(mapping.first.c_str())); + + qDebug() << "boop2" << mapping.first.c_str() << shapeIDs.size(); + if (shapeIDs.size() == 0) { + continue; + } + + auto networkMaterialResource = mapping.second; + qDebug() << (bool)networkMaterialResource; + if (networkMaterialResource && networkMaterialResource->isLoaded() && networkMaterialResource->parsedMaterials.names.size() > 0) { + auto networkMaterial = networkMaterialResource->parsedMaterials.networkMaterials[networkMaterialResource->parsedMaterials.names[0]]; + for (auto shapeID : shapeIDs) { + if (shapeID < _modelMeshRenderItemIDs.size()) { + auto itemID = _modelMeshRenderItemIDs[shapeID]; + auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex; + bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex); + graphics::MaterialLayer material = graphics::MaterialLayer(networkMaterial, ++priorityMap[shapeID]); + transaction.updateItem(itemID, [material, renderItemsKey, + invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning](ModelMeshPartPayload& data) { + data.addMaterial(material); + // if the material changed, we might need to update our item key or shape key + data.updateKey(renderItemsKey); + data.setShapeKey(invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning); + }); + } + } + } + } + AbstractViewStateInterface::instance()->getMain3DScene()->enqueueTransaction(transaction); +} + void Model::addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName) { std::set shapeIDs = getMeshIDsFromMaterialID(QString(parentMaterialName.c_str())); + + auto renderItemsKey = _renderItemKeyGlobalFlags; + PrimitiveMode primitiveMode = getPrimitiveMode(); + bool useDualQuaternionSkinning = _useDualQuaternionSkinning; + render::Transaction transaction; for (auto shapeID : shapeIDs) { if (shapeID < _modelMeshRenderItemIDs.size()) { auto itemID = _modelMeshRenderItemIDs[shapeID]; - auto renderItemsKey = _renderItemKeyGlobalFlags; - PrimitiveMode primitiveMode = getPrimitiveMode(); auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex; bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex); - bool useDualQuaternionSkinning = _useDualQuaternionSkinning; transaction.updateItem(itemID, [material, renderItemsKey, invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning](ModelMeshPartPayload& data) { data.addMaterial(material); diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index aadfca78ba..672a4c61eb 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -183,6 +183,7 @@ public: /// Provided as a convenience, will crash if !isLoaded() // And so that getHFMModel() isn't chained everywhere const HFMModel& getHFMModel() const { assert(isLoaded()); return _renderGeometry->getHFMModel(); } + const MaterialMapping& getMaterialMapping() const { assert(isLoaded()); return _renderGeometry->getMaterialMapping(); } bool isActive() const { return isLoaded(); } @@ -373,6 +374,8 @@ signals: protected: + void applyMaterialMapping(); + void setBlendshapeCoefficients(const QVector& coefficients) { _blendshapeCoefficients = coefficients; } const QVector& getBlendshapeCoefficients() const { return _blendshapeCoefficients; }