diff --git a/exts/cesium.omniverse/mdl/cesium.mdl b/exts/cesium.omniverse/mdl/cesium.mdl index e3bdbe16a..81b88adcd 100644 --- a/exts/cesium.omniverse/mdl/cesium.mdl +++ b/exts/cesium.omniverse/mdl/cesium.mdl @@ -11,6 +11,64 @@ module [[ anno::display_name("Cesium MDL functions") ]]; -// For internal use only. See note in FabricMaterial.cpp +// For internal use only export gltf_texture_lookup_value cesium_texture_lookup(*) [[ anno::hidden() ]] = gltf_texture_lookup(); export material cesium_material(*) [[ anno::hidden() ]] = gltf_material(); + +export gltf_texture_lookup_value cesium_texture_array_lookup( + uniform int texture_count = 0, + gltf_texture_lookup_value texture_0 = gltf_texture_lookup(), + gltf_texture_lookup_value texture_1 = gltf_texture_lookup(), + gltf_texture_lookup_value texture_2 = gltf_texture_lookup(), + gltf_texture_lookup_value texture_3 = gltf_texture_lookup(), + gltf_texture_lookup_value texture_4 = gltf_texture_lookup(), + gltf_texture_lookup_value texture_5 = gltf_texture_lookup(), + gltf_texture_lookup_value texture_6 = gltf_texture_lookup(), + gltf_texture_lookup_value texture_7 = gltf_texture_lookup(), + gltf_texture_lookup_value texture_8 = gltf_texture_lookup(), + gltf_texture_lookup_value texture_9 = gltf_texture_lookup(), + gltf_texture_lookup_value texture_10 = gltf_texture_lookup(), + gltf_texture_lookup_value texture_11 = gltf_texture_lookup(), + gltf_texture_lookup_value texture_12 = gltf_texture_lookup(), + gltf_texture_lookup_value texture_13 = gltf_texture_lookup(), + gltf_texture_lookup_value texture_14 = gltf_texture_lookup(), + gltf_texture_lookup_value texture_15 = gltf_texture_lookup() +) [[ anno::hidden() ]] +{ + // The array length should match MAX_TEXTURE_LAYER_COUNT in Tokens.h + gltf_texture_lookup_value[16] texture_values( + texture_0, + texture_1, + texture_2, + texture_3, + texture_4, + texture_5, + texture_6, + texture_7, + texture_8, + texture_9, + texture_10, + texture_11, + texture_12, + texture_13, + texture_14, + texture_15, + ); + + float3 final = float3(1.0, 1.0, 1.0); + + for (int i = 0; i < texture_count; i++) { + gltf_texture_lookup_value value = texture_values[i]; + if (value.valid) { + float3 rgb = float3(value.value[0], value.value[1], value.value[2]); + float alpha = value.value[3]; + final = alpha * rgb + (1.0 - alpha) * final; + } + } + + gltf_texture_lookup_value tex_ret; + tex_ret.value = float4(final[0], final[1], final[2], 1.0); + tex_ret.valid = true; + + return tex_ret; +} diff --git a/src/core/include/cesium/omniverse/FabricGeometry.h b/src/core/include/cesium/omniverse/FabricGeometry.h index 10f977f6d..cf572d14b 100644 --- a/src/core/include/cesium/omniverse/FabricGeometry.h +++ b/src/core/include/cesium/omniverse/FabricGeometry.h @@ -30,7 +30,8 @@ class FabricGeometry { const CesiumGltf::Model& model, const CesiumGltf::MeshPrimitive& primitive, bool smoothNormals, - bool hasImagery); + const std::unordered_map& texcoordIndexMapping, + const std::unordered_map& imageryTexcoordIndexMapping); void setActive(bool active); void setVisibility(bool visible); diff --git a/src/core/include/cesium/omniverse/FabricGeometryDefinition.h b/src/core/include/cesium/omniverse/FabricGeometryDefinition.h index 26bd43eac..6e64771e0 100644 --- a/src/core/include/cesium/omniverse/FabricGeometryDefinition.h +++ b/src/core/include/cesium/omniverse/FabricGeometryDefinition.h @@ -16,18 +16,18 @@ class FabricGeometryDefinition { const CesiumGltf::MeshPrimitive& primitive, bool smoothNormals); - [[nodiscard]] bool hasTexcoords() const; [[nodiscard]] bool hasNormals() const; [[nodiscard]] bool hasVertexColors() const; [[nodiscard]] bool getDoubleSided() const; + [[nodiscard]] uint64_t getTexcoordSetCount() const; bool operator==(const FabricGeometryDefinition& other) const; private: - bool _hasTexcoords{false}; bool _hasNormals{false}; bool _hasVertexColors{false}; bool _doubleSided{false}; + uint64_t _texcoordSetCount{0}; }; } // namespace cesium::omniverse diff --git a/src/core/include/cesium/omniverse/FabricMaterial.h b/src/core/include/cesium/omniverse/FabricMaterial.h index dc5bc7535..3a0d94ab2 100644 --- a/src/core/include/cesium/omniverse/FabricMaterial.h +++ b/src/core/include/cesium/omniverse/FabricMaterial.h @@ -20,14 +20,19 @@ class FabricMaterial { const omni::fabric::Path& path, const FabricMaterialDefinition& materialDefinition, const pxr::TfToken& defaultTextureAssetPathToken, + const pxr::TfToken& defaultTransparentTextureAssetPathToken, long stageId); ~FabricMaterial(); void setMaterial(int64_t tilesetId, const MaterialInfo& materialInfo); - void setBaseColorTexture(const pxr::TfToken& textureAssetPathToken, const TextureInfo& textureInfo); + void setBaseColorTexture( + const pxr::TfToken& textureAssetPathToken, + const TextureInfo& textureInfo, + uint64_t texcoordIndex, + uint64_t textureIndex); void clearMaterial(); - void clearBaseColorTexture(); + void clearBaseColorTexture(uint64_t textureIndex); void setActive(bool active); @@ -43,23 +48,31 @@ class FabricMaterial { const omni::fabric::Path& texturePath, const omni::fabric::Path& shaderPath, const omni::fabric::Token& shaderInput); - + void createTextureArray( + const omni::fabric::Path& texturePath, + const omni::fabric::Path& shaderPath, + const omni::fabric::Token& shaderInput, + uint64_t textureCount); void reset(); void setShaderValues(const omni::fabric::Path& shaderPath, const MaterialInfo& materialInfo); void setTextureValues( const omni::fabric::Path& texturePath, const pxr::TfToken& textureAssetPathToken, - const TextureInfo& textureInfo); + const TextureInfo& textureInfo, + uint64_t texcoordIndex); void setTilesetId(int64_t tilesetId); bool stageDestroyed(); + void clearBaseColorTextures(); omni::fabric::Path _materialPath; const FabricMaterialDefinition _materialDefinition; const pxr::TfToken _defaultTextureAssetPathToken; + const pxr::TfToken _defaultTransparentTextureAssetPathToken; const long _stageId; omni::fabric::Path _shaderPath; omni::fabric::Path _baseColorTexturePath; + std::vector _baseColorTextureLayerPaths; }; } // namespace cesium::omniverse diff --git a/src/core/include/cesium/omniverse/FabricMaterialDefinition.h b/src/core/include/cesium/omniverse/FabricMaterialDefinition.h index ff551594f..1c5758c45 100644 --- a/src/core/include/cesium/omniverse/FabricMaterialDefinition.h +++ b/src/core/include/cesium/omniverse/FabricMaterialDefinition.h @@ -10,17 +10,18 @@ struct MaterialInfo; class FabricMaterialDefinition { public: - FabricMaterialDefinition(const MaterialInfo& materialInfo, bool hasImagery, bool disableTextures); + FabricMaterialDefinition(const MaterialInfo& materialInfo, uint64_t imageryLayerCount, bool disableTextures); - [[nodiscard]] bool hasBaseColorTexture() const; [[nodiscard]] bool hasVertexColors() const; + [[nodiscard]] uint64_t getBaseColorTextureCount() const; + [[nodiscard]] bool hasBaseColorTextures() const; // Make sure to update this function when adding new fields to the class bool operator==(const FabricMaterialDefinition& other) const; private: - bool _hasBaseColorTexture; bool _hasVertexColors; + uint64_t _baseColorTextureCount; }; } // namespace cesium::omniverse diff --git a/src/core/include/cesium/omniverse/FabricMaterialPool.h b/src/core/include/cesium/omniverse/FabricMaterialPool.h index 699276a8d..a93c25a6b 100644 --- a/src/core/include/cesium/omniverse/FabricMaterialPool.h +++ b/src/core/include/cesium/omniverse/FabricMaterialPool.h @@ -15,6 +15,7 @@ class FabricMaterialPool final : public ObjectPool { const FabricMaterialDefinition& materialDefinition, uint64_t initialCapacity, const pxr::TfToken& defaultTextureAssetPathToken, + const pxr::TfToken& defaultTransparentTextureAssetPathToken, long stageId); [[nodiscard]] const FabricMaterialDefinition& getMaterialDefinition() const; @@ -27,6 +28,7 @@ class FabricMaterialPool final : public ObjectPool { const int64_t _poolId; const FabricMaterialDefinition _materialDefinition; const pxr::TfToken _defaultTextureAssetPathToken; + const pxr::TfToken _defaultTransparentTextureAssetPathToken; const long _stageId; }; diff --git a/src/core/include/cesium/omniverse/FabricPrepareRenderResources.h b/src/core/include/cesium/omniverse/FabricPrepareRenderResources.h index 6a51fb03a..d5af91193 100644 --- a/src/core/include/cesium/omniverse/FabricPrepareRenderResources.h +++ b/src/core/include/cesium/omniverse/FabricPrepareRenderResources.h @@ -22,6 +22,8 @@ struct FabricMesh { std::shared_ptr material; std::shared_ptr baseColorTexture; MaterialInfo materialInfo; + std::unordered_map texcoordIndexMapping; + std::unordered_map imageryTexcoordIndexMapping; }; struct TileRenderResources { diff --git a/src/core/include/cesium/omniverse/FabricResourceManager.h b/src/core/include/cesium/omniverse/FabricResourceManager.h index 7eeaa99c8..fa405963c 100644 --- a/src/core/include/cesium/omniverse/FabricResourceManager.h +++ b/src/core/include/cesium/omniverse/FabricResourceManager.h @@ -62,7 +62,7 @@ class FabricResourceManager { long stageId); std::shared_ptr - acquireMaterial(const MaterialInfo& materialInfo, bool hasImagery, long stageId, int64_t tilesetId); + acquireMaterial(const MaterialInfo& materialInfo, uint64_t imageryLayerCount, long stageId, int64_t tilesetId); std::shared_ptr acquireTexture(); @@ -140,7 +140,9 @@ class FabricResourceManager { std::mutex _poolMutex; std::unique_ptr _defaultTexture; + std::unique_ptr _defaultTransparentTexture; pxr::TfToken _defaultTextureAssetPathToken; + pxr::TfToken _defaultTransparentTextureAssetPathToken; std::vector _retainedPaths; diff --git a/src/core/include/cesium/omniverse/GltfUtil.h b/src/core/include/cesium/omniverse/GltfUtil.h index 12e967eca..50e7eddbf 100644 --- a/src/core/include/cesium/omniverse/GltfUtil.h +++ b/src/core/include/cesium/omniverse/GltfUtil.h @@ -88,4 +88,8 @@ bool hasImageryTexcoords(const CesiumGltf::Model& model, const CesiumGltf::MeshP bool hasVertexColors(const CesiumGltf::Model& model, const CesiumGltf::MeshPrimitive& primitive, uint64_t setIndex); bool hasMaterial(const CesiumGltf::MeshPrimitive& primitive); +std::vector getTexcoordSetIndexes(const CesiumGltf::Model& model, const CesiumGltf::MeshPrimitive& primitive); +std::vector +getImageryTexcoordSetIndexes(const CesiumGltf::Model& model, const CesiumGltf::MeshPrimitive& primitive); + } // namespace cesium::omniverse::GltfUtil diff --git a/src/core/include/cesium/omniverse/OmniTileset.h b/src/core/include/cesium/omniverse/OmniTileset.h index fc0af9ab9..c3e0bcac3 100644 --- a/src/core/include/cesium/omniverse/OmniTileset.h +++ b/src/core/include/cesium/omniverse/OmniTileset.h @@ -11,6 +11,7 @@ #include namespace Cesium3DTilesSelection { +class RasterOverlay; class Tileset; class ViewState; class ViewUpdateResult; @@ -72,6 +73,8 @@ class OmniTileset { void reload(); void addImageryIon(const pxr::SdfPath& imageryPath); + [[nodiscard]] std::optional findImageryIndex(const Cesium3DTilesSelection::RasterOverlay& overlay) const; + [[nodiscard]] uint64_t getImageryLayerCount() const; void onUpdateFrame(const std::vector& viewports); private: diff --git a/src/core/include/cesium/omniverse/Tokens.h b/src/core/include/cesium/omniverse/Tokens.h index 5414fe5f8..28fabbb90 100644 --- a/src/core/include/cesium/omniverse/Tokens.h +++ b/src/core/include/cesium/omniverse/Tokens.h @@ -13,9 +13,27 @@ __pragma(warning(push)) __pragma(warning(disable : 4003)) // Note: variable names should match the USD token names as closely as possible, with special characters converted to underscores #define USD_TOKENS \ - (baseColorTexture) \ + (base_color_texture) \ + (base_color_texture_0) \ + (base_color_texture_1) \ + (base_color_texture_2) \ + (base_color_texture_3) \ + (base_color_texture_4) \ + (base_color_texture_5) \ + (base_color_texture_6) \ + (base_color_texture_7) \ + (base_color_texture_8) \ + (base_color_texture_9) \ + (base_color_texture_10) \ + (base_color_texture_11) \ + (base_color_texture_12) \ + (base_color_texture_13) \ + (base_color_texture_14) \ + (base_color_texture_15) \ + (base_color_texture_array) \ (cesium) \ (cesium_material) \ + (cesium_texture_array_lookup) \ (cesium_texture_lookup) \ (constant) \ (doubleSided) \ @@ -61,6 +79,23 @@ __pragma(warning(push)) __pragma(warning(disable : 4003)) ((inputs_scale, "inputs:scale")) \ ((inputs_tex_coord_index, "inputs:tex_coord_index")) \ ((inputs_texture, "inputs:texture")) \ + ((inputs_texture_0, "inputs:texture_0")) \ + ((inputs_texture_1, "inputs:texture_1")) \ + ((inputs_texture_2, "inputs:texture_2")) \ + ((inputs_texture_3, "inputs:texture_3")) \ + ((inputs_texture_4, "inputs:texture_4")) \ + ((inputs_texture_5, "inputs:texture_5")) \ + ((inputs_texture_6, "inputs:texture_6")) \ + ((inputs_texture_7, "inputs:texture_7")) \ + ((inputs_texture_8, "inputs:texture_8")) \ + ((inputs_texture_9, "inputs:texture_9")) \ + ((inputs_texture_10, "inputs:texture_10")) \ + ((inputs_texture_11, "inputs:texture_11")) \ + ((inputs_texture_12, "inputs:texture_12")) \ + ((inputs_texture_13, "inputs:texture_13")) \ + ((inputs_texture_14, "inputs:texture_14")) \ + ((inputs_texture_15, "inputs:texture_15")) \ + ((inputs_texture_count, "inputs:texture_count")) \ ((inputs_vertex_color_name, "inputs:vertex_color_name")) \ ((inputs_wrap_s, "inputs:wrap_s")) \ ((inputs_wrap_t, "inputs:wrap_t")) \ @@ -72,7 +107,16 @@ __pragma(warning(push)) __pragma(warning(disable : 4003)) ((primvars_displayColor, "primvars:displayColor")) \ ((primvars_displayOpacity, "primvars:displayOpacity")) \ ((primvars_normals, "primvars:normals")) \ - ((primvars_st, "primvars:st")) \ + ((primvars_st_0, "primvars:st_0")) \ + ((primvars_st_1, "primvars:st_1")) \ + ((primvars_st_2, "primvars:st_2")) \ + ((primvars_st_3, "primvars:st_3")) \ + ((primvars_st_4, "primvars:st_4")) \ + ((primvars_st_5, "primvars:st_5")) \ + ((primvars_st_6, "primvars:st_6")) \ + ((primvars_st_7, "primvars:st_7")) \ + ((primvars_st_8, "primvars:st_8")) \ + ((primvars_st_9, "primvars:st_9")) \ ((primvars_vertexColor, "primvars:vertexColor")) \ ((xformOp_transform_cesium, "xformOp:transform:cesium")) @@ -104,6 +148,61 @@ __pragma(warning(pop)) namespace cesium::omniverse::FabricTokens { FABRIC_DECLARE_TOKENS(USD_TOKENS); + +const uint64_t MAX_PRIMVAR_ST_COUNT = 10; +const uint64_t MAX_TEXTURE_LAYER_COUNT = 16; + +const std::array primvars_st_n = {{ + primvars_st_0, + primvars_st_1, + primvars_st_2, + primvars_st_3, + primvars_st_4, + primvars_st_5, + primvars_st_6, + primvars_st_7, + primvars_st_8, + primvars_st_9, +}}; + +const std::array base_color_texture_n = {{ + base_color_texture_0, + base_color_texture_1, + base_color_texture_2, + base_color_texture_3, + base_color_texture_4, + base_color_texture_5, + base_color_texture_6, + base_color_texture_7, + base_color_texture_8, + base_color_texture_9, + base_color_texture_10, + base_color_texture_11, + base_color_texture_12, + base_color_texture_13, + base_color_texture_14, + base_color_texture_15, +}}; + +const std::array inputs_texture_n = {{ + inputs_texture_0, + inputs_texture_1, + inputs_texture_2, + inputs_texture_3, + inputs_texture_4, + inputs_texture_5, + inputs_texture_6, + inputs_texture_7, + inputs_texture_8, + inputs_texture_9, + inputs_texture_10, + inputs_texture_11, + inputs_texture_12, + inputs_texture_13, + inputs_texture_14, + inputs_texture_15, +}}; + } namespace cesium::omniverse::FabricTypes { @@ -128,6 +227,7 @@ const omni::fabric::Type inputs_roughness_factor(omni::fabric::BaseDataType::eFl const omni::fabric::Type inputs_scale(omni::fabric::BaseDataType::eFloat, 2, 0, omni::fabric::AttributeRole::eNone); const omni::fabric::Type inputs_tex_coord_index(omni::fabric::BaseDataType::eInt, 1, 0, omni::fabric::AttributeRole::eNone); const omni::fabric::Type inputs_texture(omni::fabric::BaseDataType::eAsset, 1, 0, omni::fabric::AttributeRole::eNone); +const omni::fabric::Type inputs_texture_count(omni::fabric::BaseDataType::eInt, 1, 0, omni::fabric::AttributeRole::eNone); const omni::fabric::Type inputs_vertex_color_name(omni::fabric::BaseDataType::eUChar, 1, 1, omni::fabric::AttributeRole::eText); const omni::fabric::Type inputs_wrap_s(omni::fabric::BaseDataType::eInt, 1, 0, omni::fabric::AttributeRole::eNone); const omni::fabric::Type inputs_wrap_t(omni::fabric::BaseDataType::eInt, 1, 0, omni::fabric::AttributeRole::eNone); diff --git a/src/core/src/FabricGeometry.cpp b/src/core/src/FabricGeometry.cpp index 09eb99d03..f22a8eb6e 100644 --- a/src/core/src/FabricGeometry.cpp +++ b/src/core/src/FabricGeometry.cpp @@ -5,6 +5,7 @@ #include "cesium/omniverse/FabricResourceManager.h" #include "cesium/omniverse/FabricUtil.h" #include "cesium/omniverse/GltfUtil.h" +#include "cesium/omniverse/LoggerSink.h" #include "cesium/omniverse/Tokens.h" #include "cesium/omniverse/UsdUtil.h" @@ -32,6 +33,22 @@ const auto DEFAULT_SCALE = pxr::GfVec3f(1.0f, 1.0f, 1.0f); const auto DEFAULT_MATRIX = pxr::GfMatrix4d(1.0); const auto DEFAULT_VISIBILITY = false; +uint64_t getTexcoordSetCount(const FabricGeometryDefinition& geometryDefinition) { + auto texcoordSetCount = geometryDefinition.getTexcoordSetCount(); + + if (texcoordSetCount > FabricTokens::MAX_PRIMVAR_ST_COUNT) { + CESIUM_LOG_WARN( + "Number of texcoord sets ({}) exceeds maximum number of texcoord sets ({}). Textures using excess texcoord " + "sets will be ignored.", + texcoordSetCount, + FabricTokens::MAX_PRIMVAR_ST_COUNT); + } + + texcoordSetCount = glm::min(texcoordSetCount, FabricTokens::MAX_PRIMVAR_ST_COUNT); + + return texcoordSetCount; +} + } // namespace FabricGeometry::FabricGeometry( @@ -102,10 +119,10 @@ void FabricGeometry::setMaterial(const omni::fabric::Path& materialPath) { } void FabricGeometry::initialize() { - const auto hasTexcoords = _geometryDefinition.hasTexcoords(); const auto hasNormals = _geometryDefinition.hasNormals(); const auto hasVertexColors = _geometryDefinition.hasVertexColors(); const auto doubleSided = _geometryDefinition.getDoubleSided(); + const auto texcoordSetCount = getTexcoordSetCount(_geometryDefinition); auto srw = UsdUtil::getFabricStageReaderWriter(); @@ -132,8 +149,8 @@ void FabricGeometry::initialize() { attributes.addAttribute(FabricTypes::subdivisionScheme, FabricTokens::subdivisionScheme); attributes.addAttribute(FabricTypes::material_binding, FabricTokens::material_binding); - if (hasTexcoords) { - attributes.addAttribute(FabricTypes::primvars_st, FabricTokens::primvars_st); + for (uint64_t i = 0; i < texcoordSetCount; i++) { + attributes.addAttribute(FabricTypes::primvars_st, FabricTokens::primvars_st_n[i]); } if (hasNormals) { @@ -156,15 +173,17 @@ void FabricGeometry::initialize() { // Initialize primvars size_t primvarsCount = 0; - size_t primvarIndexSt = 0; size_t primvarIndexNormal = 0; size_t primvarIndexVertexColor = 0; const size_t primvarIndexDisplayColor = primvarsCount++; const size_t primvarIndexDisplayOpacity = primvarsCount++; - if (hasTexcoords) { - primvarIndexSt = primvarsCount++; + std::vector primvarIndexStArray; + primvarIndexStArray.reserve(texcoordSetCount); + + for (uint64_t i = 0; i < texcoordSetCount; i++) { + primvarIndexStArray.push_back(primvarsCount++); } if (hasNormals) { @@ -191,9 +210,9 @@ void FabricGeometry::initialize() { primvarInterpolationsFabric[primvarIndexDisplayColor] = FabricTokens::constant; primvarInterpolationsFabric[primvarIndexDisplayOpacity] = FabricTokens::constant; - if (hasTexcoords) { - primvarsFabric[primvarIndexSt] = FabricTokens::primvars_st; - primvarInterpolationsFabric[primvarIndexSt] = FabricTokens::vertex; + for (uint64_t i = 0; i < texcoordSetCount; i++) { + primvarsFabric[primvarIndexStArray[i]] = FabricTokens::primvars_st_n[i]; + primvarInterpolationsFabric[primvarIndexStArray[i]] = FabricTokens::vertex; } if (hasNormals) { @@ -208,9 +227,9 @@ void FabricGeometry::initialize() { } void FabricGeometry::reset() { - const auto hasTexcoords = _geometryDefinition.hasTexcoords(); const auto hasNormals = _geometryDefinition.hasNormals(); const auto hasVertexColors = _geometryDefinition.hasVertexColors(); + const auto texcoordSetCount = getTexcoordSetCount(_geometryDefinition); auto srw = UsdUtil::getFabricStageReaderWriter(); @@ -243,8 +262,8 @@ void FabricGeometry::reset() { srw.setArrayAttributeSize(_path, FabricTokens::faceVertexIndices, 0); srw.setArrayAttributeSize(_path, FabricTokens::points, 0); - if (hasTexcoords) { - srw.setArrayAttributeSize(_path, FabricTokens::primvars_st, 0); + for (uint64_t i = 0; i < texcoordSetCount; i++) { + srw.setArrayAttributeSize(_path, FabricTokens::primvars_st_n[i], 0); } if (hasNormals) { @@ -264,13 +283,13 @@ void FabricGeometry::setGeometry( const CesiumGltf::Model& model, const CesiumGltf::MeshPrimitive& primitive, bool smoothNormals, - bool hasImagery) { + const std::unordered_map& texcoordIndexMapping, + const std::unordered_map& imageryTexcoordIndexMapping) { if (stageDestroyed()) { return; } - const auto hasTexcoords = _geometryDefinition.hasTexcoords(); const auto hasNormals = _geometryDefinition.hasNormals(); const auto hasVertexColors = _geometryDefinition.hasVertexColors(); @@ -280,8 +299,6 @@ void FabricGeometry::setGeometry( const auto indices = GltfUtil::getIndices(model, primitive, positions); const auto normals = GltfUtil::getNormals(model, primitive, positions, indices, smoothNormals); const auto vertexColors = GltfUtil::getVertexColors(model, primitive, 0); - const auto texcoords_0 = GltfUtil::getTexcoords(model, primitive, 0); - const auto imageryTexcoords = GltfUtil::getImageryTexcoords(model, primitive, 0); const auto extent = GltfUtil::getExtent(model, primitive); const auto faceVertexCounts = GltfUtil::getFaceVertexCounts(indices); @@ -398,14 +415,27 @@ void FabricGeometry::setGeometry( indices.fill(faceVertexIndicesFabric); positions.fill(pointsFabric); - if (hasTexcoords) { - const auto& texcoords = hasImagery ? imageryTexcoords : texcoords_0; - - srw.setArrayAttributeSize(_path, FabricTokens::primvars_st, texcoords.size()); + const auto fillTexcoords = [this, &srw](uint64_t texcoordIndex, const TexcoordsAccessor& texcoords) { + assert(texcoordIndex < _geometryDefinition.getTexcoordSetCount()); - auto stFabric = srw.getArrayAttributeWr(_path, FabricTokens::primvars_st); + if (texcoordIndex >= FabricTokens::MAX_PRIMVAR_ST_COUNT) { + return; + } + const auto& primvarStToken = FabricTokens::primvars_st_n[texcoordIndex]; + srw.setArrayAttributeSize(_path, primvarStToken, texcoords.size()); + auto stFabric = srw.getArrayAttributeWr(_path, primvarStToken); texcoords.fill(stFabric); + }; + + for (const auto& [gltfSetIndex, primvarStIndex] : texcoordIndexMapping) { + const auto texcoords = GltfUtil::getTexcoords(model, primitive, gltfSetIndex); + fillTexcoords(primvarStIndex, texcoords); + } + + for (const auto& [gltfSetIndex, primvarStIndex] : imageryTexcoordIndexMapping) { + const auto texcoords = GltfUtil::getImageryTexcoords(model, primitive, gltfSetIndex); + fillTexcoords(primvarStIndex, texcoords); } if (hasNormals) { diff --git a/src/core/src/FabricGeometryDefinition.cpp b/src/core/src/FabricGeometryDefinition.cpp index 998ff0683..9e5bb7ce0 100644 --- a/src/core/src/FabricGeometryDefinition.cpp +++ b/src/core/src/FabricGeometryDefinition.cpp @@ -15,20 +15,12 @@ FabricGeometryDefinition::FabricGeometryDefinition( const CesiumGltf::Model& model, const CesiumGltf::MeshPrimitive& primitive, bool smoothNormals) { - - const auto hasPrimitiveSt = GltfUtil::hasTexcoords(model, primitive, 0); - const auto hasImagerySt = GltfUtil::hasImageryTexcoords(model, primitive, 0); - const auto materialInfo = GltfUtil::getMaterialInfo(model, primitive); - - _hasTexcoords = hasPrimitiveSt || hasImagerySt; _hasNormals = GltfUtil::hasNormals(model, primitive, smoothNormals); _hasVertexColors = GltfUtil::hasVertexColors(model, primitive, 0); _doubleSided = materialInfo.doubleSided; -} - -bool FabricGeometryDefinition::hasTexcoords() const { - return _hasTexcoords; + _texcoordSetCount = GltfUtil::getTexcoordSetIndexes(model, primitive).size() + + GltfUtil::getImageryTexcoordSetIndexes(model, primitive).size(); } bool FabricGeometryDefinition::hasNormals() const { @@ -43,11 +35,11 @@ bool FabricGeometryDefinition::getDoubleSided() const { return _doubleSided; } -bool FabricGeometryDefinition::operator==(const FabricGeometryDefinition& other) const { - if (_hasTexcoords != other._hasTexcoords) { - return false; - } +[[nodiscard]] uint64_t FabricGeometryDefinition::getTexcoordSetCount() const { + return _texcoordSetCount; +} +bool FabricGeometryDefinition::operator==(const FabricGeometryDefinition& other) const { if (_hasNormals != other._hasNormals) { return false; } @@ -60,6 +52,10 @@ bool FabricGeometryDefinition::operator==(const FabricGeometryDefinition& other) return false; } + if (_texcoordSetCount != other._texcoordSetCount) { + return false; + } + return true; } diff --git a/src/core/src/FabricMaterial.cpp b/src/core/src/FabricMaterial.cpp index f5ccf6cc6..2bb99df4e 100644 --- a/src/core/src/FabricMaterial.cpp +++ b/src/core/src/FabricMaterial.cpp @@ -2,8 +2,10 @@ #include "cesium/omniverse/Context.h" #include "cesium/omniverse/FabricAttributesBuilder.h" +#include "cesium/omniverse/FabricMaterialDefinition.h" #include "cesium/omniverse/FabricResourceManager.h" #include "cesium/omniverse/FabricUtil.h" +#include "cesium/omniverse/LoggerSink.h" #include "cesium/omniverse/Tokens.h" #include "cesium/omniverse/UsdUtil.h" @@ -12,14 +14,33 @@ namespace cesium::omniverse { +namespace { +uint64_t getBaseColorTextureCount(const FabricMaterialDefinition& materialDefinition) { + auto baseColorTextureCount = materialDefinition.getBaseColorTextureCount(); + + if (baseColorTextureCount > FabricTokens::MAX_TEXTURE_LAYER_COUNT) { + CESIUM_LOG_WARN( + "Number of textures ({}) exceeds maximum texture layer count ({}). Excess textures will be ignored.", + baseColorTextureCount, + FabricTokens::MAX_TEXTURE_LAYER_COUNT); + } + + baseColorTextureCount = glm::min(baseColorTextureCount, FabricTokens::MAX_TEXTURE_LAYER_COUNT); + + return baseColorTextureCount; +} +} // namespace + FabricMaterial::FabricMaterial( const omni::fabric::Path& path, const FabricMaterialDefinition& materialDefinition, const pxr::TfToken& defaultTextureAssetPathToken, + const pxr::TfToken& defaultTransparentTextureAssetPathToken, long stageId) : _materialPath(path) , _materialDefinition(materialDefinition) , _defaultTextureAssetPathToken(defaultTextureAssetPathToken) + , _defaultTransparentTextureAssetPathToken(defaultTransparentTextureAssetPathToken) , _stageId(stageId) { if (stageDestroyed()) { @@ -38,8 +59,12 @@ FabricMaterial::~FabricMaterial() { FabricUtil::destroyPrim(_materialPath); FabricUtil::destroyPrim(_shaderPath); - if (_materialDefinition.hasBaseColorTexture()) { + if (_materialDefinition.hasBaseColorTextures()) { FabricUtil::destroyPrim(_baseColorTexturePath); + + for (const auto& baseColorTextureLayerPath : _baseColorTextureLayerPaths) { + FabricUtil::destroyPrim(baseColorTextureLayerPath); + } } } @@ -62,25 +87,39 @@ const FabricMaterialDefinition& FabricMaterial::getMaterialDefinition() const { } void FabricMaterial::initialize() { - const auto hasBaseColorTexture = _materialDefinition.hasBaseColorTexture(); - const auto& materialPath = _materialPath; - const auto shaderPath = FabricUtil::joinPaths(materialPath, FabricTokens::Shader); - const auto baseColorTexturePath = FabricUtil::joinPaths(materialPath, FabricTokens::baseColorTexture); + createMaterial(materialPath); + auto& fabricResourceManager = FabricResourceManager::getInstance(); + fabricResourceManager.retainPath(materialPath); - _materialPath = materialPath; + const auto shaderPath = FabricUtil::joinPaths(materialPath, FabricTokens::Shader); + createShader(shaderPath, materialPath); + fabricResourceManager.retainPath(shaderPath); _shaderPath = shaderPath; - _baseColorTexturePath = baseColorTexturePath; - - FabricResourceManager::getInstance().retainPath(materialPath); - FabricResourceManager::getInstance().retainPath(shaderPath); - FabricResourceManager::getInstance().retainPath(baseColorTexturePath); - createMaterial(materialPath); - createShader(shaderPath, materialPath); + const auto baseColorTextureCount = getBaseColorTextureCount(_materialDefinition); - if (hasBaseColorTexture) { + if (baseColorTextureCount == 1) { + const auto baseColorTexturePath = FabricUtil::joinPaths(materialPath, FabricTokens::base_color_texture); + fabricResourceManager.retainPath(baseColorTexturePath); + _baseColorTexturePath = baseColorTexturePath; createTexture(baseColorTexturePath, shaderPath, FabricTokens::inputs_base_color_texture); + } else if (baseColorTextureCount > 1) { + const auto baseColorTexturePath = FabricUtil::joinPaths(materialPath, FabricTokens::base_color_texture_array); + fabricResourceManager.retainPath(baseColorTexturePath); + _baseColorTexturePath = baseColorTexturePath; + createTextureArray( + baseColorTexturePath, shaderPath, FabricTokens::inputs_base_color_texture, baseColorTextureCount); + + _baseColorTextureLayerPaths.reserve(baseColorTextureCount); + for (uint64_t i = 0; i < baseColorTextureCount; i++) { + const auto& baseColorTextureToken = FabricTokens::base_color_texture_n[i]; + const auto& inputsBaseColorTextureToken = FabricTokens::inputs_texture_n[i]; + const auto baseColorTextureLayerPath = FabricUtil::joinPaths(materialPath, baseColorTextureToken); + createTexture(baseColorTextureLayerPath, baseColorTexturePath, inputsBaseColorTextureToken); + fabricResourceManager.retainPath(baseColorTextureLayerPath); + _baseColorTextureLayerPaths.push_back(baseColorTextureLayerPath); + } } } @@ -224,9 +263,53 @@ void FabricMaterial::createTexture( srw.createConnection(shaderPath, shaderInput, omni::fabric::Connection{texturePath, FabricTokens::outputs_out}); } +void FabricMaterial::createTextureArray( + const omni::fabric::Path& texturePath, + const omni::fabric::Path& shaderPath, + const omni::fabric::Token& shaderInput, + uint64_t textureCount) { + auto srw = UsdUtil::getFabricStageReaderWriter(); + + srw.createPrim(texturePath); + + FabricAttributesBuilder attributes; + + // clang-format off + attributes.addAttribute(FabricTypes::inputs_texture_count, FabricTokens::inputs_texture_count); + attributes.addAttribute(FabricTypes::inputs_excludeFromWhiteMode, FabricTokens::inputs_excludeFromWhiteMode); + attributes.addAttribute(FabricTypes::outputs_out, FabricTokens::outputs_out); + attributes.addAttribute(FabricTypes::info_implementationSource, FabricTokens::info_implementationSource); + attributes.addAttribute(FabricTypes::info_mdl_sourceAsset, FabricTokens::info_mdl_sourceAsset); + attributes.addAttribute(FabricTypes::info_mdl_sourceAsset_subIdentifier, FabricTokens::info_mdl_sourceAsset_subIdentifier); + attributes.addAttribute(FabricTypes::_sdrMetadata, FabricTokens::_sdrMetadata); + attributes.addAttribute(FabricTypes::Shader, FabricTokens::Shader); + attributes.addAttribute(FabricTypes::_cesium_tilesetId, FabricTokens::_cesium_tilesetId); + // clang-format on + + attributes.createAttributes(texturePath); + + // clang-format off + auto inputsTextureCountFabric = srw.getAttributeWr(texturePath, FabricTokens::inputs_texture_count); + auto inputsExcludeFromWhiteModeFabric = srw.getAttributeWr(texturePath, FabricTokens::inputs_excludeFromWhiteMode); + auto infoImplementationSourceFabric = srw.getAttributeWr(texturePath, FabricTokens::info_implementationSource); + auto infoMdlSourceAssetFabric = srw.getAttributeWr(texturePath, FabricTokens::info_mdl_sourceAsset); + auto infoMdlSourceAssetSubIdentifierFabric = srw.getAttributeWr(texturePath, FabricTokens::info_mdl_sourceAsset_subIdentifier); + // clang-format on + + *inputsTextureCountFabric = static_cast(textureCount); + *inputsExcludeFromWhiteModeFabric = false; + *infoImplementationSourceFabric = FabricTokens::sourceAsset; + infoMdlSourceAssetFabric->assetPath = Context::instance().getCesiumMdlPathToken(); + infoMdlSourceAssetFabric->resolvedPath = pxr::TfToken(); + *infoMdlSourceAssetSubIdentifierFabric = FabricTokens::cesium_texture_array_lookup; + + // Create connection from shader to texture. + srw.createConnection(shaderPath, shaderInput, omni::fabric::Connection{texturePath, FabricTokens::outputs_out}); +} + void FabricMaterial::reset() { clearMaterial(); - clearBaseColorTexture(); + clearBaseColorTextures(); } void FabricMaterial::setMaterial(int64_t tilesetId, const MaterialInfo& materialInfo) { @@ -240,32 +323,64 @@ void FabricMaterial::setMaterial(int64_t tilesetId, const MaterialInfo& material setTilesetId(tilesetId); } -void FabricMaterial::setBaseColorTexture(const pxr::TfToken& textureAssetPathToken, const TextureInfo& textureInfo) { +void FabricMaterial::setBaseColorTexture( + const pxr::TfToken& textureAssetPathToken, + const TextureInfo& textureInfo, + uint64_t texcoordIndex, + uint64_t textureIndex) { if (stageDestroyed()) { return; } - if (!_materialDefinition.hasBaseColorTexture()) { + if (!_materialDefinition.hasBaseColorTextures()) { + return; + } + + if (textureIndex >= FabricTokens::MAX_TEXTURE_LAYER_COUNT) { return; } - setTextureValues(_baseColorTexturePath, textureAssetPathToken, textureInfo); + if (_baseColorTextureLayerPaths.empty()) { + assert(textureIndex == 0); + setTextureValues(_baseColorTexturePath, textureAssetPathToken, textureInfo, texcoordIndex); + } else { + setTextureValues(_baseColorTextureLayerPaths[textureIndex], textureAssetPathToken, textureInfo, texcoordIndex); + } } void FabricMaterial::clearMaterial() { setMaterial(NO_TILESET_ID, GltfUtil::getDefaultMaterialInfo()); } -void FabricMaterial::clearBaseColorTexture() { - setBaseColorTexture(_defaultTextureAssetPathToken, GltfUtil::getDefaultTextureInfo()); +void FabricMaterial::clearBaseColorTextures() { + if (!_materialDefinition.hasBaseColorTextures()) { + return; + } + + if (_baseColorTextureLayerPaths.empty()) { + clearBaseColorTexture(0); + } else { + for (uint64_t i = 0; i < _baseColorTextureLayerPaths.size(); i++) { + clearBaseColorTexture(i); + } + } +} + +void FabricMaterial::clearBaseColorTexture(uint64_t textureIndex) { + const auto& token = textureIndex == 0 ? _defaultTextureAssetPathToken : _defaultTransparentTextureAssetPathToken; + setBaseColorTexture(token, GltfUtil::getDefaultTextureInfo(), 0, textureIndex); } void FabricMaterial::setTilesetId(int64_t tilesetId) { FabricUtil::setTilesetId(_materialPath, tilesetId); FabricUtil::setTilesetId(_shaderPath, tilesetId); - if (_materialDefinition.hasBaseColorTexture()) { + if (_materialDefinition.hasBaseColorTextures()) { FabricUtil::setTilesetId(_baseColorTexturePath, tilesetId); + + for (const auto& baseColorTextureLayerPath : _baseColorTextureLayerPaths) { + FabricUtil::setTilesetId(baseColorTextureLayerPath, tilesetId); + } } } @@ -292,7 +407,13 @@ void FabricMaterial::setShaderValues(const omni::fabric::Path& shaderPath, const void FabricMaterial::setTextureValues( const omni::fabric::Path& texturePath, const pxr::TfToken& textureAssetPathToken, - const TextureInfo& textureInfo) { + const TextureInfo& textureInfo, + uint64_t texcoordIndex) { + + if (texcoordIndex >= FabricTokens::MAX_TEXTURE_LAYER_COUNT) { + return; + } + auto srw = UsdUtil::getFabricStageReaderWriter(); auto offset = textureInfo.offset; @@ -317,7 +438,7 @@ void FabricMaterial::setTextureValues( textureFabric->assetPath = textureAssetPathToken; textureFabric->resolvedPath = pxr::TfToken(); - *texCoordIndexFabric = static_cast(textureInfo.setIndex); + *texCoordIndexFabric = static_cast(texcoordIndex); *wrapSFabric = textureInfo.wrapS; *wrapTFabric = textureInfo.wrapT; *offsetFabric = UsdUtil::glmToUsdVector(glm::fvec2(offset)); diff --git a/src/core/src/FabricMaterialDefinition.cpp b/src/core/src/FabricMaterialDefinition.cpp index 8ef742c3e..0550c2270 100644 --- a/src/core/src/FabricMaterialDefinition.cpp +++ b/src/core/src/FabricMaterialDefinition.cpp @@ -13,24 +13,29 @@ namespace cesium::omniverse { FabricMaterialDefinition::FabricMaterialDefinition( const MaterialInfo& materialInfo, - bool hasImagery, + uint64_t imageryLayerCount, bool disableTextures) { - _hasBaseColorTexture = materialInfo.baseColorTexture.has_value(); + uint64_t baseColorTextureCount = 0; - if (hasImagery) { - _hasBaseColorTexture = true; - } + if (!disableTextures) { + if (materialInfo.baseColorTexture.has_value()) { + baseColorTextureCount++; + } - if (disableTextures) { - _hasBaseColorTexture = false; + baseColorTextureCount += imageryLayerCount; } _hasVertexColors = materialInfo.hasVertexColors; + _baseColorTextureCount = baseColorTextureCount; +} + +uint64_t FabricMaterialDefinition::getBaseColorTextureCount() const { + return _baseColorTextureCount; } -bool FabricMaterialDefinition::hasBaseColorTexture() const { - return _hasBaseColorTexture; +bool FabricMaterialDefinition::hasBaseColorTextures() const { + return _baseColorTextureCount > 0; } bool FabricMaterialDefinition::hasVertexColors() const { @@ -39,11 +44,11 @@ bool FabricMaterialDefinition::hasVertexColors() const { // In C++ 20 we can use the default equality comparison (= default) bool FabricMaterialDefinition::operator==(const FabricMaterialDefinition& other) const { - if (_hasBaseColorTexture != other._hasBaseColorTexture) { + if (_hasVertexColors != other._hasVertexColors) { return false; } - if (_hasVertexColors != other._hasVertexColors) { + if (_baseColorTextureCount != other._baseColorTextureCount) { return false; } diff --git a/src/core/src/FabricMaterialPool.cpp b/src/core/src/FabricMaterialPool.cpp index edb34015d..34e0ff682 100644 --- a/src/core/src/FabricMaterialPool.cpp +++ b/src/core/src/FabricMaterialPool.cpp @@ -9,11 +9,13 @@ FabricMaterialPool::FabricMaterialPool( const FabricMaterialDefinition& materialDefinition, uint64_t initialCapacity, const pxr::TfToken& defaultTextureAssetPathToken, + const pxr::TfToken& defaultTransparentTextureAssetPathToken, long stageId) : ObjectPool() , _poolId(poolId) , _materialDefinition(materialDefinition) , _defaultTextureAssetPathToken(defaultTextureAssetPathToken) + , _defaultTransparentTextureAssetPathToken(defaultTransparentTextureAssetPathToken) , _stageId(stageId) { setCapacity(initialCapacity); } @@ -25,7 +27,8 @@ const FabricMaterialDefinition& FabricMaterialPool::getMaterialDefinition() cons std::shared_ptr FabricMaterialPool::createObject(uint64_t objectId) { const auto pathStr = fmt::format("/fabric_material_pool_{}_object_{}", _poolId, objectId); const auto path = omni::fabric::Path(pathStr.c_str()); - return std::make_shared(path, _materialDefinition, _defaultTextureAssetPathToken, _stageId); + return std::make_shared( + path, _materialDefinition, _defaultTextureAssetPathToken, _defaultTransparentTextureAssetPathToken, _stageId); } void FabricMaterialPool::setActive(std::shared_ptr material, bool active) { diff --git a/src/core/src/FabricPrepareRenderResources.cpp b/src/core/src/FabricPrepareRenderResources.cpp index a93838e67..6fb3e0cc1 100644 --- a/src/core/src/FabricPrepareRenderResources.cpp +++ b/src/core/src/FabricPrepareRenderResources.cpp @@ -53,9 +53,25 @@ struct TileLoadThreadResult { std::vector meshes; std::vector fabricMeshes; glm::dmat4 tileTransform; - bool hasImagery; }; +bool hasBaseColorTextureGltf(const FabricMesh& fabricMesh) { + return fabricMesh.material->getMaterialDefinition().hasBaseColorTextures() && + fabricMesh.materialInfo.baseColorTexture.has_value(); +} + +uint64_t getBaseColorTextureIndexForGltf() { + return 0; +} + +uint64_t getBaseColorTextureIndexForImagery(const FabricMesh& fabricMesh, uint64_t imageryIndex) { + if (hasBaseColorTextureGltf(fabricMesh)) { + return imageryIndex + 1; + } + + return imageryIndex; +} + std::vector gatherMeshes(const OmniTileset& tileset, const glm::dmat4& tileTransform, const CesiumGltf::Model& model) { CESIUM_TRACE("FabricPrepareRenderResources::gatherMeshes"); @@ -99,7 +115,7 @@ gatherMeshes(const OmniTileset& tileset, const glm::dmat4& tileTransform, const std::vector acquireFabricMeshes( const CesiumGltf::Model& model, const std::vector& meshes, - bool hasImagery, + uint64_t imageryLayerCount, const OmniTileset& tileset) { CESIUM_TRACE("FabricPrepareRenderResources::acquireFabricMeshes"); std::vector fabricMeshes; @@ -117,24 +133,34 @@ std::vector acquireFabricMeshes( fabricResourceManager.acquireGeometry(model, primitive, mesh.smoothNormals, stageId); fabricMesh.geometry = fabricGeometry; - const auto shouldAcquireMaterial = - FabricResourceManager::getInstance().shouldAcquireMaterial(primitive, hasImagery, tilesetMaterialPath); + const auto shouldAcquireMaterial = FabricResourceManager::getInstance().shouldAcquireMaterial( + primitive, imageryLayerCount > 0, tilesetMaterialPath); if (shouldAcquireMaterial) { const auto materialInfo = GltfUtil::getMaterialInfo(model, primitive); const auto fabricMaterial = - fabricResourceManager.acquireMaterial(materialInfo, hasImagery, stageId, tileset.getTilesetId()); + fabricResourceManager.acquireMaterial(materialInfo, imageryLayerCount, stageId, tileset.getTilesetId()); fabricMesh.material = fabricMaterial; fabricMesh.materialInfo = materialInfo; - if (fabricMaterial->getMaterialDefinition().hasBaseColorTexture() && - materialInfo.baseColorTexture.has_value()) { - const auto fabricTexture = fabricResourceManager.acquireTexture(); - fabricMesh.baseColorTexture = fabricTexture; + if (hasBaseColorTextureGltf(fabricMesh)) { + fabricMesh.baseColorTexture = fabricResourceManager.acquireTexture(); } } + + // Map glTF texcoord set index to primvar st index + const auto texcoordSetIndexes = GltfUtil::getTexcoordSetIndexes(model, primitive); + const auto imageryTexcoordSetIndexes = GltfUtil::getImageryTexcoordSetIndexes(model, primitive); + + uint64_t primvarStIndex = 0; + for (const auto gltfSetIndex : texcoordSetIndexes) { + fabricMesh.texcoordIndexMapping[gltfSetIndex] = primvarStIndex++; + } + for (const auto gltfSetIndex : imageryTexcoordSetIndexes) { + fabricMesh.imageryTexcoordIndexMapping[gltfSetIndex] = primvarStIndex++; + } } return fabricMeshes; @@ -151,7 +177,7 @@ void setFabricTextures( auto& mesh = fabricMeshes[i]; auto& baseColorTexture = mesh.baseColorTexture; - if (baseColorTexture != nullptr) { + if (hasBaseColorTextureGltf(mesh)) { const auto baseColorTextureImage = GltfUtil::getBaseColorTextureImage(model, primitive); baseColorTexture->setImage(*baseColorTextureImage); } @@ -162,7 +188,6 @@ void setFabricMeshes( const CesiumGltf::Model& model, const std::vector& meshes, std::vector& fabricMeshes, - bool hasImagery, const OmniTileset& tileset) { CESIUM_TRACE("FabricPrepareRenderResources::setFabricMeshes"); for (size_t i = 0; i < meshes.size(); i++) { @@ -184,15 +209,19 @@ void setFabricMeshes( model, primitive, meshInfo.smoothNormals, - hasImagery); + mesh.texcoordIndexMapping, + mesh.imageryTexcoordIndexMapping); if (material != nullptr) { material->setMaterial(meshInfo.tilesetId, materialInfo); geometry->setMaterial(material->getPath()); - if (baseColorTexture != nullptr && materialInfo.baseColorTexture.has_value()) { - material->setBaseColorTexture( - baseColorTexture->getAssetPathToken(), materialInfo.baseColorTexture.value()); + if (hasBaseColorTextureGltf(mesh)) { + const auto& textureInfo = materialInfo.baseColorTexture.value(); + const auto texcoordIndex = mesh.texcoordIndexMapping[textureInfo.setIndex]; + const auto textureIndex = getBaseColorTextureIndexForGltf(); + const auto& textureAssetPath = baseColorTexture->getAssetPathToken(); + material->setBaseColorTexture(textureAssetPath, textureInfo, texcoordIndex, textureIndex); } } else if (!tilesetMaterialPath.IsEmpty()) { geometry->setMaterial(FabricUtil::toFabricPath(tilesetMaterialPath)); @@ -244,7 +273,11 @@ FabricPrepareRenderResources::prepareInLoadThread( Cesium3DTilesSelection::TileLoadResultAndRenderResources{std::move(tileLoadResult), nullptr}); } - const auto hasImagery = tileLoadResult.rasterOverlayDetails.has_value(); + // We don't know how many imagery layers actually overlap this tile until attachRasterInMainThread is called + // but at least we have an upper bound. Unused texture slots are initialized with a 1x1 transparent pixel so + // blending still works. + const auto overlapsImagery = tileLoadResult.rasterOverlayDetails.has_value(); + const auto imageryLayerCount = overlapsImagery ? _tileset->getImageryLayerCount() : 0; auto meshes = gatherMeshes(*_tileset, transform, *pModel); @@ -255,25 +288,27 @@ FabricPrepareRenderResources::prepareInLoadThread( }; return asyncSystem - .runInMainThread( - [this, hasImagery, meshes = std::move(meshes), tileLoadResult = std::move(tileLoadResult)]() mutable { - if (!tilesetExists()) { - return IntermediateLoadThreadResult{ - std::move(tileLoadResult), - {}, - {}, - }; - } - - const auto pModel = std::get_if(&tileLoadResult.contentKind); - auto fabricMeshes = acquireFabricMeshes(*pModel, meshes, hasImagery, *_tileset); + .runInMainThread([this, + imageryLayerCount, + meshes = std::move(meshes), + tileLoadResult = std::move(tileLoadResult)]() mutable { + if (!tilesetExists()) { return IntermediateLoadThreadResult{ std::move(tileLoadResult), - std::move(meshes), - std::move(fabricMeshes), + {}, + {}, }; - }) - .thenInWorkerThread([this, transform, hasImagery](IntermediateLoadThreadResult&& workerResult) mutable { + } + + const auto pModel = std::get_if(&tileLoadResult.contentKind); + auto fabricMeshes = acquireFabricMeshes(*pModel, meshes, imageryLayerCount, *_tileset); + return IntermediateLoadThreadResult{ + std::move(tileLoadResult), + std::move(meshes), + std::move(fabricMeshes), + }; + }) + .thenInWorkerThread([this, transform](IntermediateLoadThreadResult&& workerResult) mutable { auto tileLoadResult = std::move(workerResult.tileLoadResult); auto meshes = std::move(workerResult.meshes); auto fabricMeshes = std::move(workerResult.fabricMeshes); @@ -289,7 +324,6 @@ FabricPrepareRenderResources::prepareInLoadThread( std::move(meshes), std::move(fabricMeshes), transform, - hasImagery, }, }; }); @@ -305,7 +339,6 @@ void* FabricPrepareRenderResources::prepareInMainThread(Cesium3DTilesSelection:: const auto& meshes = pTileLoadThreadResult->meshes; auto& fabricMeshes = pTileLoadThreadResult->fabricMeshes; - const auto hasImagery = pTileLoadThreadResult->hasImagery; const auto& tileTransform = pTileLoadThreadResult->tileTransform; const auto& content = tile.getContent(); @@ -317,7 +350,7 @@ void* FabricPrepareRenderResources::prepareInMainThread(Cesium3DTilesSelection:: const auto& model = pRenderContent->getModel(); if (tilesetExists()) { - setFabricMeshes(model, meshes, fabricMeshes, hasImagery, *_tileset); + setFabricMeshes(model, meshes, fabricMeshes, *_tileset); } return new TileRenderResources{ @@ -426,21 +459,29 @@ void FabricPrepareRenderResources::attachRasterInMainThread( return; } + auto imageryIndex = _tileset->findImageryIndex(rasterTile.getOverlay()); + if (!imageryIndex.has_value()) { + return; + } + for (const auto& mesh : pTileRenderResources->fabricMeshes) { auto& material = mesh.material; if (material != nullptr) { + const auto gltfSetIndex = static_cast(overlayTextureCoordinateID); const auto textureInfo = TextureInfo{ translation, 0.0, scale, - static_cast(overlayTextureCoordinateID), + gltfSetIndex, CesiumGltf::Sampler::WrapS::CLAMP_TO_EDGE, CesiumGltf::Sampler::WrapT::CLAMP_TO_EDGE, false, }; - // Replace the original base color texture with the imagery - material->setBaseColorTexture(texture->getAssetPathToken(), textureInfo); + const auto texcoordIndex = mesh.imageryTexcoordIndexMapping.at(gltfSetIndex); + const auto textureIndex = getBaseColorTextureIndexForImagery(mesh, imageryIndex.value()); + const auto& textureAssetPath = texture->getAssetPathToken(); + material->setBaseColorTexture(textureAssetPath, textureInfo, texcoordIndex, textureIndex); } } } @@ -448,7 +489,7 @@ void FabricPrepareRenderResources::attachRasterInMainThread( void FabricPrepareRenderResources::detachRasterInMainThread( const Cesium3DTilesSelection::Tile& tile, [[maybe_unused]] int32_t overlayTextureCoordinateID, - [[maybe_unused]] const Cesium3DTilesSelection::RasterOverlayTile& rasterTile, + const Cesium3DTilesSelection::RasterOverlayTile& rasterTile, [[maybe_unused]] void* pMainThreadRendererResources) noexcept { auto& content = tile.getContent(); @@ -466,19 +507,16 @@ void FabricPrepareRenderResources::detachRasterInMainThread( return; } + auto imageryIndex = _tileset->findImageryIndex(rasterTile.getOverlay()); + if (!imageryIndex.has_value()) { + return; + } + for (const auto& mesh : pTileRenderResources->fabricMeshes) { auto& material = mesh.material; - const auto& baseColorTexture = mesh.baseColorTexture; - const auto& materialInfo = mesh.materialInfo; - if (material != nullptr) { - if (baseColorTexture != nullptr && materialInfo.baseColorTexture.has_value()) { - // Switch back to the original base color texture - material->setBaseColorTexture( - baseColorTexture->getAssetPathToken(), materialInfo.baseColorTexture.value()); - } else { - material->clearBaseColorTexture(); - } + const auto textureIndex = getBaseColorTextureIndexForImagery(mesh, imageryIndex.value()); + material->clearBaseColorTexture(textureIndex); } } } diff --git a/src/core/src/FabricResourceManager.cpp b/src/core/src/FabricResourceManager.cpp index c254c89f7..2dbbebb41 100644 --- a/src/core/src/FabricResourceManager.cpp +++ b/src/core/src/FabricResourceManager.cpp @@ -23,16 +23,26 @@ template void removePool(std::vector& pools, const T& pool) { pools.end()); } +std::unique_ptr +createSinglePixelTexture(const std::string& name, std::array bytes) { + const auto size = carb::Uint2{1, 1}; + auto defaultTexture = std::make_unique(name); + defaultTexture->setBytesData(bytes.data(), size, omni::ui::kAutoCalculateStride, carb::Format::eRGBA8_SRGB); + return defaultTexture; +} + +const std::string DEFAULT_TEXTURE_NAME = "fabric_default_texture"; +const std::string DEFAULT_TRANSPARENT_TEXTURE_NAME = "fabric_default_transparent_texture"; + } // namespace FabricResourceManager::FabricResourceManager() { - const auto defaultTextureName = "fabric_default_texture"; - _defaultTextureAssetPathToken = UsdUtil::getDynamicTextureProviderAssetPathToken(defaultTextureName); - _defaultTexture = std::make_unique(defaultTextureName); + _defaultTexture = createSinglePixelTexture(DEFAULT_TEXTURE_NAME, {{255, 255, 255, 255}}); + _defaultTextureAssetPathToken = UsdUtil::getDynamicTextureProviderAssetPathToken(DEFAULT_TEXTURE_NAME); - const auto bytes = std::array{{255, 255, 255, 255}}; - const auto size = carb::Uint2{1, 1}; - _defaultTexture->setBytesData(bytes.data(), size, omni::ui::kAutoCalculateStride, carb::Format::eRGBA8_SRGB); + _defaultTransparentTexture = createSinglePixelTexture(DEFAULT_TRANSPARENT_TEXTURE_NAME, {{255, 255, 255, 0}}); + _defaultTransparentTextureAssetPathToken = + UsdUtil::getDynamicTextureProviderAssetPathToken(DEFAULT_TRANSPARENT_TEXTURE_NAME); } FabricResourceManager::~FabricResourceManager() = default; @@ -80,7 +90,7 @@ std::shared_ptr FabricResourceManager::acquireGeometry( } bool useSharedMaterial(const FabricMaterialDefinition& materialDefinition) { - if (materialDefinition.hasBaseColorTexture()) { + if (materialDefinition.hasBaseColorTextures()) { return false; } @@ -91,7 +101,8 @@ std::shared_ptr FabricResourceManager::createMaterial(const FabricMaterialDefinition& materialDefinition, long stageId) { const auto pathStr = fmt::format("/fabric_material_{}", getNextMaterialId()); const auto path = omni::fabric::Path(pathStr.c_str()); - return std::make_shared(path, materialDefinition, _defaultTextureAssetPathToken, stageId); + return std::make_shared( + path, materialDefinition, _defaultTextureAssetPathToken, _defaultTransparentTextureAssetPathToken, stageId); } void FabricResourceManager::removeSharedMaterial(const SharedMaterial& sharedMaterial) { @@ -163,10 +174,10 @@ void FabricResourceManager::releaseSharedMaterial(const std::shared_ptr FabricResourceManager::acquireMaterial( const MaterialInfo& materialInfo, - bool hasImagery, + uint64_t imageryLayerCount, long stageId, int64_t tilesetId) { - FabricMaterialDefinition materialDefinition(materialInfo, hasImagery, _disableTextures); + FabricMaterialDefinition materialDefinition(materialInfo, imageryLayerCount, _disableTextures); if (useSharedMaterial(materialDefinition)) { return acquireSharedMaterial(materialInfo, materialDefinition, stageId, tilesetId); @@ -341,7 +352,12 @@ FabricResourceManager::createGeometryPool(const FabricGeometryDefinition& geomet std::shared_ptr FabricResourceManager::createMaterialPool(const FabricMaterialDefinition& materialDefinition, long stageId) { return _materialPools.emplace_back(std::make_shared( - getNextPoolId(), materialDefinition, _materialPoolInitialCapacity, _defaultTextureAssetPathToken, stageId)); + getNextPoolId(), + materialDefinition, + _materialPoolInitialCapacity, + _defaultTextureAssetPathToken, + _defaultTransparentTextureAssetPathToken, + stageId)); } std::shared_ptr FabricResourceManager::createTexturePool() { diff --git a/src/core/src/GltfUtil.cpp b/src/core/src/GltfUtil.cpp index f6577ea4c..bbbd52212 100644 --- a/src/core/src/GltfUtil.cpp +++ b/src/core/src/GltfUtil.cpp @@ -1,5 +1,7 @@ #include "cesium/omniverse/GltfUtil.h" +#include "cesium/omniverse/LoggerSink.h" + #ifdef CESIUM_OMNI_MSVC #pragma push_macro("OPAQUE") #undef OPAQUE @@ -12,7 +14,9 @@ #include #include +#include #include +#include namespace cesium::omniverse::GltfUtil { @@ -312,6 +316,25 @@ const CesiumGltf::ImageCesium& getImageCesium(const CesiumGltf::Model& model, co return image.cesium; } +std::pair parseAttributeName(const std::string& attributeName) { + const auto regex = std::regex("^([a-zA-Z_]*)(_([1-9]\\d*|0))?$"); + + std::string semantic; + std::string setIndex; + + std::smatch matches; + + if (std::regex_match(attributeName, matches, regex)) { + semantic = matches[1]; + setIndex = matches[3]; + } + + uint64_t setIndexU64 = 0; + std::from_chars(setIndex.data(), setIndex.data() + setIndex.size(), setIndexU64); + + return std::make_pair(semantic, setIndexU64); +} + } // namespace PositionsAccessor getPositions(const CesiumGltf::Model& model, const CesiumGltf::MeshPrimitive& primitive) { @@ -540,6 +563,38 @@ bool hasImageryTexcoords( CesiumGltf::AccessorViewStatus::Valid; } +std::vector +getTexcoordSetIndexes(const CesiumGltf::Model& model, const CesiumGltf::MeshPrimitive& primitive) { + auto setIndexes = std::vector(); + + for (const auto& attribute : primitive.attributes) { + const auto [semantic, setIndex] = parseAttributeName(attribute.first); + if (semantic == "TEXCOORD") { + if (hasTexcoords(model, primitive, setIndex)) { + setIndexes.push_back(setIndex); + } + } + } + + return setIndexes; +} + +std::vector +getImageryTexcoordSetIndexes(const CesiumGltf::Model& model, const CesiumGltf::MeshPrimitive& primitive) { + auto setIndexes = std::vector(); + + for (const auto& attribute : primitive.attributes) { + const auto [semantic, setIndex] = parseAttributeName(attribute.first); + if (semantic == "_CESIUMOVERLAY") { + if (hasImageryTexcoords(model, primitive, setIndex)) { + setIndexes.push_back(setIndex); + } + } + } + + return setIndexes; +} + bool hasVertexColors(const CesiumGltf::Model& model, const CesiumGltf::MeshPrimitive& primitive, uint64_t setIndex) { return getVertexColors(model, primitive, setIndex).size() > 0; } diff --git a/src/core/src/OmniTileset.cpp b/src/core/src/OmniTileset.cpp index 201c9f6d1..ba137a757 100644 --- a/src/core/src/OmniTileset.cpp +++ b/src/core/src/OmniTileset.cpp @@ -411,6 +411,23 @@ void OmniTileset::addImageryIon(const pxr::SdfPath& imageryPath) { _tileset->getOverlays().add(ionRasterOverlay); } +std::optional OmniTileset::findImageryIndex(const Cesium3DTilesSelection::RasterOverlay& overlay) const { + uint64_t overlayIndex = 0; + for (const auto& pOverlay : _tileset->getOverlays()) { + if (&overlay == pOverlay.get()) { + return overlayIndex; + } + + overlayIndex++; + } + + return std::nullopt; +} + +uint64_t OmniTileset::getImageryLayerCount() const { + return _tileset->getOverlays().size(); +} + void OmniTileset::onUpdateFrame(const std::vector& viewports) { if (!UsdUtil::primExists(_tilesetPath)) { // TfNotice can be slow, and sometimes we get a frame or two before we actually get a chance to react on it.