From f9d5eddaebaaca0c706b6d44acb684d6301d9e65 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Mon, 16 Oct 2023 16:54:47 -0400 Subject: [PATCH] Get property texture picking to work --- Config/Engine.ini | 3 +- .../Private/CesiumFeatureIdSet.cpp | 53 ++++++++ .../Private/CesiumFeatureIdTexture.cpp | 4 +- .../Private/CesiumGltfComponent.cpp | 103 +++++++------- .../Private/CesiumGltfPrimitiveComponent.h | 40 ++++-- .../CesiumMetadataPickingBlueprintLibrary.cpp | 64 ++------- .../Private/CesiumPrimitiveFeatures.cpp | 14 ++ .../Private/CesiumPropertyTexture.cpp | 24 ++-- .../Private/CesiumPropertyTextureProperty.cpp | 4 +- .../Private/CesiumRasterOverlays.h | 2 +- Source/CesiumRuntime/Private/LoadGltfResult.h | 126 +++++++++++++----- .../CesiumRuntime/Public/CesiumFeatureIdSet.h | 30 ++++- .../Public/CesiumPrimitiveFeatures.h | 20 ++- .../Public/CesiumPropertyTexture.h | 10 +- 14 files changed, 318 insertions(+), 179 deletions(-) diff --git a/Config/Engine.ini b/Config/Engine.ini index 8cb4e5284..539b92b30 100644 --- a/Config/Engine.ini +++ b/Config/Engine.ini @@ -85,8 +85,7 @@ RunningThreadedRequestLimit=100 # EXT_feature_metadata -> EXT_structural_metadata changes # Deprecate the old type enum. Unfortunately, there's no way to redirect it to a CesiumMetadataValueType struct. -+EnumRedirects=(OldName="ECesiumMetadataTrueType", NewName="ECesiumMetadataTrueType_DEPRECATED", ValueChanges= - (("None","None_DEPRECATED"),("Int8","Int8_DEPRECATED"),("Uint8","Uint8_DEPRECATED"),("Int16","Int16_DEPRECATED"),("Uint16","Uint16_DEPRECATED"),("Int32","Int32_DEPRECATED"),("Uint32","Uint32_DEPRECATED"),("Int64","Int64_DEPRECATED"),("Uint64","Uint64_DEPRECATED"),("Float32","Float32_DEPRECATED"),("Float64","Float64_DEPRECATED"),("Boolean","Boolean_DEPRECATED"),("Enum","Enum_DEPRECATED"),("String","String_DEPRECATED"),("Array","Array_DEPRECATED"))) ++EnumRedirects=(OldName="ECesiumMetadataTrueType", NewName="ECesiumMetadataTrueType_DEPRECATED", ValueChanges=(("None","None_DEPRECATED"),("Int8","Int8_DEPRECATED"),("Uint8","Uint8_DEPRECATED"),("Int16","Int16_DEPRECATED"),("Uint16","Uint16_DEPRECATED"),("Int32","Int32_DEPRECATED"),("Uint32","Uint32_DEPRECATED"),("Int64","Int64_DEPRECATED"),("Uint64","Uint64_DEPRECATED"),("Float32","Float32_DEPRECATED"),("Float64","Float64_DEPRECATED"),("Boolean","Boolean_DEPRECATED"),("Enum","Enum_DEPRECATED"),("String","String_DEPRECATED"),("Array","Array_DEPRECATED"))) +StructRedirects=(OldName="CesiumMetadataGenericValue", NewName="CesiumMetadataValue") +ClassRedirects=(OldName="CesiumMetadataGenericValueBlueprintLibrary", NewName="CesiumMetadataValueBlueprintLibrary") diff --git a/Source/CesiumRuntime/Private/CesiumFeatureIdSet.cpp b/Source/CesiumRuntime/Private/CesiumFeatureIdSet.cpp index c18f57b9b..dec2fbbeb 100644 --- a/Source/CesiumRuntime/Private/CesiumFeatureIdSet.cpp +++ b/Source/CesiumRuntime/Private/CesiumFeatureIdSet.cpp @@ -5,6 +5,7 @@ #include "CesiumGltf/ExtensionModelExtStructuralMetadata.h" #include "CesiumGltf/FeatureId.h" #include "CesiumGltf/Model.h" +#include "CesiumGltfPrimitiveComponent.h" using namespace CesiumGltf; @@ -135,3 +136,55 @@ int64 UCesiumFeatureIdSetBlueprintLibrary::GetFeatureIDForVertex( return -1; } + +int64 UCesiumFeatureIdSetBlueprintLibrary::GetFeatureIDFromHit( + UPARAM(ref) const FCesiumFeatureIdSet& FeatureIDSet, + const FHitResult& Hit) { + if (FeatureIDSet._featureIDSetType == ECesiumFeatureIdSetType::Texture) { + FCesiumFeatureIdTexture texture = + std::get(FeatureIDSet._featureID); + return UCesiumFeatureIdTextureBlueprintLibrary::GetFeatureIDFromHit( + texture, + Hit); + } + + // Find the first vertex of the face. + const UCesiumGltfPrimitiveComponent* pGltfComponent = + Cast(Hit.Component); + if (!IsValid(pGltfComponent)) { + return false; + } + + if (!pGltfComponent->GetStaticMesh() || + !pGltfComponent->GetStaticMesh()->GetRenderData()) { + return false; + } + + auto& LODResources = + pGltfComponent->GetStaticMesh()->GetRenderData()->LODResources[0]; + auto PositionBuffer = LODResources.VertexBuffers.PositionVertexBuffer; + + auto faceIndices = std::visit( + CesiumFaceVertexIndicesFromAccessor{ + Hit.FaceIndex, + static_cast(PositionBuffer.GetNumVertices())}, + pGltfComponent->IndexAccessor); + + int64 VertexIndex = faceIndices[0]; + + if (FeatureIDSet._featureIDSetType == ECesiumFeatureIdSetType::Attribute) { + FCesiumFeatureIdAttribute attribute = + std::get(FeatureIDSet._featureID); + return UCesiumFeatureIdAttributeBlueprintLibrary::GetFeatureIDForVertex( + attribute, + VertexIndex); + } + + if (FeatureIDSet._featureIDSetType == ECesiumFeatureIdSetType::Implicit) { + return (VertexIndex >= 0 && VertexIndex < FeatureIDSet._featureCount) + ? VertexIndex + : -1; + } + + return -1; +} diff --git a/Source/CesiumRuntime/Private/CesiumFeatureIdTexture.cpp b/Source/CesiumRuntime/Private/CesiumFeatureIdTexture.cpp index 50cb56891..ae3698c3b 100644 --- a/Source/CesiumRuntime/Private/CesiumFeatureIdTexture.cpp +++ b/Source/CesiumRuntime/Private/CesiumFeatureIdTexture.cpp @@ -72,10 +72,10 @@ int64 UCesiumFeatureIdTextureBlueprintLibrary::GetUnrealUVChannel( return -1; } - auto textureCoordinateIndexIt = pPrimitive->glTFToUnrealTexCoordMap.find( + auto textureCoordinateIndexIt = pPrimitive->GltfToUnrealTexCoordMap.find( UCesiumFeatureIdTextureBlueprintLibrary::GetGltfTextureCoordinateSetIndex( FeatureIDTexture)); - if (textureCoordinateIndexIt == pPrimitive->glTFToUnrealTexCoordMap.end()) { + if (textureCoordinateIndexIt == pPrimitive->GltfToUnrealTexCoordMap.end()) { return -1; } diff --git a/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp b/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp index a88d7f6be..68e1641ce 100644 --- a/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp +++ b/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp @@ -119,7 +119,7 @@ static uint32_t updateTextureCoordinates( TArray& vertices, const TArray& indices, const std::optional& texture, - std::unordered_map& glTFToUnrealTexCoordMap) { + std::unordered_map& gltfToUnrealTexCoordMap) { if (!texture) { return 0; } @@ -131,7 +131,7 @@ static uint32_t updateTextureCoordinates( vertices, indices, "TEXCOORD_" + std::to_string(texture.value().texCoord), - glTFToUnrealTexCoordMap); + gltfToUnrealTexCoordMap); } uint32_t updateTextureCoordinates( @@ -141,7 +141,7 @@ uint32_t updateTextureCoordinates( TArray& vertices, const TArray& indices, const std::string& attributeName, - std::unordered_map& glTFToUnrealTexCoordMap) { + std::unordered_map& gltfToUnrealTexCoordMap) { auto uvAccessorIt = primitive.attributes.find(attributeName); if (uvAccessorIt == primitive.attributes.end()) { // Texture not used, texture coordinates don't matter. @@ -149,14 +149,14 @@ uint32_t updateTextureCoordinates( } int32_t uvAccessorID = uvAccessorIt->second; - auto mapIt = glTFToUnrealTexCoordMap.find(uvAccessorID); - if (mapIt != glTFToUnrealTexCoordMap.end()) { + auto mapIt = gltfToUnrealTexCoordMap.find(uvAccessorID); + if (mapIt != gltfToUnrealTexCoordMap.end()) { // Texture coordinates for this accessor are already populated. return mapIt->second; } - size_t textureCoordinateIndex = glTFToUnrealTexCoordMap.size(); - glTFToUnrealTexCoordMap[uvAccessorID] = textureCoordinateIndex; + size_t textureCoordinateIndex = gltfToUnrealTexCoordMap.size(); + gltfToUnrealTexCoordMap[uvAccessorID] = textureCoordinateIndex; AccessorView uvAccessor(model, uvAccessorID); if (uvAccessor.status() != AccessorViewStatus::Valid) { @@ -553,6 +553,7 @@ static void createTexCoordAccessorsForFeaturesMetadata( if (gltfTexCoordSetIndex < 0 || texCoordAccessorsMap.find(gltfTexCoordSetIndex) != texCoordAccessorsMap.end()) { + // Skip if the index is invalid or if it has already been accounted for. continue; } @@ -577,7 +578,7 @@ static void updateTextureCoordinatesForFeaturesMetadata( const CesiumEncodedFeaturesMetadata::EncodedModelMetadata& encodedModelMetadata, TMap& featuresMetadataTexcoordParameters, - std::unordered_map& glTFToUnrealTexCoordMap) { + std::unordered_map& gltfToUnrealTexCoordMap) { TRACE_CPUPROFILER_EVENT_SCOPE( Cesium::UpdateTextureCoordinatesForFeaturesMetadata) @@ -603,7 +604,7 @@ static void updateTextureCoordinatesForFeaturesMetadata( indices, "TEXCOORD_" + std::to_string(encodedProperty.textureCoordinateSetIndex), - glTFToUnrealTexCoordMap)); + gltfToUnrealTexCoordMap)); } } @@ -629,8 +630,8 @@ static void updateTextureCoordinatesForFeaturesMetadata( // This was already validated when creating the EncodedFeatureIdSet. int32_t accessor = primitive.attributes.at(attributeName); - uint32_t textureCoordinateIndex = glTFToUnrealTexCoordMap.size(); - glTFToUnrealTexCoordMap[accessor] = textureCoordinateIndex; + uint32_t textureCoordinateIndex = gltfToUnrealTexCoordMap.size(); + gltfToUnrealTexCoordMap[accessor] = textureCoordinateIndex; featuresMetadataTexcoordParameters.Emplace( encodedFeatureIDSet.name, textureCoordinateIndex); @@ -688,14 +689,14 @@ static void updateTextureCoordinatesForFeaturesMetadata( "TEXCOORD_" + std::to_string( encodedFeatureIDTexture.textureCoordinateSetIndex), - glTFToUnrealTexCoordMap)); + gltfToUnrealTexCoordMap)); } else { // Similar to feature ID attributes, we encode the unsigned integer vertex // ids as floats in the u-channel of a texture coordinate slot. If it ever // becomes possible to access the vertex ID through an Unreal material // node, this can be removed. - uint32_t textureCoordinateIndex = glTFToUnrealTexCoordMap.size(); - glTFToUnrealTexCoordMap[-1] = textureCoordinateIndex; + uint32_t textureCoordinateIndex = gltfToUnrealTexCoordMap.size(); + gltfToUnrealTexCoordMap[-1] = textureCoordinateIndex; featuresMetadataTexcoordParameters.Emplace( encodedFeatureIDSet.name, textureCoordinateIndex); @@ -728,7 +729,7 @@ static void updateTextureCoordinatesForMetadata_DEPRECATED( encodedPrimitiveMetadata, const TArray& featureIdAttributes, TMap& metadataTextureCoordinateParameters, - std::unordered_map& glTFToUnrealTexCoordMap) { + std::unordered_map& gltfToUnrealTexCoordMap) { TRACE_CPUPROFILER_EVENT_SCOPE(Cesium::UpdateTextureCoordinatesForMetadata) @@ -746,7 +747,7 @@ static void updateTextureCoordinatesForMetadata_DEPRECATED( "TEXCOORD_" + std::to_string( encodedFeatureIdTexture.textureCoordinateAttributeId), - glTFToUnrealTexCoordMap)); + gltfToUnrealTexCoordMap)); } for (const FString& featureTextureName : @@ -767,7 +768,7 @@ static void updateTextureCoordinatesForMetadata_DEPRECATED( indices, "TEXCOORD_" + std::to_string( encodedProperty.textureCoordinateAttributeId), - glTFToUnrealTexCoordMap)); + gltfToUnrealTexCoordMap)); } } } @@ -792,8 +793,8 @@ static void updateTextureCoordinatesForMetadata_DEPRECATED( // This was already validated when creating the EncodedFeatureIdSet. int32_t accessor = primitive.attributes.at(attributeName); - uint32_t textureCoordinateIndex = glTFToUnrealTexCoordMap.size(); - glTFToUnrealTexCoordMap[accessor] = textureCoordinateIndex; + uint32_t textureCoordinateIndex = gltfToUnrealTexCoordMap.size(); + gltfToUnrealTexCoordMap[accessor] = textureCoordinateIndex; metadataTextureCoordinateParameters.Emplace( encodedFeatureIdAttribute.name, textureCoordinateIndex); @@ -1170,8 +1171,8 @@ static void loadPrimitive( // We need to copy the texture coordinates associated with each texture (if // any) into the the appropriate UVs slot in FStaticMeshBuildVertex. - std::unordered_map& glTFToUnrealTexCoordMap = - primitiveResult.glTFToUnrealTexCoordMap; + std::unordered_map& gltfToUnrealTexCoordMap = + primitiveResult.GltfToUnrealTexCoordMap; { TRACE_CPUPROFILER_EVENT_SCOPE(Cesium::loadTextures) @@ -1201,7 +1202,7 @@ static void loadPrimitive( StaticMeshBuildVertices, indices, pbrMetallicRoughness.baseColorTexture, - glTFToUnrealTexCoordMap); + gltfToUnrealTexCoordMap); primitiveResult.textureCoordinateParameters ["metallicRoughnessTextureCoordinateIndex"] = updateTextureCoordinates( model, @@ -1210,7 +1211,7 @@ static void loadPrimitive( StaticMeshBuildVertices, indices, pbrMetallicRoughness.metallicRoughnessTexture, - glTFToUnrealTexCoordMap); + gltfToUnrealTexCoordMap); primitiveResult .textureCoordinateParameters["normalTextureCoordinateIndex"] = updateTextureCoordinates( @@ -1220,7 +1221,7 @@ static void loadPrimitive( StaticMeshBuildVertices, indices, material.normalTexture, - glTFToUnrealTexCoordMap); + gltfToUnrealTexCoordMap); primitiveResult .textureCoordinateParameters["occlusionTextureCoordinateIndex"] = updateTextureCoordinates( @@ -1230,7 +1231,7 @@ static void loadPrimitive( StaticMeshBuildVertices, indices, material.occlusionTexture, - glTFToUnrealTexCoordMap); + gltfToUnrealTexCoordMap); primitiveResult .textureCoordinateParameters["emissiveTextureCoordinateIndex"] = updateTextureCoordinates( @@ -1240,7 +1241,7 @@ static void loadPrimitive( StaticMeshBuildVertices, indices, material.emissiveTexture, - glTFToUnrealTexCoordMap); + gltfToUnrealTexCoordMap); for (size_t i = 0; i < primitiveResult.overlayTextureCoordinateIDToUVIndex.size(); @@ -1256,7 +1257,7 @@ static void loadPrimitive( StaticMeshBuildVertices, indices, attributeName, - glTFToUnrealTexCoordMap); + gltfToUnrealTexCoordMap); } else { primitiveResult.overlayTextureCoordinateIDToUVIndex[i] = 0; } @@ -1313,8 +1314,8 @@ static void loadPrimitive( primitiveResult.EncodedFeatures, primitiveResult.EncodedMetadata, pModelResult->EncodedMetadata, - primitiveResult.featuresMetadataTexCoordParameters, - glTFToUnrealTexCoordMap); + primitiveResult.FeaturesMetadataTexCoordParameters, + gltfToUnrealTexCoordMap); } else if (pMetadataDescription_DEPRECATED) { primitiveResult.EncodedMetadata_DEPRECATED = CesiumEncodedMetadataUtility::encodeMetadataPrimitiveAnyThreadPart( @@ -1331,8 +1332,8 @@ static void loadPrimitive( *primitiveResult.EncodedMetadata_DEPRECATED, UCesiumMetadataPrimitiveBlueprintLibrary::GetFeatureIdAttributes( primitiveResult.Metadata_DEPRECATED), - primitiveResult.featuresMetadataTexCoordParameters, - glTFToUnrealTexCoordMap); + primitiveResult.FeaturesMetadataTexCoordParameters, + gltfToUnrealTexCoordMap); } PRAGMA_ENABLE_DEPRECATION_WARNINGS @@ -1442,8 +1443,8 @@ static void loadPrimitive( LODResources.VertexBuffers.StaticMeshVertexBuffer.Init( StaticMeshBuildVertices, - glTFToUnrealTexCoordMap.size() == 0 ? 1 - : glTFToUnrealTexCoordMap.size(), + gltfToUnrealTexCoordMap.size() == 0 ? 1 + : gltfToUnrealTexCoordMap.size(), false); } @@ -1541,17 +1542,7 @@ static void loadIndexedPrimitive( const MeshPrimitive& primitive = *options.pPrimitive; const Accessor& indexAccessorGltf = model.accessors[primitive.indices]; - if (indexAccessorGltf.componentType == Accessor::ComponentType::BYTE) { - AccessorView indexAccessor(model, primitive.indices); - loadPrimitive( - primitiveResult, - transform, - options, - positionAccessor, - positionView, - indexAccessor); - } else if ( - indexAccessorGltf.componentType == + if (indexAccessorGltf.componentType == Accessor::ComponentType::UNSIGNED_BYTE) { AccessorView indexAccessor(model, primitive.indices); loadPrimitive( @@ -1561,16 +1552,7 @@ static void loadIndexedPrimitive( positionAccessor, positionView, indexAccessor); - } else if ( - indexAccessorGltf.componentType == Accessor::ComponentType::SHORT) { - AccessorView indexAccessor(model, primitive.indices); - loadPrimitive( - primitiveResult, - transform, - options, - positionAccessor, - positionView, - indexAccessor); + primitiveResult.IndexAccessor = indexAccessor; } else if ( indexAccessorGltf.componentType == Accessor::ComponentType::UNSIGNED_SHORT) { @@ -1582,6 +1564,7 @@ static void loadIndexedPrimitive( positionAccessor, positionView, indexAccessor); + primitiveResult.IndexAccessor = indexAccessor; } else if ( indexAccessorGltf.componentType == Accessor::ComponentType::UNSIGNED_INT) { @@ -1593,6 +1576,7 @@ static void loadIndexedPrimitive( positionAccessor, positionView, indexAccessor); + primitiveResult.IndexAccessor = indexAccessor; } } @@ -1621,6 +1605,7 @@ static void loadPrimitive( } AccessorView positionView(model, *pPositionAccessor); + result.PositionAccessor = positionView; if (primitive.indices < 0 || primitive.indices >= model.accessors.size()) { std::vector syntheticIndexBuffer(positionView.size()); @@ -2259,7 +2244,7 @@ static void SetFeaturesMetadataParameterValues( int32 index) { if (encodePrimitiveFeaturesGameThreadPart(loadResult.EncodedFeatures)) { for (const auto& textureCoordinateSet : - loadResult.featuresMetadataTexCoordParameters) { + loadResult.FeaturesMetadataTexCoordParameters) { pMaterial->SetScalarParameterValueByInfo( FMaterialParameterInfo( FName(textureCoordinateSet.Key), @@ -2397,7 +2382,7 @@ static void SetMetadataParameterValues_DEPRECATED( } for (const auto& textureCoordinateSet : - loadResult.featuresMetadataTexCoordParameters) { + loadResult.FeaturesMetadataTexCoordParameters) { pMaterial->SetScalarParameterValueByInfo( FMaterialParameterInfo( FName(textureCoordinateSet.Key), @@ -2530,9 +2515,11 @@ static void loadPrimitiveGameThreadPart( pMesh->pTilesetActor = pTilesetActor; pMesh->overlayTextureCoordinateIDToUVIndex = loadResult.overlayTextureCoordinateIDToUVIndex; - pMesh->glTFToUnrealTexCoordMap = - std::move(loadResult.glTFToUnrealTexCoordMap); + pMesh->GltfToUnrealTexCoordMap = + std::move(loadResult.GltfToUnrealTexCoordMap); pMesh->TexCoordAccessorMap = std::move(loadResult.TexCoordAccessorMap); + pMesh->PositionAccessor = std::move(loadResult.PositionAccessor); + pMesh->IndexAccessor = std::move(loadResult.IndexAccessor); pMesh->HighPrecisionNodeTransform = loadResult.transform; pMesh->UpdateTransformFromCesium(cesiumToUnrealTransform); diff --git a/Source/CesiumRuntime/Private/CesiumGltfPrimitiveComponent.h b/Source/CesiumRuntime/Private/CesiumGltfPrimitiveComponent.h index 1b3aa7d7e..3886ed80b 100644 --- a/Source/CesiumRuntime/Private/CesiumGltfPrimitiveComponent.h +++ b/Source/CesiumRuntime/Private/CesiumGltfPrimitiveComponent.h @@ -61,7 +61,6 @@ class UCesiumGltfPrimitiveComponent : public UStaticMeshComponent { PRAGMA_ENABLE_DEPRECATION_WARNINGS ACesium3DTileset* pTilesetActor; - const CesiumGltf::Model* pModel; const CesiumGltf::MeshPrimitive* pMeshPrimitive; @@ -70,18 +69,39 @@ class UCesiumGltfPrimitiveComponent : public UStaticMeshComponent { */ glm::dmat4x4 HighPrecisionNodeTransform; + /** + * Maps an overlay texture coordinate ID to the index of the corresponding + * texture coordinates in the mesh's UVs array. + */ OverlayTextureCoordinateIDMap overlayTextureCoordinateIDToUVIndex; - // Maps the accessor index in a glTF to its corresponding texture coordinate - // index in the Unreal mesh. - // The -1 key is reserved for implicit feature IDs (in other words, the vertex - // index). - std::unordered_map glTFToUnrealTexCoordMap; - - // Maps texture coordinate set indices in a glTF to AccessorViews. This stores - // accessor views on texture coordinate sets that will be used by feature ID - // textures or property textures. + + /** + * Maps the accessor index in a glTF to its corresponding texture coordinate + * index in the Unreal mesh. The -1 key is reserved for implicit feature IDs + * (in other words, the vertex index). + */ + std::unordered_map GltfToUnrealTexCoordMap; + + /** + * Maps texture coordinate set indices in a glTF to AccessorViews. This stores + * accessor views on texture coordinate sets that will be used by feature ID + * textures or property textures for picking. + */ std::unordered_map TexCoordAccessorMap; + /** + * The position accessor of the glTF primitive. This is used for computing + * the UV at a hit location on a primitive, and is safer to access than the + * mesh's RenderData. + */ + CesiumGltf::AccessorView PositionAccessor; + + /** + * The index accessor of the glTF primitive, if one is specified. This is used + * for computing the UV at a hit location on a primitive. + */ + CesiumIndexAccessorType IndexAccessor; + std::optional boundingVolume; /** diff --git a/Source/CesiumRuntime/Private/CesiumMetadataPickingBlueprintLibrary.cpp b/Source/CesiumRuntime/Private/CesiumMetadataPickingBlueprintLibrary.cpp index 9bcc2427b..b8c294e46 100644 --- a/Source/CesiumRuntime/Private/CesiumMetadataPickingBlueprintLibrary.cpp +++ b/Source/CesiumRuntime/Private/CesiumMetadataPickingBlueprintLibrary.cpp @@ -79,39 +79,6 @@ UCesiumMetadataPickingBlueprintLibrary::GetMetadataValuesForFaceAsStrings( return strings; } -namespace { -bool GetVertexIndicesFromFace( - const FStaticMeshLODResources& LODResources, - int32 FaceIndex, - std::array& Indices) { - int32 FirstIndex = FaceIndex * 3; - - if (LODResources.IndexBuffer.GetNumIndices() > 0) { - if (FirstIndex + 2 >= LODResources.IndexBuffer.GetNumIndices()) { - return false; - } - - for (int32 i = 0; i < 3; i++) { - Indices[static_cast(i)] = - LODResources.IndexBuffer.GetIndex(FirstIndex + i); - } - - return true; - } - - int32 VertexCount = LODResources.GetNumVertices(); - if (FirstIndex + 2 >= VertexCount) { - return false; - } - - Indices[0] = static_cast(FirstIndex); - Indices[1] = static_cast(FirstIndex + 1); - Indices[2] = static_cast(FirstIndex + 2); - - return true; -} -} // namespace - bool UCesiumMetadataPickingBlueprintLibrary::FindUVFromHit( const FHitResult& Hit, int64 GltfTexCoordSetIndex, @@ -122,27 +89,17 @@ bool UCesiumMetadataPickingBlueprintLibrary::FindUVFromHit( return false; } - const auto pMesh = pGltfComponent->GetStaticMesh(); - if (!IsValid(pMesh)) { - return false; - } - - const auto pRenderData = pMesh->GetRenderData(); - if (!pRenderData || pRenderData->LODResources.Num() == 0) { - return false; - } - auto accessorIt = pGltfComponent->TexCoordAccessorMap.find(GltfTexCoordSetIndex); if (accessorIt == pGltfComponent->TexCoordAccessorMap.end()) { return false; } - const auto& LODResources = pRenderData->LODResources[0]; - std::array VertexIndices; - if (!GetVertexIndicesFromFace(LODResources, Hit.FaceIndex, VertexIndices)) { - return false; - } + std::array VertexIndices = std::visit( + CesiumFaceVertexIndicesFromAccessor{ + Hit.FaceIndex, + pGltfComponent->PositionAccessor.size()}, + pGltfComponent->IndexAccessor); // Adapted from UBodySetup::CalcUVAtLocation. Compute the barycentric // coordinates of the point relative to the face, then use those to @@ -162,16 +119,13 @@ bool UCesiumMetadataPickingBlueprintLibrary::FindUVFromHit( std::array Positions; for (size_t i = 0; i < Positions.size(); i++) { - auto Position = - LODResources.VertexBuffers.PositionVertexBuffer.VertexPosition( - VertexIndices[i]); - Positions[i] = FVector(Position[0], Position[1], Position[2]); + auto Position = pGltfComponent->PositionAccessor[VertexIndices[i]]; + Positions[i] = FVector(Position[0], -Position[1], Position[2]); } const FVector Location = pGltfComponent->GetComponentToWorld().InverseTransformPosition( Hit.Location); - FVector BaryCoords = FMath::ComputeBaryCentric2D( Location, Positions[0], @@ -222,9 +176,9 @@ UCesiumMetadataPickingBlueprintLibrary::GetPropertyTableValuesFromHit( propertyTables[propertyTableIndex]; int64 featureID = - UCesiumPrimitiveFeaturesBlueprintLibrary::GetFeatureIDFromFace( + UCesiumPrimitiveFeaturesBlueprintLibrary::GetFeatureIDFromHit( features, - Hit.FaceIndex, + Hit, FeatureIDSetIndex); if (featureID < 0) { return TMap(); diff --git a/Source/CesiumRuntime/Private/CesiumPrimitiveFeatures.cpp b/Source/CesiumRuntime/Private/CesiumPrimitiveFeatures.cpp index 89f67a43e..45af5c34e 100644 --- a/Source/CesiumRuntime/Private/CesiumPrimitiveFeatures.cpp +++ b/Source/CesiumRuntime/Private/CesiumPrimitiveFeatures.cpp @@ -112,3 +112,17 @@ int64 UCesiumPrimitiveFeaturesBlueprintLibrary::GetFeatureIDFromFace( PrimitiveFeatures, FaceIndex)); } + +int64 UCesiumPrimitiveFeaturesBlueprintLibrary::GetFeatureIDFromHit( + UPARAM(ref) const FCesiumPrimitiveFeatures& PrimitiveFeatures, + const FHitResult& Hit, + int64 FeatureIDSetIndex) { + if (FeatureIDSetIndex < 0 || + FeatureIDSetIndex >= PrimitiveFeatures._featureIDSets.Num()) { + return -1; + } + + return UCesiumFeatureIdSetBlueprintLibrary::GetFeatureIDFromHit( + PrimitiveFeatures._featureIDSets[FeatureIDSetIndex], + Hit); +} diff --git a/Source/CesiumRuntime/Private/CesiumPropertyTexture.cpp b/Source/CesiumRuntime/Private/CesiumPropertyTexture.cpp index 21bee1b9e..a8e358b58 100644 --- a/Source/CesiumRuntime/Private/CesiumPropertyTexture.cpp +++ b/Source/CesiumRuntime/Private/CesiumPropertyTexture.cpp @@ -32,8 +32,6 @@ FCesiumPropertyTexture::FCesiumPropertyTexture( FString key(UTF8_TO_TCHAR(propertyName.data())); properties.Add(key, FCesiumPropertyTextureProperty(propertyValue)); }); - - /* const std::string positionName = "POSITION";*/ } /*static*/ const ECesiumPropertyTextureStatus @@ -77,24 +75,24 @@ UCesiumPropertyTextureBlueprintLibrary::GetMetadataValuesForUV( const FVector2D& UV) { TMap values; - for (const auto& pair : PropertyTexture._properties) { - const FCesiumPropertyTextureProperty& property = pair.Value; + for (const auto& propertyIt : PropertyTexture._properties) { + const FCesiumPropertyTextureProperty& property = propertyIt.Value; ECesiumPropertyTexturePropertyStatus status = UCesiumPropertyTexturePropertyBlueprintLibrary:: GetPropertyTexturePropertyStatus(property); if (status == ECesiumPropertyTexturePropertyStatus::Valid) { values.Add( - pair.Key, + propertyIt.Key, UCesiumPropertyTexturePropertyBlueprintLibrary::GetValue( - pair.Value, + propertyIt.Value, UV)); } else if ( status == ECesiumPropertyTexturePropertyStatus::EmptyPropertyWithDefault) { values.Add( - pair.Key, + propertyIt.Key, UCesiumPropertyTexturePropertyBlueprintLibrary::GetDefaultValue( - pair.Value)); + propertyIt.Value)); } } @@ -108,6 +106,16 @@ UCesiumPropertyTextureBlueprintLibrary::GetMetadataValuesFromHit( TMap values; for (const auto& propertyIt : PropertyTexture._properties) { + if (UCesiumPropertyTexturePropertyBlueprintLibrary:: + GetPropertyTexturePropertyStatus(propertyIt.Value) == + ECesiumPropertyTexturePropertyStatus::EmptyPropertyWithDefault) { + values.Add( + propertyIt.Key, + UCesiumPropertyTexturePropertyBlueprintLibrary::GetDefaultValue( + propertyIt.Value)); + continue; + } + auto glTFTexCoordIndex = propertyIt.Value.getTexCoordSetIndex(); FVector2D UV; if (UCesiumMetadataPickingBlueprintLibrary::FindUVFromHit( diff --git a/Source/CesiumRuntime/Private/CesiumPropertyTextureProperty.cpp b/Source/CesiumRuntime/Private/CesiumPropertyTextureProperty.cpp index ca8016c5e..f620381c5 100644 --- a/Source/CesiumRuntime/Private/CesiumPropertyTextureProperty.cpp +++ b/Source/CesiumRuntime/Private/CesiumPropertyTextureProperty.cpp @@ -403,8 +403,8 @@ int64 UCesiumPropertyTexturePropertyBlueprintLibrary::GetUnrealUVChannel( GetGltfTextureCoordinateSetIndex(Property); auto textureCoordinateIndexIt = - pPrimitive->glTFToUnrealTexCoordMap.find(texCoordSetIndex); - if (textureCoordinateIndexIt == pPrimitive->glTFToUnrealTexCoordMap.end()) { + pPrimitive->GltfToUnrealTexCoordMap.find(texCoordSetIndex); + if (textureCoordinateIndexIt == pPrimitive->GltfToUnrealTexCoordMap.end()) { return -1; } diff --git a/Source/CesiumRuntime/Private/CesiumRasterOverlays.h b/Source/CesiumRuntime/Private/CesiumRasterOverlays.h index ae58e07bf..d2d9ada6b 100644 --- a/Source/CesiumRuntime/Private/CesiumRasterOverlays.h +++ b/Source/CesiumRuntime/Private/CesiumRasterOverlays.h @@ -1,4 +1,4 @@ -// Copyright 2020-2021 CesiumGS, Inc. and Contributors +// Copyright 2020-2023 CesiumGS, Inc. and Contributors #pragma once diff --git a/Source/CesiumRuntime/Private/LoadGltfResult.h b/Source/CesiumRuntime/Private/LoadGltfResult.h index a44e877b8..c47625aac 100644 --- a/Source/CesiumRuntime/Private/LoadGltfResult.h +++ b/Source/CesiumRuntime/Private/LoadGltfResult.h @@ -23,33 +23,25 @@ #include #include -// TODO: internal documentation namespace LoadGltfResult { +/** + * Represents the result of loading a glTF primitive on a game thread. + * Temporarily holds render data that will be used in the Unreal material, as + * well as any data that needs to be transferred to the corresponding + * CesiumGltfPrimitiveComponent after it is created on the main thread. + */ struct LoadPrimitiveResult { - // Parses EXT_mesh_features from a mesh primitive. - FCesiumPrimitiveFeatures Features{}; - // Parses EXT_structural_metadata from a mesh primitive. - FCesiumPrimitiveMetadata Metadata{}; - - // Encodes the EXT_mesh_features on a mesh primitive. - CesiumEncodedFeaturesMetadata::EncodedPrimitiveFeatures EncodedFeatures{}; - // Encodes the EXT_structural_metadata on a mesh primitive. - CesiumEncodedFeaturesMetadata::EncodedPrimitiveMetadata EncodedMetadata{}; - - PRAGMA_DISABLE_DEPRECATION_WARNINGS - // For backwards compatibility with CesiumEncodedMetadataComponent. - FCesiumMetadataPrimitive Metadata_DEPRECATED{}; - std::optional - EncodedMetadata_DEPRECATED = std::nullopt; - PRAGMA_ENABLE_DEPRECATION_WARNINGS - - // A map of feature ID set names to their corresponding texture coordinate - // indices in the Unreal mesh. - TMap featuresMetadataTexCoordParameters; +#pragma region Temporary render data + /** + * The render data. This is populated so it can be set on the static mesh + * created on the main thread. + */ TUniquePtr RenderData = nullptr; - const CesiumGltf::Model* pModel = nullptr; - const CesiumGltf::MeshPrimitive* pMeshPrimitive = nullptr; + + /** + * A pointer to the glTF material. + */ const CesiumGltf::Material* pMaterial = nullptr; glm::dmat4x4 transform{1.0}; TSharedPtr @@ -64,6 +56,11 @@ struct LoadPrimitiveResult { TUniquePtr occlusionTexture; TUniquePtr waterMaskTexture; std::unordered_map textureCoordinateParameters; + /** + * A map of feature ID set names to their corresponding texture coordinate + * indices in the Unreal mesh. + */ + TMap FeaturesMetadataTexCoordParameters; bool isUnlit = false; @@ -74,33 +71,96 @@ struct LoadPrimitiveResult { double waterMaskTranslationY = 0.0; double waterMaskScale = 1.0; + /** + * The dimensions of the primitive. Passed to a CesiumGltfPointsComponent for + * use in computing attenuation. + */ + glm::vec3 dimensions; + +#pragma endregion + +#pragma region CesiumGltfPrimitiveComponent data + const CesiumGltf::Model* pModel = nullptr; + const CesiumGltf::MeshPrimitive* pMeshPrimitive = nullptr; + + /** Parses EXT_mesh_features from a mesh primitive.*/ + FCesiumPrimitiveFeatures Features{}; + /** Parses EXT_structural_metadata from a mesh primitive.*/ + FCesiumPrimitiveMetadata Metadata{}; + + /** Encodes the EXT_mesh_features on a mesh primitive.*/ + CesiumEncodedFeaturesMetadata::EncodedPrimitiveFeatures EncodedFeatures{}; + /** Encodes the EXT_structural_metadata on a mesh primitive.*/ + CesiumEncodedFeaturesMetadata::EncodedPrimitiveMetadata EncodedMetadata{}; + + PRAGMA_DISABLE_DEPRECATION_WARNINGS + // For backwards compatibility with CesiumEncodedMetadataComponent. + FCesiumMetadataPrimitive Metadata_DEPRECATED{}; + std::optional + EncodedMetadata_DEPRECATED = std::nullopt; + PRAGMA_ENABLE_DEPRECATION_WARNINGS + + /** + * Maps an overlay texture coordinate ID to the index of the corresponding + * texture coordinates in the mesh's UVs array. + */ OverlayTextureCoordinateIDMap overlayTextureCoordinateIDToUVIndex{}; - // Maps the accessor index in a glTF to its corresponding texture coordinate - // index in the Unreal mesh. - // The -1 key is reserved for implicit feature IDs (in other words, the vertex - // index). - std::unordered_map glTFToUnrealTexCoordMap; - - // Maps texture coordinate set indices in a glTF to AccessorViews. This stores - // accessor views on texture coordinate sets that will be used by feature ID - // textures or property textures. + + /** + * Maps the accessor index in a glTF to its corresponding texture coordinate + * index in the Unreal mesh. The -1 key is reserved for implicit feature IDs + * (in other words, the vertex index). + */ + std::unordered_map GltfToUnrealTexCoordMap; + + /** + * Maps texture coordinate set indices in a glTF to AccessorViews. This stores + * accessor views on texture coordinate sets that will be used by feature ID + * textures or property textures for picking. + */ std::unordered_map TexCoordAccessorMap; - glm::vec3 dimensions; + /** + * The position accessor of the glTF primitive. This is used for computing + * the UV at a hit location on a primitive, and is safer to access than the + * mesh's RenderData. + */ + CesiumGltf::AccessorView PositionAccessor; + + /** + * The index accessor of the glTF primitive, if one is specified. This is used + * for computing the UV at a hit location on a primitive. + */ + CesiumIndexAccessorType IndexAccessor; + +#pragma endregion }; +/** + * Represents the result of loading a glTF mesh on a game thread. + */ struct LoadMeshResult { std::vector primitiveResults{}; }; +/** + * Represents the result of loading a glTF node on a game thread. + */ struct LoadNodeResult { std::optional meshResult = std::nullopt; }; +/** + * Represents the result of loading a glTF model on a game thread. + * Temporarily holds data that needs to be transferred to the corresponding + * CesiumGltfComponent after it is created on the main thread. + */ struct LoadModelResult { std::vector nodeResults{}; + // Parses the root EXT_structural_metadata extension. FCesiumModelMetadata Metadata{}; + // Encodes the EXT_structural_metadata on a glTF model. CesiumEncodedFeaturesMetadata::EncodedModelMetadata EncodedMetadata{}; diff --git a/Source/CesiumRuntime/Public/CesiumFeatureIdSet.h b/Source/CesiumRuntime/Public/CesiumFeatureIdSet.h index 673614e6c..72def5663 100644 --- a/Source/CesiumRuntime/Public/CesiumFeatureIdSet.h +++ b/Source/CesiumRuntime/Public/CesiumFeatureIdSet.h @@ -151,10 +151,10 @@ class CESIUMRUNTIME_API UCesiumFeatureIdSetBlueprintLibrary /** * Gets the feature ID associated with a given vertex. The feature ID can be - * used with a FCesiumPropertyTable to retrieve the per-vertex - * metadata. This returns -1 if the given vertex is out-of-bounds, or if the - * feature ID set is invalid (e.g., it contains an invalid feature ID - * texture). + * used with a FCesiumPropertyTable to retrieve the corresponding metadata. + * + * This returns -1 if the given vertex is out-of-bounds, or if the feature ID + * set is invalid (e.g., it contains an invalid feature ID texture). */ UFUNCTION( BlueprintCallable, @@ -163,4 +163,26 @@ class CESIUMRUNTIME_API UCesiumFeatureIdSetBlueprintLibrary static int64 GetFeatureIDForVertex( UPARAM(ref) const FCesiumFeatureIdSet& FeatureIDSet, int64 VertexIndex); + + /** + * Given a trace hit result, gets the feature ID from the feature ID set on + * the hit component. This returns a more accurate value for feature ID + * textures, since they define feature IDs per-texel instead of per-vertex. + * The feature ID can be used with a FCesiumPropertyTable to retrieve the + * corresponding metadata. + * + * This can still retrieve the feature IDs for non-texture feature ID sets. + * For attribute or implicit feature IDs, the first feature ID associated + * with the first vertex of the intersected face is returned. + * + * This returns -1 if the feature ID set is invalid (e.g., it contains an + * invalid feature ID texture). + */ + UFUNCTION( + BlueprintCallable, + BlueprintPure, + Category = "Cesium|Features|FeatureIDSet") + static int64 GetFeatureIDFromHit( + UPARAM(ref) const FCesiumFeatureIdSet& FeatureIDSet, + const FHitResult& Hit); }; diff --git a/Source/CesiumRuntime/Public/CesiumPrimitiveFeatures.h b/Source/CesiumRuntime/Public/CesiumPrimitiveFeatures.h index 4c2c81be5..d3cfa040e 100644 --- a/Source/CesiumRuntime/Public/CesiumPrimitiveFeatures.h +++ b/Source/CesiumRuntime/Public/CesiumPrimitiveFeatures.h @@ -33,7 +33,7 @@ struct CESIUMRUNTIME_API FCesiumPrimitiveFeatures { * @param Model The model that contains the EXT_mesh_features extension * @param Primitive The mesh primitive that stores EXT_mesh_features * extension - * @param Features The EXT_mesh_features of the gltf mesh primitive. + * @param Features The EXT_mesh_features of the glTF mesh primitive. * primitive */ FCesiumPrimitiveFeatures( @@ -130,4 +130,22 @@ class CESIUMRUNTIME_API UCesiumPrimitiveFeaturesBlueprintLibrary UPARAM(ref) const FCesiumPrimitiveFeatures& PrimitiveFeatures, int64 FaceIndex, int64 FeatureIDSetIndex = 0); + + /** + * Gets the feature ID from the given line trace hit, assuming it + * has hit a glTF primitive component containing this CesiumPrimitiveFeatures. + * + * A primitive may have multiple feature ID sets, so this allows a feature ID + * set to be specified by index. This value should index into the array of + * CesiumFeatureIdSets in the CesiumPrimitiveFeatures. If the specified + * feature ID set index is invalid, this returns -1. + */ + UFUNCTION( + BlueprintCallable, + BlueprintPure, + Category = "Cesium|Primitive|Features") + static int64 GetFeatureIDFromHit( + UPARAM(ref) const FCesiumPrimitiveFeatures& PrimitiveFeatures, + const FHitResult& Hit, + int64 FeatureIDSetIndex = 0); }; diff --git a/Source/CesiumRuntime/Public/CesiumPropertyTexture.h b/Source/CesiumRuntime/Public/CesiumPropertyTexture.h index c228fd8d3..44e034523 100644 --- a/Source/CesiumRuntime/Public/CesiumPropertyTexture.h +++ b/Source/CesiumRuntime/Public/CesiumPropertyTexture.h @@ -144,9 +144,13 @@ class CESIUMRUNTIME_API UCesiumPropertyTextureBlueprintLibrary const FVector2D& UV); /** - * Given a trace hit result, get all of the property values from the hit - * component, mapped by property name. This will only include values from - * valid property texture properties. + * Given a trace hit result, gets all of the property values from property + * texture on the hit component, mapped by property name. This will only + * include values from valid property texture properties. + * + * In EXT_structural_metadata, individual properties can specify different + * texture coordinate sets to be sampled from. This method uses the + * corresponding texture coordinate sets to sample each property. * * @param Hit The trace hit result * @return The property values mapped by property name.