diff --git a/assignment-client/CMakeLists.txt b/assignment-client/CMakeLists.txt index f28dc90b7d..b7afc3ed9e 100644 --- a/assignment-client/CMakeLists.txt +++ b/assignment-client/CMakeLists.txt @@ -14,7 +14,7 @@ link_hifi_libraries( audio avatars octree gpu graphics shaders fbx hfm entities networking animation recording shared script-engine embedded-webserver controllers physics plugins midi image - model-networking ktx shaders + material-networking model-networking ktx shaders ) add_dependencies(${TARGET_NAME} oven) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 74e25662c7..bb8ebbd2a0 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -205,8 +205,8 @@ endif() # link required hifi libraries link_hifi_libraries( shared workload task octree ktx gpu gl procedural graphics graphics-scripting render - pointers - recording hfm fbx networking model-networking model-baker entities avatars trackers + pointers recording hfm fbx networking material-networking + model-networking model-baker entities avatars trackers audio audio-client animation script-engine physics render-utils entities-renderer avatars-renderer ui qml auto-updater midi controllers plugins image trackers diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index bbe4d70ab6..bdaac7e924 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -102,7 +102,7 @@ #include #include #include -#include +#include #include #include #include @@ -154,7 +154,7 @@ #include #include #include -#include +#include #include "recording/ClipCache.h" #include "AudioClient.h" diff --git a/libraries/animation/src/AnimationCache.cpp b/libraries/animation/src/AnimationCache.cpp index 4e988334f9..237fd3da02 100644 --- a/libraries/animation/src/AnimationCache.cpp +++ b/libraries/animation/src/AnimationCache.cpp @@ -41,7 +41,7 @@ QSharedPointer AnimationCache::createResource(const QUrl& url) { } QSharedPointer AnimationCache::createResourceCopy(const QSharedPointer& resource) { - return QSharedPointer(new Animation(*resource.staticCast().data()), &Resource::deleter); + return QSharedPointer(new Animation(*resource.staticCast()), &Resource::deleter); } AnimationReader::AnimationReader(const QUrl& url, const QByteArray& data) : diff --git a/libraries/audio/src/SoundCache.cpp b/libraries/audio/src/SoundCache.cpp index 343de46e9a..c36897c766 100644 --- a/libraries/audio/src/SoundCache.cpp +++ b/libraries/audio/src/SoundCache.cpp @@ -40,5 +40,5 @@ QSharedPointer SoundCache::createResource(const QUrl& url) { } QSharedPointer SoundCache::createResourceCopy(const QSharedPointer& resource) { - return QSharedPointer(new Sound(*resource.staticCast().data()), &Resource::deleter); + return QSharedPointer(new Sound(*resource.staticCast()), &Resource::deleter); } \ No newline at end of file diff --git a/libraries/avatars-renderer/CMakeLists.txt b/libraries/avatars-renderer/CMakeLists.txt index 06a3804ece..de1ac1a7c2 100644 --- a/libraries/avatars-renderer/CMakeLists.txt +++ b/libraries/avatars-renderer/CMakeLists.txt @@ -1,6 +1,6 @@ set(TARGET_NAME avatars-renderer) setup_hifi_library(Network Script) -link_hifi_libraries(shared shaders gpu graphics animation model-networking script-engine render render-utils image trackers entities-renderer) +link_hifi_libraries(shared shaders gpu graphics animation material-networking model-networking script-engine render render-utils image trackers entities-renderer) include_hifi_library_headers(avatars) include_hifi_library_headers(networking) include_hifi_library_headers(hfm) diff --git a/libraries/display-plugins/CMakeLists.txt b/libraries/display-plugins/CMakeLists.txt index 8e966ed9ea..ad6503b22d 100644 --- a/libraries/display-plugins/CMakeLists.txt +++ b/libraries/display-plugins/CMakeLists.txt @@ -2,6 +2,7 @@ set(TARGET_NAME display-plugins) setup_hifi_library(Gui) link_hifi_libraries(shared shaders plugins ui-plugins gl ui render-utils ${PLATFORM_GL_BACKEND}) include_hifi_library_headers(gpu) +include_hifi_library_headers(material-networking) include_hifi_library_headers(model-networking) include_hifi_library_headers(networking) include_hifi_library_headers(graphics) diff --git a/libraries/entities-renderer/CMakeLists.txt b/libraries/entities-renderer/CMakeLists.txt index b08856e8a8..e1896cf674 100644 --- a/libraries/entities-renderer/CMakeLists.txt +++ b/libraries/entities-renderer/CMakeLists.txt @@ -1,6 +1,6 @@ set(TARGET_NAME entities-renderer) setup_hifi_library(Network Script) -link_hifi_libraries(shared workload gpu shaders procedural graphics model-networking script-engine render render-utils image qml ui pointers) +link_hifi_libraries(shared workload gpu shaders procedural graphics material-networking model-networking script-engine render render-utils image qml ui pointers) include_hifi_library_headers(networking) include_hifi_library_headers(gl) include_hifi_library_headers(ktx) diff --git a/libraries/entities/CMakeLists.txt b/libraries/entities/CMakeLists.txt index e359c7132f..56adb59914 100644 --- a/libraries/entities/CMakeLists.txt +++ b/libraries/entities/CMakeLists.txt @@ -6,4 +6,4 @@ include_hifi_library_headers(fbx) include_hifi_library_headers(gpu) include_hifi_library_headers(image) include_hifi_library_headers(ktx) -link_hifi_libraries(shared shaders networking octree avatars graphics model-networking) +link_hifi_libraries(shared shaders networking octree avatars graphics material-networking model-networking) diff --git a/libraries/entities/src/MaterialEntityItem.h b/libraries/entities/src/MaterialEntityItem.h index ba142d7719..069c71c1d6 100644 --- a/libraries/entities/src/MaterialEntityItem.h +++ b/libraries/entities/src/MaterialEntityItem.h @@ -13,7 +13,7 @@ #include "MaterialMappingMode.h" #include -#include +#include class MaterialEntityItem : public EntityItem { using Pointer = std::shared_ptr; diff --git a/libraries/fbx/src/FBXSerializer.cpp b/libraries/fbx/src/FBXSerializer.cpp index 207ee2982d..9e7f422b40 100644 --- a/libraries/fbx/src/FBXSerializer.cpp +++ b/libraries/fbx/src/FBXSerializer.cpp @@ -1326,7 +1326,7 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr hfmModel.meshExtents.reset(); // Create the Material Library - consolidateHFMMaterials(mapping); + consolidateHFMMaterials(); // We can't allow the scaling of a given image to different sizes, because the hash used for the KTX cache is based on the original image // Allowing scaling of the same image to different sizes would cause different KTX files to target the same cache key diff --git a/libraries/fbx/src/FBXSerializer.h b/libraries/fbx/src/FBXSerializer.h index b95bb729e7..379b1ac743 100644 --- a/libraries/fbx/src/FBXSerializer.h +++ b/libraries/fbx/src/FBXSerializer.h @@ -153,7 +153,7 @@ public: QHash _hfmMaterials; QHash _materialParams; - void consolidateHFMMaterials(const QVariantHash& mapping); + void consolidateHFMMaterials(); bool _loadLightmaps { true }; float _lightmapOffset { 0.0f }; diff --git a/libraries/fbx/src/FBXSerializer_Material.cpp b/libraries/fbx/src/FBXSerializer_Material.cpp index 9caf713e75..b47329e483 100644 --- a/libraries/fbx/src/FBXSerializer_Material.cpp +++ b/libraries/fbx/src/FBXSerializer_Material.cpp @@ -75,15 +75,7 @@ HFMTexture FBXSerializer::getTexture(const QString& textureID, const QString& ma return texture; } -void FBXSerializer::consolidateHFMMaterials(const QVariantHash& mapping) { - QJsonObject materialMap; - if (mapping.contains("materialMap")) { - QByteArray materialMapValue = mapping.value("materialMap").toByteArray(); - materialMap = QJsonDocument::fromJson(materialMapValue).object(); - if (materialMap.isEmpty()) { - qCDebug(modelformat) << "fbx Material Map found but did not produce valid JSON:" << materialMapValue; - } - } +void FBXSerializer::consolidateHFMMaterials() { for (QHash::iterator it = _hfmMaterials.begin(); it != _hfmMaterials.end(); it++) { HFMMaterial& material = (*it); @@ -266,23 +258,6 @@ void FBXSerializer::consolidateHFMMaterials(const QVariantHash& mapping) { } qCDebug(modelformat) << " fbx material Name:" << material.name; - if (materialMap.contains(material.name)) { - QJsonObject materialOptions = materialMap.value(material.name).toObject(); - qCDebug(modelformat) << "Mapping fbx material:" << material.name << " with HifiMaterial: " << materialOptions; - - if (materialOptions.contains("scattering")) { - float scattering = (float) materialOptions.value("scattering").toDouble(); - material._material->setScattering(scattering); - } - - if (materialOptions.contains("scatteringMap")) { - QByteArray scatteringMap = materialOptions.value("scatteringMap").toVariant().toByteArray(); - material.scatteringTexture = HFMTexture(); - material.scatteringTexture.name = material.name + ".scatteringMap"; - material.scatteringTexture.filename = scatteringMap; - } - } - if (material.opacity <= 0.0f) { material._material->setOpacity(1.0f); } else { diff --git a/libraries/graphics-scripting/CMakeLists.txt b/libraries/graphics-scripting/CMakeLists.txt index 0f59fb41f8..9bb34adda1 100644 --- a/libraries/graphics-scripting/CMakeLists.txt +++ b/libraries/graphics-scripting/CMakeLists.txt @@ -1,4 +1,4 @@ set(TARGET_NAME graphics-scripting) setup_hifi_library() -link_hifi_libraries(shared networking graphics fbx image model-networking script-engine) +link_hifi_libraries(shared networking graphics fbx image material-networking model-networking script-engine) include_hifi_library_headers(gpu) diff --git a/libraries/material-networking/CMakeLists.txt b/libraries/material-networking/CMakeLists.txt new file mode 100644 index 0000000000..2bf8ea213d --- /dev/null +++ b/libraries/material-networking/CMakeLists.txt @@ -0,0 +1,5 @@ +set(TARGET_NAME material-networking) +setup_hifi_library() +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/model-networking/src/model-networking/KTXCache.cpp b/libraries/material-networking/src/material-networking/KTXCache.cpp similarity index 100% rename from libraries/model-networking/src/model-networking/KTXCache.cpp rename to libraries/material-networking/src/material-networking/KTXCache.cpp diff --git a/libraries/model-networking/src/model-networking/KTXCache.h b/libraries/material-networking/src/material-networking/KTXCache.h similarity index 100% rename from libraries/model-networking/src/model-networking/KTXCache.h rename to libraries/material-networking/src/material-networking/KTXCache.h diff --git a/libraries/model-networking/src/model-networking/MaterialCache.cpp b/libraries/material-networking/src/material-networking/MaterialCache.cpp similarity index 63% rename from libraries/model-networking/src/model-networking/MaterialCache.cpp rename to libraries/material-networking/src/material-networking/MaterialCache.cpp index aaa9767397..6561fc697e 100644 --- a/libraries/model-networking/src/model-networking/MaterialCache.cpp +++ b/libraries/material-networking/src/material-networking/MaterialCache.cpp @@ -425,5 +425,311 @@ QSharedPointer MaterialCache::createResource(const QUrl& url) { } QSharedPointer MaterialCache::createResourceCopy(const QSharedPointer& resource) { - return QSharedPointer(new NetworkMaterialResource(*resource.staticCast().data()), &Resource::deleter); + return QSharedPointer(new NetworkMaterialResource(*resource.staticCast()), &Resource::deleter); +} + +NetworkMaterial::NetworkMaterial(const NetworkMaterial& m) : + Material(m), + _textures(m._textures), + _albedoTransform(m._albedoTransform), + _lightmapTransform(m._lightmapTransform), + _lightmapParams(m._lightmapParams), + _isOriginal(m._isOriginal) +{} + +const QString NetworkMaterial::NO_TEXTURE = QString(); + +const QString& NetworkMaterial::getTextureName(MapChannel channel) { + if (_textures[channel].texture) { + return _textures[channel].name; + } + return NO_TEXTURE; +} + +QUrl NetworkMaterial::getTextureUrl(const QUrl& baseUrl, const HFMTexture& texture) { + if (texture.content.isEmpty()) { + // External file: search relative to the baseUrl, in case filename is relative + return baseUrl.resolved(QUrl(texture.filename)); + } else { + // Inlined file: cache under the fbx file to avoid namespace clashes + // NOTE: We cannot resolve the path because filename may be an absolute path + assert(texture.filename.size() > 0); + auto baseUrlStripped = baseUrl.toDisplayString(QUrl::RemoveFragment | QUrl::RemoveQuery | QUrl::RemoveUserInfo); + if (texture.filename.at(0) == '/') { + return baseUrlStripped + texture.filename; + } else { + return baseUrlStripped + '/' + texture.filename; + } + } +} + +graphics::TextureMapPointer NetworkMaterial::fetchTextureMap(const QUrl& baseUrl, const HFMTexture& hfmTexture, + image::TextureUsage::Type type, MapChannel channel) { + + if (baseUrl.isEmpty()) { + return nullptr; + } + + const auto url = getTextureUrl(baseUrl, hfmTexture); + const auto texture = DependencyManager::get()->getTexture(url, type, hfmTexture.content, hfmTexture.maxNumPixels, hfmTexture.sourceChannel); + _textures[channel] = Texture { hfmTexture.name, texture }; + + auto map = std::make_shared(); + if (texture) { + map->setTextureSource(texture->_textureSource); + } + map->setTextureTransform(hfmTexture.transform); + + return map; +} + +graphics::TextureMapPointer NetworkMaterial::fetchTextureMap(const QUrl& url, image::TextureUsage::Type type, MapChannel channel) { + auto textureCache = DependencyManager::get(); + if (textureCache && !url.isEmpty()) { + auto texture = textureCache->getTexture(url, type); + _textures[channel].texture = texture; + + auto map = std::make_shared(); + if (texture) { + map->setTextureSource(texture->_textureSource); + } + + return map; + } + return nullptr; +} + +void NetworkMaterial::setAlbedoMap(const QUrl& url, bool useAlphaChannel) { + auto map = fetchTextureMap(url, image::TextureUsage::ALBEDO_TEXTURE, MapChannel::ALBEDO_MAP); + if (map) { + map->setUseAlphaChannel(useAlphaChannel); + setTextureMap(MapChannel::ALBEDO_MAP, map); + } +} + +void NetworkMaterial::setNormalMap(const QUrl& url, bool isBumpmap) { + auto map = fetchTextureMap(url, isBumpmap ? image::TextureUsage::BUMP_TEXTURE : image::TextureUsage::NORMAL_TEXTURE, MapChannel::NORMAL_MAP); + if (map) { + setTextureMap(MapChannel::NORMAL_MAP, map); + } +} + +void NetworkMaterial::setRoughnessMap(const QUrl& url, bool isGloss) { + auto map = fetchTextureMap(url, isGloss ? image::TextureUsage::GLOSS_TEXTURE : image::TextureUsage::ROUGHNESS_TEXTURE, MapChannel::ROUGHNESS_MAP); + if (map) { + setTextureMap(MapChannel::ROUGHNESS_MAP, map); + } +} + +void NetworkMaterial::setMetallicMap(const QUrl& url, bool isSpecular) { + auto map = fetchTextureMap(url, isSpecular ? image::TextureUsage::SPECULAR_TEXTURE : image::TextureUsage::METALLIC_TEXTURE, MapChannel::METALLIC_MAP); + if (map) { + setTextureMap(MapChannel::METALLIC_MAP, map); + } +} + +void NetworkMaterial::setOcclusionMap(const QUrl& url) { + auto map = fetchTextureMap(url, image::TextureUsage::OCCLUSION_TEXTURE, MapChannel::OCCLUSION_MAP); + if (map) { + setTextureMap(MapChannel::OCCLUSION_MAP, map); + } +} + +void NetworkMaterial::setEmissiveMap(const QUrl& url) { + auto map = fetchTextureMap(url, image::TextureUsage::EMISSIVE_TEXTURE, MapChannel::EMISSIVE_MAP); + if (map) { + setTextureMap(MapChannel::EMISSIVE_MAP, map); + } +} + +void NetworkMaterial::setScatteringMap(const QUrl& url) { + auto map = fetchTextureMap(url, image::TextureUsage::SCATTERING_TEXTURE, MapChannel::SCATTERING_MAP); + if (map) { + setTextureMap(MapChannel::SCATTERING_MAP, map); + } +} + +void NetworkMaterial::setLightmapMap(const QUrl& url) { + auto map = fetchTextureMap(url, image::TextureUsage::LIGHTMAP_TEXTURE, MapChannel::LIGHTMAP_MAP); + if (map) { + //map->setTextureTransform(_lightmapTransform); + //map->setLightmapOffsetScale(_lightmapParams.x, _lightmapParams.y); + setTextureMap(MapChannel::LIGHTMAP_MAP, map); + } +} + +NetworkMaterial::NetworkMaterial(const HFMMaterial& material, const QUrl& textureBaseUrl) : + graphics::Material(*material._material), + _textures(MapChannel::NUM_MAP_CHANNELS) +{ + _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.roughnessTexture.filename.isEmpty()) { + auto map = fetchTextureMap(textureBaseUrl, material.roughnessTexture, image::TextureUsage::ROUGHNESS_TEXTURE, MapChannel::ROUGHNESS_MAP); + setTextureMap(MapChannel::ROUGHNESS_MAP, map); + } else if (!material.glossTexture.filename.isEmpty()) { + auto map = fetchTextureMap(textureBaseUrl, material.glossTexture, image::TextureUsage::GLOSS_TEXTURE, MapChannel::ROUGHNESS_MAP); + setTextureMap(MapChannel::ROUGHNESS_MAP, map); + } + + if (!material.metallicTexture.filename.isEmpty()) { + auto map = fetchTextureMap(textureBaseUrl, material.metallicTexture, image::TextureUsage::METALLIC_TEXTURE, MapChannel::METALLIC_MAP); + setTextureMap(MapChannel::METALLIC_MAP, map); + } else if (!material.specularTexture.filename.isEmpty()) { + auto map = fetchTextureMap(textureBaseUrl, material.specularTexture, image::TextureUsage::SPECULAR_TEXTURE, MapChannel::METALLIC_MAP); + setTextureMap(MapChannel::METALLIC_MAP, map); + } + + if (!material.occlusionTexture.filename.isEmpty()) { + auto map = fetchTextureMap(textureBaseUrl, material.occlusionTexture, image::TextureUsage::OCCLUSION_TEXTURE, MapChannel::OCCLUSION_MAP); + if (map) { + map->setTextureTransform(material.occlusionTexture.transform); + } + setTextureMap(MapChannel::OCCLUSION_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.scatteringTexture.filename.isEmpty()) { + auto map = fetchTextureMap(textureBaseUrl, material.scatteringTexture, image::TextureUsage::SCATTERING_TEXTURE, MapChannel::SCATTERING_MAP); + setTextureMap(MapChannel::SCATTERING_MAP, map); + } + + if (!material.lightmapTexture.filename.isEmpty()) { + auto map = fetchTextureMap(textureBaseUrl, material.lightmapTexture, image::TextureUsage::LIGHTMAP_TEXTURE, MapChannel::LIGHTMAP_MAP); + if (map) { + _lightmapTransform = material.lightmapTexture.transform; + _lightmapParams = material.lightmapParams; + map->setTextureTransform(_lightmapTransform); + map->setLightmapOffsetScale(_lightmapParams.x, _lightmapParams.y); + } + setTextureMap(MapChannel::LIGHTMAP_MAP, map); + } +} + +void NetworkMaterial::setTextures(const QVariantMap& textureMap) { + _isOriginal = false; + + const auto& albedoName = getTextureName(MapChannel::ALBEDO_MAP); + const auto& normalName = getTextureName(MapChannel::NORMAL_MAP); + const auto& roughnessName = getTextureName(MapChannel::ROUGHNESS_MAP); + const auto& metallicName = getTextureName(MapChannel::METALLIC_MAP); + const auto& occlusionName = getTextureName(MapChannel::OCCLUSION_MAP); + const auto& emissiveName = getTextureName(MapChannel::EMISSIVE_MAP); + const auto& lightmapName = getTextureName(MapChannel::LIGHTMAP_MAP); + const auto& scatteringName = getTextureName(MapChannel::SCATTERING_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 (!roughnessName.isEmpty()) { + auto url = textureMap.contains(roughnessName) ? textureMap[roughnessName].toUrl() : QUrl(); + // FIXME: If passing a gloss map instead of a roughmap how do we know? + auto map = fetchTextureMap(url, image::TextureUsage::ROUGHNESS_TEXTURE, MapChannel::ROUGHNESS_MAP); + setTextureMap(MapChannel::ROUGHNESS_MAP, map); + } + + if (!metallicName.isEmpty()) { + auto url = textureMap.contains(metallicName) ? textureMap[metallicName].toUrl() : QUrl(); + // FIXME: If passing a specular map instead of a metallic how do we know? + auto map = fetchTextureMap(url, image::TextureUsage::METALLIC_TEXTURE, MapChannel::METALLIC_MAP); + setTextureMap(MapChannel::METALLIC_MAP, map); + } + + if (!occlusionName.isEmpty()) { + auto url = textureMap.contains(occlusionName) ? textureMap[occlusionName].toUrl() : QUrl(); + // FIXME: we need to handle the occlusion map transform here + auto map = fetchTextureMap(url, image::TextureUsage::OCCLUSION_TEXTURE, MapChannel::OCCLUSION_MAP); + setTextureMap(MapChannel::OCCLUSION_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 (!scatteringName.isEmpty()) { + auto url = textureMap.contains(scatteringName) ? textureMap[scatteringName].toUrl() : QUrl(); + auto map = fetchTextureMap(url, image::TextureUsage::SCATTERING_TEXTURE, MapChannel::SCATTERING_MAP); + setTextureMap(MapChannel::SCATTERING_MAP, map); + } + + if (!lightmapName.isEmpty()) { + auto url = textureMap.contains(lightmapName) ? textureMap[lightmapName].toUrl() : QUrl(); + auto map = fetchTextureMap(url, image::TextureUsage::LIGHTMAP_TEXTURE, MapChannel::LIGHTMAP_MAP); + if (map) { + map->setTextureTransform(_lightmapTransform); + map->setLightmapOffsetScale(_lightmapParams.x, _lightmapParams.y); + } + setTextureMap(MapChannel::LIGHTMAP_MAP, map); + } +} + +bool NetworkMaterial::isMissingTexture() { + for (auto& networkTexture : _textures) { + auto& texture = networkTexture.texture; + if (!texture) { + continue; + } + // Failed texture downloads need to be considered as 'loaded' + // or the object will never fade in + bool finished = texture->isFailed() || (texture->isLoaded() && texture->getGPUTexture() && texture->getGPUTexture()->isDefined()); + if (!finished) { + return true; + } + } + return false; +} + +void NetworkMaterial::checkResetOpacityMap() { + // If material textures are loaded, check the material translucency + // FIXME: This should not be done here. The opacity map should already be reset in Material::setTextureMap. + // However, currently that code can be called before the albedo map is defined, so resetOpacityMap will fail. + // Geometry::areTexturesLoaded() is called repeatedly until it returns true, so we do the check here for now + const auto& albedoTexture = _textures[NetworkMaterial::MapChannel::ALBEDO_MAP]; + if (albedoTexture.texture) { + resetOpacityMap(); + } } \ 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 new file mode 100644 index 0000000000..d327aedb22 --- /dev/null +++ b/libraries/material-networking/src/material-networking/MaterialCache.h @@ -0,0 +1,117 @@ +// +// Created by Sam Gondelman on 2/9/2018 +// Copyright 2018 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 +// +#ifndef hifi_MaterialCache_h +#define hifi_MaterialCache_h + +#include "glm/glm.hpp" + +#include +#include +#include + +#include "TextureCache.h" + +class NetworkMaterial : public graphics::Material { +public: + using MapChannel = graphics::Material::MapChannel; + + NetworkMaterial() : _textures(MapChannel::NUM_MAP_CHANNELS) {} + NetworkMaterial(const HFMMaterial& material, const QUrl& textureBaseUrl); + NetworkMaterial(const NetworkMaterial& material); + + void setAlbedoMap(const QUrl& url, bool useAlphaChannel); + void setNormalMap(const QUrl& url, bool isBumpmap); + void setRoughnessMap(const QUrl& url, bool isGloss); + void setMetallicMap(const QUrl& url, bool isSpecular); + void setOcclusionMap(const QUrl& url); + void setEmissiveMap(const QUrl& url); + void setScatteringMap(const QUrl& url); + void setLightmapMap(const QUrl& url); + + bool isMissingTexture(); + void checkResetOpacityMap(); + +protected: + friend class Geometry; + + class Texture { + public: + QString name; + NetworkTexturePointer texture; + }; + using Textures = std::vector; + + Textures _textures; + + static const QString NO_TEXTURE; + const QString& getTextureName(MapChannel channel); + + void setTextures(const QVariantMap& textureMap); + + const bool& isOriginal() const { return _isOriginal; } + +private: + // Helpers for the ctors + QUrl getTextureUrl(const QUrl& baseUrl, const HFMTexture& hfmTexture); + graphics::TextureMapPointer fetchTextureMap(const QUrl& baseUrl, const HFMTexture& hfmTexture, + image::TextureUsage::Type type, MapChannel channel); + graphics::TextureMapPointer fetchTextureMap(const QUrl& url, image::TextureUsage::Type type, MapChannel channel); + + Transform _albedoTransform; + Transform _lightmapTransform; + vec2 _lightmapParams; + + bool _isOriginal { true }; +}; + +class NetworkMaterialResource : public Resource { +public: + NetworkMaterialResource() : Resource() {} + NetworkMaterialResource(const QUrl& url); + + QString getType() const override { return "NetworkMaterial"; } + + virtual void downloadFinished(const QByteArray& data) override; + + typedef struct ParsedMaterials { + uint version { 1 }; + std::vector names; + std::unordered_map> networkMaterials; + + void reset() { + version = 1; + names.clear(); + networkMaterials.clear(); + } + + } ParsedMaterials; + + ParsedMaterials parsedMaterials; + + static ParsedMaterials parseJSONMaterials(const QJsonDocument& materialJSON, const QUrl& baseUrl); + static std::pair> parseJSONMaterial(const QJsonObject& materialJSON, const QUrl& baseUrl); + +private: + static bool parseJSONColor(const QJsonValue& array, glm::vec3& color, bool& isSRGB); +}; + +using NetworkMaterialResourcePointer = QSharedPointer; +using MaterialMapping = std::vector>; + +class MaterialCache : public ResourceCache { +public: + static MaterialCache& instance(); + + NetworkMaterialResourcePointer getMaterial(const QUrl& url); + +protected: + virtual QSharedPointer createResource(const QUrl& url) override; + QSharedPointer createResourceCopy(const QSharedPointer& resource) override; +}; + +#endif diff --git a/libraries/material-networking/src/material-networking/MaterialNetworkingLogging.cpp b/libraries/material-networking/src/material-networking/MaterialNetworkingLogging.cpp new file mode 100644 index 0000000000..9a99c21240 --- /dev/null +++ b/libraries/material-networking/src/material-networking/MaterialNetworkingLogging.cpp @@ -0,0 +1,11 @@ +// +// 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 "MaterialNetworkingLogging.h" + +Q_LOGGING_CATEGORY(materialnetworking, "hifi.gpu-material-network") diff --git a/libraries/material-networking/src/material-networking/MaterialNetworkingLogging.h b/libraries/material-networking/src/material-networking/MaterialNetworkingLogging.h new file mode 100644 index 0000000000..a3f220d027 --- /dev/null +++ b/libraries/material-networking/src/material-networking/MaterialNetworkingLogging.h @@ -0,0 +1,11 @@ +// +// 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 + +Q_DECLARE_LOGGING_CATEGORY(materialnetworking) diff --git a/libraries/model-networking/src/model-networking/ShaderCache.cpp b/libraries/material-networking/src/material-networking/ShaderCache.cpp similarity index 94% rename from libraries/model-networking/src/model-networking/ShaderCache.cpp rename to libraries/material-networking/src/material-networking/ShaderCache.cpp index 8d060c42f2..4c8d659315 100644 --- a/libraries/model-networking/src/model-networking/ShaderCache.cpp +++ b/libraries/material-networking/src/material-networking/ShaderCache.cpp @@ -29,5 +29,5 @@ QSharedPointer ShaderCache::createResource(const QUrl& url) { } QSharedPointer ShaderCache::createResourceCopy(const QSharedPointer& resource) { - return QSharedPointer(new NetworkShader(*resource.staticCast().data()), &Resource::deleter); + return QSharedPointer(new NetworkShader(*resource.staticCast()), &Resource::deleter); } diff --git a/libraries/model-networking/src/model-networking/ShaderCache.h b/libraries/material-networking/src/material-networking/ShaderCache.h similarity index 100% rename from libraries/model-networking/src/model-networking/ShaderCache.h rename to libraries/material-networking/src/material-networking/ShaderCache.h diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/material-networking/src/material-networking/TextureCache.cpp similarity index 98% rename from libraries/model-networking/src/model-networking/TextureCache.cpp rename to libraries/material-networking/src/material-networking/TextureCache.cpp index a268f4ad0a..ee3c88f02c 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/material-networking/src/material-networking/TextureCache.cpp @@ -44,7 +44,7 @@ #include #include "NetworkLogging.h" -#include "ModelNetworkingLogging.h" +#include "MaterialNetworkingLogging.h" #include "NetworkingConstants.h" #include #include @@ -198,16 +198,16 @@ public: namespace std { template <> struct hash { - size_t operator()(const QByteArray& a) const { - return qHash(a); + size_t operator()(const QByteArray& byteArray) const { + return qHash(byteArray); } }; template <> struct hash { - size_t operator()(const TextureExtra& a) const { + size_t operator()(const TextureExtra& textureExtra) const { size_t result = 0; - hash_combine(result, (int)a.type, a.content, a.maxNumPixels, (int)a.sourceChannel); + hash_combine(result, (int)textureExtra.type, textureExtra.content, textureExtra.maxNumPixels, (int)textureExtra.sourceChannel); return result; } }; @@ -329,15 +329,14 @@ QSharedPointer TextureCache::createResource(const QUrl& url) { } QSharedPointer TextureCache::createResourceCopy(const QSharedPointer& resource) { - return QSharedPointer(new NetworkTexture(*resource.staticCast().data()), &Resource::deleter); + return QSharedPointer(new NetworkTexture(*resource.staticCast()), &Resource::deleter); } int networkTexturePointerMetaTypeId = qRegisterMetaType>(); NetworkTexture::NetworkTexture(const QUrl& url, bool resourceTexture) : Resource(url), - Texture(), - _maxNumPixels(100) + Texture() { if (resourceTexture) { _textureSource = std::make_shared(url); @@ -955,7 +954,7 @@ void NetworkTexture::handleFinishedInitialLoad() { cache::FilePointer file; auto& ktxCache = textureCache->_ktxCache; if (!memKtx || !(file = ktxCache->writeFile(data, KTXCache::Metadata(filename, length)))) { - qCWarning(modelnetworking) << url << " failed to write cache file"; + qCWarning(materialnetworking) << url << " failed to write cache file"; QMetaObject::invokeMethod(resource.data(), "setImage", Q_ARG(gpu::TexturePointer, nullptr), Q_ARG(int, 0), @@ -1145,7 +1144,7 @@ void ImageReader::listSupportedImageFormats() { static std::once_flag once; std::call_once(once, []{ auto supportedFormats = QImageReader::supportedImageFormats(); - qCDebug(modelnetworking) << "List of supported Image formats:" << supportedFormats.join(", "); + qCDebug(materialnetworking) << "List of supported Image formats:" << supportedFormats.join(", "); }); } @@ -1194,7 +1193,7 @@ void ImageReader::read() { if (texture) { texture = textureCache->cacheTextureByHash(hash, texture); } else { - qCWarning(modelnetworking) << "Invalid cached KTX " << _url << " under hash " << hash.c_str() << ", recreating..."; + qCWarning(materialnetworking) << "Invalid cached KTX " << _url << " under hash " << hash.c_str() << ", recreating..."; } } } diff --git a/libraries/model-networking/src/model-networking/TextureCache.h b/libraries/material-networking/src/material-networking/TextureCache.h similarity index 100% rename from libraries/model-networking/src/model-networking/TextureCache.h rename to libraries/material-networking/src/material-networking/TextureCache.h diff --git a/libraries/model-networking/src/model-networking/TextureCacheScriptingInterface.cpp b/libraries/material-networking/src/material-networking/TextureCacheScriptingInterface.cpp similarity index 100% rename from libraries/model-networking/src/model-networking/TextureCacheScriptingInterface.cpp rename to libraries/material-networking/src/material-networking/TextureCacheScriptingInterface.cpp diff --git a/libraries/model-networking/src/model-networking/TextureCacheScriptingInterface.h b/libraries/material-networking/src/material-networking/TextureCacheScriptingInterface.h similarity index 100% rename from libraries/model-networking/src/model-networking/TextureCacheScriptingInterface.h rename to libraries/material-networking/src/material-networking/TextureCacheScriptingInterface.h diff --git a/libraries/model-baker/CMakeLists.txt b/libraries/model-baker/CMakeLists.txt index aabd6eba3a..22c240b487 100644 --- a/libraries/model-baker/CMakeLists.txt +++ b/libraries/model-baker/CMakeLists.txt @@ -1,6 +1,7 @@ set(TARGET_NAME model-baker) setup_hifi_library() -link_hifi_libraries(shared task gpu graphics hfm) - +link_hifi_libraries(shared shaders task gpu graphics hfm material-networking) +include_hifi_library_headers(networking) include_hifi_library_headers(image) +include_hifi_library_headers(ktx) \ No newline at end of file diff --git a/libraries/model-baker/src/model-baker/Baker.cpp b/libraries/model-baker/src/model-baker/Baker.cpp index 1c2a2f5c63..dfb18eef86 100644 --- a/libraries/model-baker/src/model-baker/Baker.cpp +++ b/libraries/model-baker/src/model-baker/Baker.cpp @@ -101,7 +101,7 @@ namespace baker { class BuildModelTask { public: - using Input = VaryingSet5, std::vector, QMap /*jointRotationOffsets*/, QHash /*jointIndices*/>; + using Input = VaryingSet5, std::vector, QMap, QHash>; using Output = hfm::Model::Pointer; using JobModel = Job::ModelIO; @@ -118,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); @@ -154,13 +154,18 @@ namespace baker { const auto jointRotationOffsets = jointInfoOut.getN(1); const auto jointIndices = jointInfoOut.getN(2); + // Parse material mapping + const auto materialMapping = model.addJob("ParseMaterialMapping", mapping); + // 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).asVarying(); - hfmModelOut = model.addJob("BuildModel", buildModelInputs); + const auto hfmModelOut = model.addJob("BuildModel", buildModelInputs); + + output = Output(hfmModelOut, materialMapping); } }; @@ -172,7 +177,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..7a923a3702 --- /dev/null +++ b/libraries/model-baker/src/model-baker/ParseMaterialMappingTask.cpp @@ -0,0 +1,76 @@ +// +// 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& mapping, Output& output) { + 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 mappingJSON = materialMap[mapping]; + if (mappingJSON.isObject()) { + auto mappingValue = mappingJSON.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; + } + } + + // Material JSON description + { + NetworkMaterialResourcePointer materialResource = NetworkMaterialResourcePointer(new NetworkMaterialResource(), [](NetworkMaterialResource* ptr) { ptr->deleteLater(); }); + materialResource->moveToThread(qApp->thread()); + // TODO: add baseURL to allow FSTs to reference relative files next to them + materialResource->parsedMaterials = NetworkMaterialResource::parseJSONMaterials(QJsonDocument(mappingValue), QUrl()); + materialMapping.push_back(std::pair(mapping.toStdString(), materialResource)); + } + + } else if (mappingJSON.isString()) { + auto mappingValue = mappingJSON.toString(); + materialMapping.push_back(std::pair(mapping.toStdString(), MaterialCache::instance().getMaterial(mappingValue))); + } + } + } + } + + output = materialMapping; +} diff --git a/libraries/model-baker/src/model-baker/ParseMaterialMappingTask.h b/libraries/model-baker/src/model-baker/ParseMaterialMappingTask.h new file mode 100644 index 0000000000..69e00b0324 --- /dev/null +++ b/libraries/model-baker/src/model-baker/ParseMaterialMappingTask.h @@ -0,0 +1,29 @@ +// +// 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 +// + +#ifndef hifi_ParseMaterialMappingTask_h +#define hifi_ParseMaterialMappingTask_h + +#include + +#include + +#include "Engine.h" + +#include + +class ParseMaterialMappingTask { +public: + using Input = QVariantHash; + using Output = MaterialMapping; + using JobModel = baker::Job::ModelIO; + + void run(const baker::BakeContextPointer& context, const Input& input, Output& output); +}; + +#endif // hifi_ParseMaterialMappingTask_h \ No newline at end of file diff --git a/libraries/model-networking/CMakeLists.txt b/libraries/model-networking/CMakeLists.txt index 6a7182cc33..e79d18f779 100644 --- a/libraries/model-networking/CMakeLists.txt +++ b/libraries/model-networking/CMakeLists.txt @@ -1,6 +1,8 @@ set(TARGET_NAME model-networking) setup_hifi_library() -link_hifi_libraries(shared shaders networking graphics fbx ktx image gl model-baker) -include_hifi_library_headers(gpu) +link_hifi_libraries(shared shaders networking graphics fbx material-networking model-baker) include_hifi_library_headers(hfm) include_hifi_library_headers(task) +include_hifi_library_headers(gpu) +include_hifi_library_headers(image) +include_hifi_library_headers(ktx) \ No newline at end of file diff --git a/libraries/model-networking/src/model-networking/MaterialCache.h b/libraries/model-networking/src/model-networking/MaterialCache.h deleted file mode 100644 index 6abadfc030..0000000000 --- a/libraries/model-networking/src/model-networking/MaterialCache.h +++ /dev/null @@ -1,60 +0,0 @@ -// -// Created by Sam Gondelman on 2/9/2018 -// Copyright 2018 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 -// -#ifndef hifi_MaterialCache_h -#define hifi_MaterialCache_h - -#include - -#include "glm/glm.hpp" - -#include "ModelCache.h" - -class NetworkMaterialResource : public Resource { -public: - NetworkMaterialResource(const QUrl& url); - - QString getType() const override { return "NetworkMaterial"; } - - virtual void downloadFinished(const QByteArray& data) override; - - typedef struct ParsedMaterials { - uint version { 1 }; - std::vector names; - std::unordered_map> networkMaterials; - - void reset() { - version = 1; - names.clear(); - networkMaterials.clear(); - } - - } ParsedMaterials; - - ParsedMaterials parsedMaterials; - - static ParsedMaterials parseJSONMaterials(const QJsonDocument& materialJSON, const QUrl& baseUrl); - static std::pair> parseJSONMaterial(const QJsonObject& materialJSON, const QUrl& baseUrl); - -private: - static bool parseJSONColor(const QJsonValue& array, glm::vec3& color, bool& isSRGB); -}; - -using NetworkMaterialResourcePointer = QSharedPointer; - -class MaterialCache : public ResourceCache { -public: - static MaterialCache& instance(); - - NetworkMaterialResourcePointer getMaterial(const QUrl& url); - -protected: - virtual QSharedPointer createResource(const QUrl& url) override; - QSharedPointer createResourceCopy(const QSharedPointer& resource) override; -}; - -#endif diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 90925d17c3..581196b2cc 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -76,9 +76,9 @@ namespace std { template <> struct hash { - size_t operator()(const GeometryExtra& a) const { + size_t operator()(const GeometryExtra& geometryExtra) const { size_t result = 0; - hash_combine(result, a.mapping, a.textureBaseUrl, a.combineParts); + hash_combine(result, geometryExtra.mapping, geometryExtra.textureBaseUrl, geometryExtra.combineParts); return result; } }; @@ -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; @@ -392,7 +394,7 @@ QSharedPointer ModelCache::createResource(const QUrl& url) { } QSharedPointer ModelCache::createResourceCopy(const QSharedPointer& resource) { - return QSharedPointer(new GeometryDefinitionResource(*resource.staticCast().data()), &Resource::deleter); + return QSharedPointer(new GeometryDefinitionResource(*resource.staticCast()), &Resource::deleter); } GeometryResource::Pointer ModelCache::getGeometryResource(const QUrl& url, @@ -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; @@ -556,310 +559,4 @@ void GeometryResourceWatcher::resourceRefreshed() { // _instance.reset(); } -NetworkMaterial::NetworkMaterial(const NetworkMaterial& m) : - Material(m), - _textures(m._textures), - _albedoTransform(m._albedoTransform), - _lightmapTransform(m._lightmapTransform), - _lightmapParams(m._lightmapParams), - _isOriginal(m._isOriginal) -{} - -const QString NetworkMaterial::NO_TEXTURE = QString(); - -const QString& NetworkMaterial::getTextureName(MapChannel channel) { - if (_textures[channel].texture) { - return _textures[channel].name; - } - return NO_TEXTURE; -} - -QUrl NetworkMaterial::getTextureUrl(const QUrl& baseUrl, const HFMTexture& texture) { - if (texture.content.isEmpty()) { - // External file: search relative to the baseUrl, in case filename is relative - return baseUrl.resolved(QUrl(texture.filename)); - } else { - // Inlined file: cache under the fbx file to avoid namespace clashes - // NOTE: We cannot resolve the path because filename may be an absolute path - assert(texture.filename.size() > 0); - auto baseUrlStripped = baseUrl.toDisplayString(QUrl::RemoveFragment | QUrl::RemoveQuery | QUrl::RemoveUserInfo); - if (texture.filename.at(0) == '/') { - return baseUrlStripped + texture.filename; - } else { - return baseUrlStripped + '/' + texture.filename; - } - } -} - -graphics::TextureMapPointer NetworkMaterial::fetchTextureMap(const QUrl& baseUrl, const HFMTexture& hfmTexture, - image::TextureUsage::Type type, MapChannel channel) { - - if (baseUrl.isEmpty()) { - return nullptr; - } - - const auto url = getTextureUrl(baseUrl, hfmTexture); - const auto texture = DependencyManager::get()->getTexture(url, type, hfmTexture.content, hfmTexture.maxNumPixels, hfmTexture.sourceChannel); - _textures[channel] = Texture { hfmTexture.name, texture }; - - auto map = std::make_shared(); - if (texture) { - map->setTextureSource(texture->_textureSource); - } - map->setTextureTransform(hfmTexture.transform); - - return map; -} - -graphics::TextureMapPointer NetworkMaterial::fetchTextureMap(const QUrl& url, image::TextureUsage::Type type, MapChannel channel) { - auto textureCache = DependencyManager::get(); - if (textureCache && !url.isEmpty()) { - auto texture = textureCache->getTexture(url, type); - _textures[channel].texture = texture; - - auto map = std::make_shared(); - if (texture) { - map->setTextureSource(texture->_textureSource); - } - - return map; - } - return nullptr; -} - -void NetworkMaterial::setAlbedoMap(const QUrl& url, bool useAlphaChannel) { - auto map = fetchTextureMap(url, image::TextureUsage::ALBEDO_TEXTURE, MapChannel::ALBEDO_MAP); - if (map) { - map->setUseAlphaChannel(useAlphaChannel); - setTextureMap(MapChannel::ALBEDO_MAP, map); - } -} - -void NetworkMaterial::setNormalMap(const QUrl& url, bool isBumpmap) { - auto map = fetchTextureMap(url, isBumpmap ? image::TextureUsage::BUMP_TEXTURE : image::TextureUsage::NORMAL_TEXTURE, MapChannel::NORMAL_MAP); - if (map) { - setTextureMap(MapChannel::NORMAL_MAP, map); - } -} - -void NetworkMaterial::setRoughnessMap(const QUrl& url, bool isGloss) { - auto map = fetchTextureMap(url, isGloss ? image::TextureUsage::GLOSS_TEXTURE : image::TextureUsage::ROUGHNESS_TEXTURE, MapChannel::ROUGHNESS_MAP); - if (map) { - setTextureMap(MapChannel::ROUGHNESS_MAP, map); - } -} - -void NetworkMaterial::setMetallicMap(const QUrl& url, bool isSpecular) { - auto map = fetchTextureMap(url, isSpecular ? image::TextureUsage::SPECULAR_TEXTURE : image::TextureUsage::METALLIC_TEXTURE, MapChannel::METALLIC_MAP); - if (map) { - setTextureMap(MapChannel::METALLIC_MAP, map); - } -} - -void NetworkMaterial::setOcclusionMap(const QUrl& url) { - auto map = fetchTextureMap(url, image::TextureUsage::OCCLUSION_TEXTURE, MapChannel::OCCLUSION_MAP); - if (map) { - setTextureMap(MapChannel::OCCLUSION_MAP, map); - } -} - -void NetworkMaterial::setEmissiveMap(const QUrl& url) { - auto map = fetchTextureMap(url, image::TextureUsage::EMISSIVE_TEXTURE, MapChannel::EMISSIVE_MAP); - if (map) { - setTextureMap(MapChannel::EMISSIVE_MAP, map); - } -} - -void NetworkMaterial::setScatteringMap(const QUrl& url) { - auto map = fetchTextureMap(url, image::TextureUsage::SCATTERING_TEXTURE, MapChannel::SCATTERING_MAP); - if (map) { - setTextureMap(MapChannel::SCATTERING_MAP, map); - } -} - -void NetworkMaterial::setLightmapMap(const QUrl& url) { - auto map = fetchTextureMap(url, image::TextureUsage::LIGHTMAP_TEXTURE, MapChannel::LIGHTMAP_MAP); - if (map) { - //map->setTextureTransform(_lightmapTransform); - //map->setLightmapOffsetScale(_lightmapParams.x, _lightmapParams.y); - setTextureMap(MapChannel::LIGHTMAP_MAP, map); - } -} - -NetworkMaterial::NetworkMaterial(const HFMMaterial& material, const QUrl& textureBaseUrl) : - graphics::Material(*material._material), - _textures(MapChannel::NUM_MAP_CHANNELS) -{ - _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.roughnessTexture.filename.isEmpty()) { - auto map = fetchTextureMap(textureBaseUrl, material.roughnessTexture, image::TextureUsage::ROUGHNESS_TEXTURE, MapChannel::ROUGHNESS_MAP); - setTextureMap(MapChannel::ROUGHNESS_MAP, map); - } else if (!material.glossTexture.filename.isEmpty()) { - auto map = fetchTextureMap(textureBaseUrl, material.glossTexture, image::TextureUsage::GLOSS_TEXTURE, MapChannel::ROUGHNESS_MAP); - setTextureMap(MapChannel::ROUGHNESS_MAP, map); - } - - if (!material.metallicTexture.filename.isEmpty()) { - auto map = fetchTextureMap(textureBaseUrl, material.metallicTexture, image::TextureUsage::METALLIC_TEXTURE, MapChannel::METALLIC_MAP); - setTextureMap(MapChannel::METALLIC_MAP, map); - } else if (!material.specularTexture.filename.isEmpty()) { - auto map = fetchTextureMap(textureBaseUrl, material.specularTexture, image::TextureUsage::SPECULAR_TEXTURE, MapChannel::METALLIC_MAP); - setTextureMap(MapChannel::METALLIC_MAP, map); - } - - if (!material.occlusionTexture.filename.isEmpty()) { - auto map = fetchTextureMap(textureBaseUrl, material.occlusionTexture, image::TextureUsage::OCCLUSION_TEXTURE, MapChannel::OCCLUSION_MAP); - if (map) { - map->setTextureTransform(material.occlusionTexture.transform); - } - setTextureMap(MapChannel::OCCLUSION_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.scatteringTexture.filename.isEmpty()) { - auto map = fetchTextureMap(textureBaseUrl, material.scatteringTexture, image::TextureUsage::SCATTERING_TEXTURE, MapChannel::SCATTERING_MAP); - setTextureMap(MapChannel::SCATTERING_MAP, map); - } - - if (!material.lightmapTexture.filename.isEmpty()) { - auto map = fetchTextureMap(textureBaseUrl, material.lightmapTexture, image::TextureUsage::LIGHTMAP_TEXTURE, MapChannel::LIGHTMAP_MAP); - if (map) { - _lightmapTransform = material.lightmapTexture.transform; - _lightmapParams = material.lightmapParams; - map->setTextureTransform(_lightmapTransform); - map->setLightmapOffsetScale(_lightmapParams.x, _lightmapParams.y); - } - setTextureMap(MapChannel::LIGHTMAP_MAP, map); - } -} - -void NetworkMaterial::setTextures(const QVariantMap& textureMap) { - _isOriginal = false; - - const auto& albedoName = getTextureName(MapChannel::ALBEDO_MAP); - const auto& normalName = getTextureName(MapChannel::NORMAL_MAP); - const auto& roughnessName = getTextureName(MapChannel::ROUGHNESS_MAP); - const auto& metallicName = getTextureName(MapChannel::METALLIC_MAP); - const auto& occlusionName = getTextureName(MapChannel::OCCLUSION_MAP); - const auto& emissiveName = getTextureName(MapChannel::EMISSIVE_MAP); - const auto& lightmapName = getTextureName(MapChannel::LIGHTMAP_MAP); - const auto& scatteringName = getTextureName(MapChannel::SCATTERING_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 (!roughnessName.isEmpty()) { - auto url = textureMap.contains(roughnessName) ? textureMap[roughnessName].toUrl() : QUrl(); - // FIXME: If passing a gloss map instead of a roughmap how do we know? - auto map = fetchTextureMap(url, image::TextureUsage::ROUGHNESS_TEXTURE, MapChannel::ROUGHNESS_MAP); - setTextureMap(MapChannel::ROUGHNESS_MAP, map); - } - - if (!metallicName.isEmpty()) { - auto url = textureMap.contains(metallicName) ? textureMap[metallicName].toUrl() : QUrl(); - // FIXME: If passing a specular map instead of a metallic how do we know? - auto map = fetchTextureMap(url, image::TextureUsage::METALLIC_TEXTURE, MapChannel::METALLIC_MAP); - setTextureMap(MapChannel::METALLIC_MAP, map); - } - - if (!occlusionName.isEmpty()) { - auto url = textureMap.contains(occlusionName) ? textureMap[occlusionName].toUrl() : QUrl(); - // FIXME: we need to handle the occlusion map transform here - auto map = fetchTextureMap(url, image::TextureUsage::OCCLUSION_TEXTURE, MapChannel::OCCLUSION_MAP); - setTextureMap(MapChannel::OCCLUSION_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 (!scatteringName.isEmpty()) { - auto url = textureMap.contains(scatteringName) ? textureMap[scatteringName].toUrl() : QUrl(); - auto map = fetchTextureMap(url, image::TextureUsage::SCATTERING_TEXTURE, MapChannel::SCATTERING_MAP); - setTextureMap(MapChannel::SCATTERING_MAP, map); - } - - if (!lightmapName.isEmpty()) { - auto url = textureMap.contains(lightmapName) ? textureMap[lightmapName].toUrl() : QUrl(); - auto map = fetchTextureMap(url, image::TextureUsage::LIGHTMAP_TEXTURE, MapChannel::LIGHTMAP_MAP); - if (map) { - map->setTextureTransform(_lightmapTransform); - map->setLightmapOffsetScale(_lightmapParams.x, _lightmapParams.y); - } - setTextureMap(MapChannel::LIGHTMAP_MAP, map); - } -} - -bool NetworkMaterial::isMissingTexture() { - for (auto& networkTexture : _textures) { - auto& texture = networkTexture.texture; - if (!texture) { - continue; - } - // Failed texture downloads need to be considered as 'loaded' - // or the object will never fade in - bool finished = texture->isFailed() || (texture->isLoaded() && texture->getGPUTexture() && texture->getGPUTexture()->isDefined()); - if (!finished) { - return true; - } - } - return false; -} - -void NetworkMaterial::checkResetOpacityMap() { - // If material textures are loaded, check the material translucency - // FIXME: This should not be done here. The opacity map should already be reset in Material::setTextureMap. - // However, currently that code can be called before the albedo map is defined, so resetOpacityMap will fail. - // Geometry::areTexturesLoaded() is called repeatedly until it returns true, so we do the check here for now - const auto& albedoTexture = _textures[NetworkMaterial::MapChannel::ALBEDO_MAP]; - if (albedoTexture.texture) { - resetOpacityMap(); - } -} - #include "ModelCache.moc" diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index 497cae86a3..4cd7048dca 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -15,17 +15,13 @@ #include #include -#include #include #include "FBXSerializer.h" -#include "TextureCache.h" +#include +#include #include "ModelLoader.h" -// Alias instead of derive to avoid copying - -class NetworkTexture; -class NetworkMaterial; class MeshPart; class GeometryMappingResource; @@ -49,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; @@ -64,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; @@ -166,59 +164,6 @@ private: ModelLoader _modelLoader; }; -class NetworkMaterial : public graphics::Material { -public: - using MapChannel = graphics::Material::MapChannel; - - NetworkMaterial() : _textures(MapChannel::NUM_MAP_CHANNELS) {} - NetworkMaterial(const HFMMaterial& material, const QUrl& textureBaseUrl); - NetworkMaterial(const NetworkMaterial& material); - - void setAlbedoMap(const QUrl& url, bool useAlphaChannel); - void setNormalMap(const QUrl& url, bool isBumpmap); - void setRoughnessMap(const QUrl& url, bool isGloss); - void setMetallicMap(const QUrl& url, bool isSpecular); - void setOcclusionMap(const QUrl& url); - void setEmissiveMap(const QUrl& url); - void setScatteringMap(const QUrl& url); - void setLightmapMap(const QUrl& url); - - bool isMissingTexture(); - void checkResetOpacityMap(); - -protected: - friend class Geometry; - - class Texture { - public: - QString name; - NetworkTexturePointer texture; - }; - using Textures = std::vector; - - Textures _textures; - - static const QString NO_TEXTURE; - const QString& getTextureName(MapChannel channel); - - void setTextures(const QVariantMap& textureMap); - - const bool& isOriginal() const { return _isOriginal; } - -private: - // Helpers for the ctors - QUrl getTextureUrl(const QUrl& baseUrl, const HFMTexture& hfmTexture); - graphics::TextureMapPointer fetchTextureMap(const QUrl& baseUrl, const HFMTexture& hfmTexture, - image::TextureUsage::Type type, MapChannel channel); - graphics::TextureMapPointer fetchTextureMap(const QUrl& url, image::TextureUsage::Type type, MapChannel channel); - - Transform _albedoTransform; - Transform _lightmapTransform; - vec2 _lightmapParams; - - bool _isOriginal { true }; -}; - class MeshPart { public: MeshPart(int mesh, int part, int material) : meshID { mesh }, partID { part }, materialID { material } {} diff --git a/libraries/model-networking/src/model-networking/ModelNetworkingLogging.cpp b/libraries/model-networking/src/model-networking/ModelNetworkingLogging.cpp index 0c44fa33eb..d76efec31a 100644 --- a/libraries/model-networking/src/model-networking/ModelNetworkingLogging.cpp +++ b/libraries/model-networking/src/model-networking/ModelNetworkingLogging.cpp @@ -8,4 +8,4 @@ #include "ModelNetworkingLogging.h" -Q_LOGGING_CATEGORY(modelnetworking, "hifi.gpu-network") +Q_LOGGING_CATEGORY(modelnetworking, "hifi.gpu-model-network") diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index f3967d8ffc..2096213273 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -360,13 +360,13 @@ class Resource : public QObject { Q_OBJECT public: - + Resource() : QObject(), _loaded(true) {} Resource(const Resource& other); Resource(const QUrl& url); virtual ~Resource(); virtual QString getType() const { return "Resource"; } - + /// Returns the key last used to identify this resource in the unused map. int getLRUKey() const { return _lruKey; } @@ -375,13 +375,13 @@ public: /// Sets the load priority for one owner. virtual void setLoadPriority(const QPointer& owner, float priority); - + /// Sets a set of priorities at once. virtual void setLoadPriorities(const QHash, float>& priorities); - + /// Clears the load priority for one owner. virtual void clearLoadPriority(const QPointer& owner); - + /// Returns the highest load priority across all owners. float getLoadPriority(); @@ -491,14 +491,14 @@ protected: QWeakPointer _self; QPointer _cache; - qint64 _bytesReceived{ 0 }; - qint64 _bytesTotal{ 0 }; - qint64 _bytes{ 0 }; + qint64 _bytesReceived { 0 }; + qint64 _bytesTotal { 0 }; + qint64 _bytes { 0 }; int _requestID; - ResourceRequest* _request{ nullptr }; + ResourceRequest* _request { nullptr }; - size_t _extraHash; + size_t _extraHash { std::numeric_limits::max() }; public slots: void handleDownloadProgress(uint64_t bytesReceived, uint64_t bytesTotal); diff --git a/libraries/physics/CMakeLists.txt b/libraries/physics/CMakeLists.txt index 5249ed2950..d7ce40641d 100644 --- a/libraries/physics/CMakeLists.txt +++ b/libraries/physics/CMakeLists.txt @@ -7,6 +7,7 @@ include_hifi_library_headers(avatars) include_hifi_library_headers(audio) include_hifi_library_headers(octree) include_hifi_library_headers(animation) +include_hifi_library_headers(material-networking) include_hifi_library_headers(model-networking) include_hifi_library_headers(image) include_hifi_library_headers(ktx) diff --git a/libraries/procedural/CMakeLists.txt b/libraries/procedural/CMakeLists.txt index f3c3be687a..d08a7aef02 100644 --- a/libraries/procedural/CMakeLists.txt +++ b/libraries/procedural/CMakeLists.txt @@ -1,3 +1,4 @@ set(TARGET_NAME procedural) setup_hifi_library() -link_hifi_libraries(shared gpu shaders networking graphics model-networking ktx image) + +link_hifi_libraries(shared gpu shaders networking graphics material-networking ktx image) diff --git a/libraries/procedural/src/procedural/Procedural.h b/libraries/procedural/src/procedural/Procedural.h index 3e10678ba7..8477e69afc 100644 --- a/libraries/procedural/src/procedural/Procedural.h +++ b/libraries/procedural/src/procedural/Procedural.h @@ -19,8 +19,8 @@ #include #include #include -#include -#include +#include +#include using UniformLambdas = std::list>; const size_t MAX_PROCEDURAL_TEXTURE_CHANNELS{ 4 }; diff --git a/libraries/recording/src/recording/ClipCache.cpp b/libraries/recording/src/recording/ClipCache.cpp index c08dd40ad8..bc20e4d8eb 100644 --- a/libraries/recording/src/recording/ClipCache.cpp +++ b/libraries/recording/src/recording/ClipCache.cpp @@ -54,5 +54,5 @@ QSharedPointer ClipCache::createResource(const QUrl& url) { } QSharedPointer ClipCache::createResourceCopy(const QSharedPointer& resource) { - return QSharedPointer(new NetworkClipLoader(*resource.staticCast().data()), &Resource::deleter); + return QSharedPointer(new NetworkClipLoader(*resource.staticCast()), &Resource::deleter); } \ No newline at end of file diff --git a/libraries/render-utils/CMakeLists.txt b/libraries/render-utils/CMakeLists.txt index 2b092bff2a..833d78bb74 100644 --- a/libraries/render-utils/CMakeLists.txt +++ b/libraries/render-utils/CMakeLists.txt @@ -3,7 +3,7 @@ set(TARGET_NAME render-utils) # pull in the resources.qrc file qt5_add_resources(QT_RESOURCES_FILE "${CMAKE_CURRENT_SOURCE_DIR}/res/fonts/fonts.qrc") setup_hifi_library(Gui Network Qml Quick Script) -link_hifi_libraries(shared task ktx gpu shaders graphics graphics-scripting model-networking render animation fbx image procedural) +link_hifi_libraries(shared task ktx gpu shaders graphics graphics-scripting material-networking model-networking render animation fbx image procedural) include_hifi_library_headers(audio) include_hifi_library_headers(networking) include_hifi_library_headers(octree) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 0206bd6963..b9b294d0e3 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -756,7 +756,16 @@ scriptable::ScriptableModelBase Model::getScriptableModel() { int numParts = (int)mesh->getNumParts(); for (int partIndex = 0; partIndex < numParts; partIndex++) { - result.appendMaterial(graphics::MaterialLayer(getGeometry()->getShapeMaterial(shapeID), 0), shapeID, _modelMeshMaterialNames[shapeID]); + auto& materialName = _modelMeshMaterialNames[shapeID]; + result.appendMaterial(graphics::MaterialLayer(getGeometry()->getShapeMaterial(shapeID), 0), shapeID, materialName); + + auto mappedMaterialIter = _materialMapping.find(shapeID); + if (mappedMaterialIter != _materialMapping.end()) { + auto mappedMaterials = mappedMaterialIter->second; + for (auto& mappedMaterial : mappedMaterials) { + result.appendMaterial(mappedMaterial, shapeID, materialName); + } + } shapeID++; } } @@ -956,6 +965,7 @@ bool Model::addToScene(const render::ScenePointer& scene, } if (somethingAdded) { + applyMaterialMapping(); _addedToScene = true; updateRenderItems(); _needsFixupInScene = false; @@ -973,6 +983,7 @@ void Model::removeFromScene(const render::ScenePointer& scene, render::Transacti _modelMeshRenderItems.clear(); _modelMeshMaterialNames.clear(); _modelMeshRenderItemShapes.clear(); + _priorityMap.clear(); _blendshapeOffsets.clear(); _blendshapeOffsetsInitialized = false; @@ -1519,17 +1530,65 @@ std::set Model::getMeshIDsFromMaterialID(QString parentMaterialNam return toReturn; } +void Model::applyMaterialMapping() { + auto renderItemsKey = _renderItemKeyGlobalFlags; + PrimitiveMode primitiveMode = getPrimitiveMode(); + bool useDualQuaternionSkinning = _useDualQuaternionSkinning; + + auto& materialMapping = getMaterialMapping(); + for (auto& mapping : materialMapping) { + std::set shapeIDs = getMeshIDsFromMaterialID(QString(mapping.first.c_str())); + auto networkMaterialResource = mapping.second; + if (!networkMaterialResource || shapeIDs.size() == 0) { + continue; + } + + auto materialLoaded = [this, networkMaterialResource, shapeIDs, renderItemsKey, primitiveMode, useDualQuaternionSkinning]() { + if (networkMaterialResource->isFailed() || networkMaterialResource->parsedMaterials.names.size() == 0) { + return; + } + render::Transaction transaction; + 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]); + _materialMapping[shapeID].push_back(material); + 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); + }; + + if (networkMaterialResource->isLoaded()) { + materialLoaded(); + } else { + connect(networkMaterialResource.data(), &Resource::finished, materialLoaded); + } + } +} + 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..d1d4a7d3d1 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,10 @@ signals: protected: + std::unordered_map _priorityMap; // only used for materialMapping + std::unordered_map> _materialMapping; // generated during applyMaterialMapping + void applyMaterialMapping(); + void setBlendshapeCoefficients(const QVector& coefficients) { _blendshapeCoefficients = coefficients; } const QVector& getBlendshapeCoefficients() const { return _blendshapeCoefficients; } diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index 5f3763ac2a..6f6f2ab856 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -15,7 +15,7 @@ #include #include -#include +#include #include #include #include diff --git a/libraries/render-utils/src/TextureCache.h b/libraries/render-utils/src/TextureCache.h index d6c1e419b9..f010666e19 100644 --- a/libraries/render-utils/src/TextureCache.h +++ b/libraries/render-utils/src/TextureCache.h @@ -1,2 +1,2 @@ // Compatibility -#include +#include diff --git a/libraries/script-engine/CMakeLists.txt b/libraries/script-engine/CMakeLists.txt index 346c6e50f6..82c408f386 100644 --- a/libraries/script-engine/CMakeLists.txt +++ b/libraries/script-engine/CMakeLists.txt @@ -17,6 +17,6 @@ if (NOT ANDROID) endif () -link_hifi_libraries(shared networking octree shaders gpu procedural graphics model-networking ktx recording avatars fbx hfm entities controllers animation audio physics image midi) +link_hifi_libraries(shared networking octree shaders gpu procedural graphics material-networking model-networking ktx recording avatars fbx hfm entities controllers animation audio physics image midi) # ui includes gl, but link_hifi_libraries does not use transitive includes, so gl must be explicit include_hifi_library_headers(gl) diff --git a/plugins/openvr/CMakeLists.txt b/plugins/openvr/CMakeLists.txt index 8e43397c19..dcb2e39e1b 100644 --- a/plugins/openvr/CMakeLists.txt +++ b/plugins/openvr/CMakeLists.txt @@ -11,7 +11,7 @@ if (WIN32 AND (NOT USE_GLES)) setup_hifi_plugin(Gui Qml Multimedia) link_hifi_libraries(shared task gl qml networking controllers ui plugins display-plugins ui-plugins input-plugins script-engine - audio-client render-utils graphics shaders gpu render model-networking model-baker hfm fbx ktx image procedural ${PLATFORM_GL_BACKEND}) + audio-client render-utils graphics shaders gpu render material-networking model-networking model-baker hfm fbx ktx image procedural ${PLATFORM_GL_BACKEND}) include_hifi_library_headers(octree) target_openvr()