From 43d74994332af460e805dd529b6631a4d743ad28 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Fri, 11 Aug 2023 11:29:49 -0400 Subject: [PATCH] Add missing header files, prevent material from generating withunsaved changes --- .../Private/CesiumEncodedFeaturesMetadata.h | 1 + .../Private/CesiumEncodedMetadataUtility.cpp | 4 + .../CesiumFeaturesMetadataComponent.cpp | 55 +++++-- .../Private/CesiumGltfComponent.cpp | 10 +- .../Private/CesiumGltfPrimitiveComponent.h | 1 + .../CesiumMetadataPickingBlueprintLibrary.cpp | 4 +- .../CesiumMetadataUtilityBlueprintLibrary.cpp | 7 +- .../Private/CesiumPrimitiveFeatures.cpp | 11 +- .../CesiumSubLevelSwitcherComponent.cpp | 1 + .../Private/Tests/CesiumGltfSpecUtility.h | 11 +- .../Tests/CesiumPrimitiveFeatures.spec.cpp | 150 ++++++++++++------ .../Public/CesiumFeatureIdTexture.h | 1 + .../CesiumMetadataPickingBlueprintLibrary.h | 3 +- .../Public/CesiumMetadataPropertyDetails.h | 2 +- .../CesiumMetadataUtilityBlueprintLibrary.h | 4 +- .../Public/CesiumPrimitiveFeatures.h | 15 +- .../Public/CesiumPrimitiveMetadata.h | 4 +- 17 files changed, 191 insertions(+), 93 deletions(-) diff --git a/Source/CesiumRuntime/Private/CesiumEncodedFeaturesMetadata.h b/Source/CesiumRuntime/Private/CesiumEncodedFeaturesMetadata.h index eae6a0f02..6d30ad558 100644 --- a/Source/CesiumRuntime/Private/CesiumEncodedFeaturesMetadata.h +++ b/Source/CesiumRuntime/Private/CesiumEncodedFeaturesMetadata.h @@ -18,6 +18,7 @@ struct FCesiumPropertyTable; struct FCesiumPropertyTableProperty; struct FCesiumPropertyTexture; struct FCesiumPropertyTableDescription; +struct FCesiumPropertyTextureDescription; struct FFeatureTextureDescription; struct FCesiumModelMetadataDescription; struct FCesiumPrimitiveFeaturesDescription; diff --git a/Source/CesiumRuntime/Private/CesiumEncodedMetadataUtility.cpp b/Source/CesiumRuntime/Private/CesiumEncodedMetadataUtility.cpp index 74c4ae44e..c7510c776 100644 --- a/Source/CesiumRuntime/Private/CesiumEncodedMetadataUtility.cpp +++ b/Source/CesiumRuntime/Private/CesiumEncodedMetadataUtility.cpp @@ -26,6 +26,8 @@ using namespace CesiumTextureUtility; +PRAGMA_DISABLE_DEPRECATION_WARNINGS + namespace CesiumEncodedMetadataUtility { namespace { @@ -800,3 +802,5 @@ FString createHlslSafeName(const FString& rawName) { } } // namespace CesiumEncodedMetadataUtility + +PRAGMA_ENABLE_DEPRECATION_WARNINGS diff --git a/Source/CesiumRuntime/Private/CesiumFeaturesMetadataComponent.cpp b/Source/CesiumRuntime/Private/CesiumFeaturesMetadataComponent.cpp index fac13254c..366522471 100644 --- a/Source/CesiumRuntime/Private/CesiumFeaturesMetadataComponent.cpp +++ b/Source/CesiumRuntime/Private/CesiumFeaturesMetadataComponent.cpp @@ -8,6 +8,7 @@ #include "CesiumGltfPrimitiveComponent.h" #include "CesiumMetadataConversions.h" #include "CesiumModelMetadata.h" +#include "CesiumRuntime.h" #if WITH_EDITOR #include "AssetRegistry/AssetData.h" @@ -438,6 +439,7 @@ static void RemapUserConnections( TMap>& ConnectionRemap, UMaterialFunction* GetFeatureIdsFromAttributeFunction, UMaterialFunction* GetFeatureIdsFromTextureFunction) { + MaterialNodeClassification Classification; ClassifyNodes( Layer, @@ -571,7 +573,7 @@ UMaterialExpressionMaterialFunctionCall* GenerateNodesForFeatureIdAttribute( TextureCoordinateIndex->MaterialExpressionEditorY = NodeY; AutoGeneratedNodes.Add(TextureCoordinateIndex); - NodeX += Incr; + NodeX += 2 * Incr; UMaterialExpressionMaterialFunctionCall* GetFeatureIdsFromAttribute = NewObject(TargetMaterialLayer); @@ -600,6 +602,8 @@ void GenerateNodesForPropertyTable( int32 SectionLeft = NodeX; int32 SectionTop = NodeY; + NodeX += 1.5 * Incr; + UMaterialExpressionCustom* GetPropertyValuesFunction = NewObject(TargetMaterialLayer); GetPropertyValuesFunction->Inputs.Reserve(PropertyTable.Properties.Num() + 2); @@ -617,8 +621,6 @@ void GenerateNodesForPropertyTable( FeatureIDInput.InputName = FName("FeatureID"); FeatureIDInput.Input.Expression = GetFeatureIdCall; - NodeX += Incr; - if (PropertyTable.Properties.Num()) { const FCesiumPropertyTablePropertyDescription& property = PropertyTable.Properties[0]; @@ -638,12 +640,18 @@ void GenerateNodesForPropertyTable( } NodeX = SectionLeft; - NodeY += Incr; GetPropertyValuesFunction->AdditionalOutputs.Reserve( PropertyTable.Properties.Num()); for (const FCesiumPropertyTablePropertyDescription& property : PropertyTable.Properties) { + if (property.EncodingDetails.Conversion == + ECesiumEncodedMetadataConversion::None) { + continue; + } + + NodeY += Incr; + FString propertyName = createHlslSafeName(property.Name); UMaterialExpressionTextureObjectParameter* PropertyData = @@ -705,8 +713,6 @@ void GenerateNodesForPropertyTable( GetPropertyValuesFunction->Code += propertyName + " = " + asComponentString + "(" + PropertyDataName + ".Load(int3(_czm_pixelX, _czm_pixelY, 0))." + swizzle + ");\n"; - - NodeY += Incr; } // Obligatory return code. @@ -856,8 +862,8 @@ void GenerateMaterialNodes( TSet GeneratedPropertyTableNames; - int32 SectionLeft = NodeX; - int32 GeneratedNodesWidth = 0; + int32 FeatureIdSectionLeft = NodeX; + int32 PropertyTableSectionLeft = FeatureIdSectionLeft + 3 * Incr; for (const FCesiumFeatureIdSetDescription& featureIdSet : pComponent->FeatureIdSets) { @@ -897,7 +903,7 @@ void GenerateMaterialNodes( }); if (pPropertyTable) { - NodeX += 4 * Incr; + NodeX = PropertyTableSectionLeft; GenerateNodesForPropertyTable( *pPropertyTable, @@ -910,13 +916,14 @@ void GenerateMaterialNodes( GeneratedPropertyTableNames.Add(pPropertyTable->Name); } - GeneratedNodesWidth = std::max(NodeX, GeneratedNodesWidth); - NodeX = SectionLeft; - NodeY += Incr; + NodeX = FeatureIdSectionLeft; + NodeY += 2 * Incr; } - NodeX += Incr; + NodeX = PropertyTableSectionLeft; + // Generate nodes for any property tables that aren't linked to a feature ID + // set. for (const FCesiumPropertyTableDescription& propertyTable : pComponent->PropertyTables) { if (!GeneratedPropertyTableNames.Find(propertyTable.Name)) { @@ -927,15 +934,14 @@ void GenerateMaterialNodes( NodeX, NodeY, nullptr); - GeneratedNodesWidth = std::max(NodeX, GeneratedNodesWidth); - NodeX = SectionLeft; + NodeX = PropertyTableSectionLeft; NodeY += Incr; } } // GenerateNodesForPropertyTextures - NodeX = 0; + NodeX = FeatureIdSectionLeft; NodeY = -2 * Incr; UMaterialExpressionFunctionInput* InputMaterial = nullptr; @@ -965,7 +971,7 @@ void GenerateMaterialNodes( OneTimeGeneratedNodes.Add(InputMaterial); } - NodeX += GeneratedNodesWidth + 2 * Incr; + NodeX += PropertyTableSectionLeft + 3 * Incr; UMaterialExpressionSetMaterialAttributes* SetMaterialAttributes = nullptr; #if ENGINE_MINOR_VERSION == 0 @@ -1045,6 +1051,21 @@ void UCesiumFeaturesMetadataComponent::GenerateMaterial() { if (!GetFeatureIdsFromAttributeFunction || !GetFeatureIdsFromTextureFunction) { + UE_LOG( + LogCesium, + Error, + TEXT( + "Can't find the material functions necessary to generate material. Aborting.")); + return; + } + + if (this->TargetMaterialLayer && + this->TargetMaterialLayer->GetPackage()->IsDirty()) { + UE_LOG( + LogCesium, + Error, + TEXT( + "Can't regenerate a material layer that has unsaved changes. Please save your changes and try again.")); return; } diff --git a/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp b/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp index dd5e0d766..8be13ef33 100644 --- a/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp +++ b/Source/CesiumRuntime/Private/CesiumGltfComponent.cpp @@ -1948,7 +1948,6 @@ static void SetPropertyTableParameterValues( int32 index) { for (const CesiumEncodedFeaturesMetadata::EncodedPropertyTableProperty& encodedProperty : encodedPropertyTable.properties) { - pMaterial->SetTextureParameterValueByInfo( FMaterialParameterInfo( FName(CesiumEncodedFeaturesMetadata:: @@ -2454,7 +2453,14 @@ static void loadPrimitiveGameThreadPart( PRAGMA_DISABLE_DEPRECATION_WARNINGS - pMesh->Metadata_DEPRECATED = std::move(loadResult.Metadata_DEPRECATED); + // Doing the above std::move operations invalidates the pointers in the + // FCesiumMetadataPrimitive constructed on the loadResult. It's a bit awkward, + // but we have to reconstruct the metadata primitive here. + pMesh->Metadata_DEPRECATED = FCesiumMetadataPrimitive{ + pMesh->Features, + pMesh->Metadata, + pGltf->Metadata}; + if (loadResult.EncodedMetadata_DEPRECATED) { pMesh->EncodedMetadata_DEPRECATED = std::move(loadResult.EncodedMetadata_DEPRECATED); diff --git a/Source/CesiumRuntime/Private/CesiumGltfPrimitiveComponent.h b/Source/CesiumRuntime/Private/CesiumGltfPrimitiveComponent.h index 90d10aac5..b33958069 100644 --- a/Source/CesiumRuntime/Private/CesiumGltfPrimitiveComponent.h +++ b/Source/CesiumRuntime/Private/CesiumGltfPrimitiveComponent.h @@ -52,6 +52,7 @@ class UCesiumGltfPrimitiveComponent : public UStaticMeshComponent { * For backwards compatibility with the EXT_feature_metadata implementation. */ FCesiumMetadataPrimitive Metadata_DEPRECATED; + std::optional EncodedMetadata_DEPRECATED; PRAGMA_ENABLE_DEPRECATION_WARNINGS diff --git a/Source/CesiumRuntime/Private/CesiumMetadataPickingBlueprintLibrary.cpp b/Source/CesiumRuntime/Private/CesiumMetadataPickingBlueprintLibrary.cpp index 5d72c1822..cc223af5e 100644 --- a/Source/CesiumRuntime/Private/CesiumMetadataPickingBlueprintLibrary.cpp +++ b/Source/CesiumRuntime/Private/CesiumMetadataPickingBlueprintLibrary.cpp @@ -46,8 +46,8 @@ UCesiumMetadataPickingBlueprintLibrary::GetMetadataValuesForFace( int64 featureID = UCesiumPrimitiveFeaturesBlueprintLibrary::GetFeatureIDFromFace( features, - featureIDSet, - FaceIndex); + FaceIndex, + FeatureIDSetIndex); if (featureID < 0) { return TMap(); } diff --git a/Source/CesiumRuntime/Private/CesiumMetadataUtilityBlueprintLibrary.cpp b/Source/CesiumRuntime/Private/CesiumMetadataUtilityBlueprintLibrary.cpp index 5847e8bba..faa15c49f 100644 --- a/Source/CesiumRuntime/Private/CesiumMetadataUtilityBlueprintLibrary.cpp +++ b/Source/CesiumRuntime/Private/CesiumMetadataUtilityBlueprintLibrary.cpp @@ -3,7 +3,6 @@ PRAGMA_DISABLE_DEPRECATION_WARNINGS #include "CesiumMetadataUtilityBlueprintLibrary.h" -#include "CesiumFeatureIdAttribute.h" #include "CesiumFeatureIdTexture.h" #include "CesiumGltfComponent.h" #include "CesiumGltfPrimitiveComponent.h" @@ -51,8 +50,6 @@ UCesiumMetadataUtilityBlueprintLibrary::GetMetadataValuesForFace( const FCesiumPrimitiveMetadata& primitiveMetadata = pGltfComponent->Metadata; // For now, only considers the first feature ID set - // TODO: expand to arbitrary number of features once testing data is - // available const FCesiumFeatureIdSet& featureIDSet = featureIDSets[0]; const int64 propertyTableIndex = UCesiumFeatureIdSetBlueprintLibrary::GetPropertyTableIndex(featureIDSet); @@ -69,8 +66,8 @@ UCesiumMetadataUtilityBlueprintLibrary::GetMetadataValuesForFace( int64 featureID = UCesiumPrimitiveFeaturesBlueprintLibrary::GetFeatureIDFromFace( features, - featureIDSet, - FaceIndex); + FaceIndex, + 0); if (featureID < 0) { return TMap(); } diff --git a/Source/CesiumRuntime/Private/CesiumPrimitiveFeatures.cpp b/Source/CesiumRuntime/Private/CesiumPrimitiveFeatures.cpp index 876dd4e53..01db98902 100644 --- a/Source/CesiumRuntime/Private/CesiumPrimitiveFeatures.cpp +++ b/Source/CesiumRuntime/Private/CesiumPrimitiveFeatures.cpp @@ -128,10 +128,15 @@ int64 UCesiumPrimitiveFeaturesBlueprintLibrary::GetFirstVertexFromFace( int64 UCesiumPrimitiveFeaturesBlueprintLibrary::GetFeatureIDFromFace( UPARAM(ref) const FCesiumPrimitiveFeatures& PrimitiveFeatures, - UPARAM(ref) const FCesiumFeatureIdSet& FeatureIDSet, - int64 FaceIndex) { + int64 FaceIndex, + int64 FeatureIDSetIndex) { + if (FeatureIDSetIndex < 0 || + FeatureIDSetIndex > PrimitiveFeatures._featureIDSets.Num()) { + return -1; + } + return UCesiumFeatureIdSetBlueprintLibrary::GetFeatureIDForVertex( - FeatureIDSet, + PrimitiveFeatures._featureIDSets[FeatureIDSetIndex], UCesiumPrimitiveFeaturesBlueprintLibrary::GetFirstVertexFromFace( PrimitiveFeatures, FaceIndex)); diff --git a/Source/CesiumRuntime/Private/CesiumSubLevelSwitcherComponent.cpp b/Source/CesiumRuntime/Private/CesiumSubLevelSwitcherComponent.cpp index 5e2955b33..ed83985c3 100644 --- a/Source/CesiumRuntime/Private/CesiumSubLevelSwitcherComponent.cpp +++ b/Source/CesiumRuntime/Private/CesiumSubLevelSwitcherComponent.cpp @@ -1,4 +1,5 @@ #include "CesiumSubLevelSwitcherComponent.h" +#include "CesiumRuntime.h" #include "CesiumSubLevelComponent.h" #include "Engine/LevelStreaming.h" #include "Engine/World.h" diff --git a/Source/CesiumRuntime/Private/Tests/CesiumGltfSpecUtility.h b/Source/CesiumRuntime/Private/Tests/CesiumGltfSpecUtility.h index 0680bc40e..41788da24 100644 --- a/Source/CesiumRuntime/Private/Tests/CesiumGltfSpecUtility.h +++ b/Source/CesiumRuntime/Private/Tests/CesiumGltfSpecUtility.h @@ -117,21 +117,22 @@ CesiumGltf::PropertyTableProperty& AddPropertyTablePropertyToModel( const std::string& type, const std::optional& componentType, const std::vector& values) { - ExtensionModelExtStructuralMetadata* pExtension = - model.getExtension(); + CesiumGltf::ExtensionModelExtStructuralMetadata* pExtension = + model.getExtension(); if (pExtension == nullptr) { - pExtension = &model.addExtension(); + pExtension = + &model.addExtension(); } if (!pExtension->schema) { pExtension->schema.emplace(); } - Schema& schema = *pExtension->schema; + CesiumGltf::Schema& schema = *pExtension->schema; const std::string& className = propertyTable.classProperty; CesiumGltf::Class& theClass = schema.classes[className]; - ClassProperty& classProperty = theClass.properties[propertyName]; + CesiumGltf::ClassProperty& classProperty = theClass.properties[propertyName]; classProperty.type = type; classProperty.componentType = componentType; diff --git a/Source/CesiumRuntime/Private/Tests/CesiumPrimitiveFeatures.spec.cpp b/Source/CesiumRuntime/Private/Tests/CesiumPrimitiveFeatures.spec.cpp index c554b7f06..cc28df267 100644 --- a/Source/CesiumRuntime/Private/Tests/CesiumPrimitiveFeatures.spec.cpp +++ b/Source/CesiumRuntime/Private/Tests/CesiumPrimitiveFeatures.spec.cpp @@ -328,14 +328,52 @@ void FCesiumPrimitiveFeaturesSpec::Define() { primitiveFeatures); TestEqual( - "FeatureIDForOutOfBoundsFace", + "FeatureIDForPrimitiveWithNoSets", UCesiumPrimitiveFeaturesBlueprintLibrary::GetFeatureIDFromFace( primitiveFeatures, - featureIDSets[0], 0), -1); }); + It("returns -1 for out of bounds feature ID set index", [this]() { + std::vector attributeIDs{1, 1, 1, 1, 0, 0, 0}; + AddFeatureIDsAsAttributeToModel(model, *pPrimitive, attributeIDs, 2, 0); + + const std::vector indices{0, 1, 2, 0, 2, 3, 4, 5, 6}; + CreateIndicesForPrimitive( + model, + *pPrimitive, + AccessorSpec::Type::SCALAR, + AccessorSpec::ComponentType::UNSIGNED_BYTE, + indices); + + Accessor& accessor = model.accessors.emplace_back(); + accessor.count = 7; + pPrimitive->attributes.insert( + {"POSITION", static_cast(model.accessors.size() - 1)}); + + FCesiumPrimitiveFeatures primitiveFeatures = + FCesiumPrimitiveFeatures(model, *pPrimitive, *pExtension); + const TArray& featureIDSets = + UCesiumPrimitiveFeaturesBlueprintLibrary::GetFeatureIDSets( + primitiveFeatures); + + TestEqual( + "FeatureIDForOutOfBoundsSetIndex", + UCesiumPrimitiveFeaturesBlueprintLibrary::GetFeatureIDFromFace( + primitiveFeatures, + 0, + -1), + -1); + TestEqual( + "FeatureIDForOutOfBoundsSetIndex", + UCesiumPrimitiveFeaturesBlueprintLibrary::GetFeatureIDFromFace( + primitiveFeatures, + 0, + 2), + -1); + }); + Describe("FeatureIDAttribute", [this]() { It("returns -1 for out-of-bounds face index", [this]() { std::vector attributeIDs{1, 1, 1}; @@ -356,22 +394,17 @@ void FCesiumPrimitiveFeaturesSpec::Define() { FCesiumPrimitiveFeatures primitiveFeatures = FCesiumPrimitiveFeatures(model, *pPrimitive, *pExtension); - const TArray& featureIDSets = - UCesiumPrimitiveFeaturesBlueprintLibrary::GetFeatureIDSets( - primitiveFeatures); TestEqual( "FeatureIDForNegativeFace", UCesiumPrimitiveFeaturesBlueprintLibrary::GetFeatureIDFromFace( primitiveFeatures, - featureIDSets[0], -1), -1); TestEqual( "FeatureIDForOutOfBoundsFace", UCesiumPrimitiveFeaturesBlueprintLibrary::GetFeatureIDFromFace( primitiveFeatures, - featureIDSets[0], 2), -1); }); @@ -387,9 +420,6 @@ void FCesiumPrimitiveFeaturesSpec::Define() { FCesiumPrimitiveFeatures primitiveFeatures = FCesiumPrimitiveFeatures(model, *pPrimitive, *pExtension); - const TArray& featureIDSets = - UCesiumPrimitiveFeaturesBlueprintLibrary::GetFeatureIDSets( - primitiveFeatures); const size_t numFaces = static_cast(accessor.count / 3); for (size_t i = 0; i < numFaces; i++) { @@ -397,7 +427,6 @@ void FCesiumPrimitiveFeaturesSpec::Define() { "FeatureIDForFace", UCesiumPrimitiveFeaturesBlueprintLibrary::GetFeatureIDFromFace( primitiveFeatures, - featureIDSets[0], static_cast(i)), attributeIDs[i * 3]); } @@ -422,9 +451,6 @@ void FCesiumPrimitiveFeaturesSpec::Define() { FCesiumPrimitiveFeatures primitiveFeatures = FCesiumPrimitiveFeatures(model, *pPrimitive, *pExtension); - const TArray& featureIDSets = - UCesiumPrimitiveFeaturesBlueprintLibrary::GetFeatureIDSets( - primitiveFeatures); const size_t numFaces = indices.size() / 3; for (size_t i = 0; i < numFaces; i++) { @@ -432,7 +458,6 @@ void FCesiumPrimitiveFeaturesSpec::Define() { "FeatureIDForFace", UCesiumPrimitiveFeaturesBlueprintLibrary::GetFeatureIDFromFace( primitiveFeatures, - featureIDSets[0], static_cast(i)), attributeIDs[i * 3]); } @@ -471,22 +496,17 @@ void FCesiumPrimitiveFeaturesSpec::Define() { FCesiumPrimitiveFeatures primitiveFeatures = FCesiumPrimitiveFeatures(model, *pPrimitive, *pExtension); - const TArray& featureIDSets = - UCesiumPrimitiveFeaturesBlueprintLibrary::GetFeatureIDSets( - primitiveFeatures); TestEqual( "FeatureIDForNegativeFace", UCesiumPrimitiveFeaturesBlueprintLibrary::GetFeatureIDFromFace( primitiveFeatures, - featureIDSets[0], -1), -1); TestEqual( "FeatureIDForOutOfBoundsFace", UCesiumPrimitiveFeaturesBlueprintLibrary::GetFeatureIDFromFace( primitiveFeatures, - featureIDSets[0], 2), -1); }); @@ -517,22 +537,17 @@ void FCesiumPrimitiveFeaturesSpec::Define() { FCesiumPrimitiveFeatures primitiveFeatures = FCesiumPrimitiveFeatures(model, *pPrimitive, *pExtension); - const TArray& featureIDSets = - UCesiumPrimitiveFeaturesBlueprintLibrary::GetFeatureIDSets( - primitiveFeatures); TestEqual( "FeatureIDForFace", UCesiumPrimitiveFeaturesBlueprintLibrary::GetFeatureIDFromFace( primitiveFeatures, - featureIDSets[0], 0), 0); TestEqual( "FeatureIDForFace", UCesiumPrimitiveFeaturesBlueprintLibrary::GetFeatureIDFromFace( primitiveFeatures, - featureIDSets[0], 1), 3); }); @@ -569,22 +584,17 @@ void FCesiumPrimitiveFeaturesSpec::Define() { FCesiumPrimitiveFeatures primitiveFeatures = FCesiumPrimitiveFeatures(model, *pPrimitive, *pExtension); - const TArray& featureIDSets = - UCesiumPrimitiveFeaturesBlueprintLibrary::GetFeatureIDSets( - primitiveFeatures); TestEqual( "FeatureIDForFace", UCesiumPrimitiveFeaturesBlueprintLibrary::GetFeatureIDFromFace( primitiveFeatures, - featureIDSets[0], 0), 0); TestEqual( "FeatureIDForFace", UCesiumPrimitiveFeaturesBlueprintLibrary::GetFeatureIDFromFace( primitiveFeatures, - featureIDSets[0], 1), 2); }); @@ -604,22 +614,17 @@ void FCesiumPrimitiveFeaturesSpec::Define() { FCesiumPrimitiveFeatures primitiveFeatures = FCesiumPrimitiveFeatures(model, *pPrimitive, *pExtension); - const TArray& featureIDSets = - UCesiumPrimitiveFeaturesBlueprintLibrary::GetFeatureIDSets( - primitiveFeatures); TestEqual( "FeatureIDForNegativeFace", UCesiumPrimitiveFeaturesBlueprintLibrary::GetFeatureIDFromFace( primitiveFeatures, - featureIDSets[0], -1), -1); TestEqual( "FeatureIDForOutOfBoundsFace", UCesiumPrimitiveFeaturesBlueprintLibrary::GetFeatureIDFromFace( primitiveFeatures, - featureIDSets[0], 10), -1); }); @@ -632,22 +637,17 @@ void FCesiumPrimitiveFeaturesSpec::Define() { FCesiumPrimitiveFeatures primitiveFeatures = FCesiumPrimitiveFeatures(model, *pPrimitive, *pExtension); - const TArray& featureIDSets = - UCesiumPrimitiveFeaturesBlueprintLibrary::GetFeatureIDSets( - primitiveFeatures); TestEqual( "FeatureIDForFace", UCesiumPrimitiveFeaturesBlueprintLibrary::GetFeatureIDFromFace( primitiveFeatures, - featureIDSets[0], 0), 0); TestEqual( "FeatureIDForFace", UCesiumPrimitiveFeaturesBlueprintLibrary::GetFeatureIDFromFace( primitiveFeatures, - featureIDSets[0], 1), 3); }); @@ -668,25 +668,85 @@ void FCesiumPrimitiveFeaturesSpec::Define() { FCesiumPrimitiveFeatures primitiveFeatures = FCesiumPrimitiveFeatures(model, *pPrimitive, *pExtension); - const TArray& featureIDSets = - UCesiumPrimitiveFeaturesBlueprintLibrary::GetFeatureIDSets( - primitiveFeatures); TestEqual( "FeatureIDForFace", UCesiumPrimitiveFeaturesBlueprintLibrary::GetFeatureIDFromFace( primitiveFeatures, - featureIDSets[0], 0), 2); TestEqual( "FeatureIDForFace", UCesiumPrimitiveFeaturesBlueprintLibrary::GetFeatureIDFromFace( primitiveFeatures, - featureIDSets[0], 1), 3); }); }); + + It("gets feature ID from correct set with specified feature ID set index", + [this]() { + // First feature ID set is attribute + std::vector attributeIDs{1, 1, 1, 1, 0, 0, 0}; + AddFeatureIDsAsAttributeToModel( + model, + *pPrimitive, + attributeIDs, + 2, + 0); + + const std::vector indices{0, 1, 2, 0, 2, 3, 4, 5, 6}; + CreateIndicesForPrimitive( + model, + *pPrimitive, + AccessorSpec::Type::SCALAR, + AccessorSpec::ComponentType::UNSIGNED_BYTE, + indices); + + Accessor& accessor = model.accessors.emplace_back(); + accessor.count = 7; + pPrimitive->attributes.insert( + {"POSITION", static_cast(model.accessors.size() - 1)}); + + // Second feature ID set is implicit + FeatureId& implicitIDs = pExtension->featureIds.emplace_back(); + implicitIDs.featureCount = 7; + + FCesiumPrimitiveFeatures primitiveFeatures = + FCesiumPrimitiveFeatures(model, *pPrimitive, *pExtension); + + const TArray& featureIDSets = + UCesiumPrimitiveFeaturesBlueprintLibrary::GetFeatureIDSets( + primitiveFeatures); + TestEqual("FeatureIDSetCount", featureIDSets.Num(), 2); + + int64 setIndex = 0; + for (size_t index = 0; index < indices.size(); index += 3) { + std::string label("FeatureIDAttribute" + std::to_string(index)); + int64 faceIndex = static_cast(index) / 3; + int64 featureID = static_cast(attributeIDs[indices[index]]); + TestEqual( + FString(label.c_str()), + UCesiumPrimitiveFeaturesBlueprintLibrary::GetFeatureIDFromFace( + primitiveFeatures, + faceIndex, + setIndex), + featureID); + } + + setIndex = 1; + for (size_t index = 0; index < indices.size(); index += 3) { + std::string label("ImplicitFeatureID" + std::to_string(index)); + int64 faceIndex = static_cast(index) / 3; + int64 featureID = static_cast(indices[index]); + TestEqual( + FString(label.c_str()), + UCesiumPrimitiveFeaturesBlueprintLibrary::GetFeatureIDFromFace( + primitiveFeatures, + faceIndex, + setIndex), + featureID); + } + }); }); } diff --git a/Source/CesiumRuntime/Public/CesiumFeatureIdTexture.h b/Source/CesiumRuntime/Public/CesiumFeatureIdTexture.h index d6838d2ee..0233a04cc 100644 --- a/Source/CesiumRuntime/Public/CesiumFeatureIdTexture.h +++ b/Source/CesiumRuntime/Public/CesiumFeatureIdTexture.h @@ -2,6 +2,7 @@ #pragma once +#include "CesiumGltf/AccessorView.h" #include "CesiumGltf/FeatureIdTextureView.h" #include "Containers/UnrealString.h" #include "Kismet/BlueprintFunctionLibrary.h" diff --git a/Source/CesiumRuntime/Public/CesiumMetadataPickingBlueprintLibrary.h b/Source/CesiumRuntime/Public/CesiumMetadataPickingBlueprintLibrary.h index 810693fc1..8847841b1 100644 --- a/Source/CesiumRuntime/Public/CesiumMetadataPickingBlueprintLibrary.h +++ b/Source/CesiumRuntime/Public/CesiumMetadataPickingBlueprintLibrary.h @@ -2,13 +2,12 @@ #pragma once +#include "CesiumMetadataValue.h" #include "Containers/UnrealString.h" #include "Kismet/BlueprintFunctionLibrary.h" #include "UObject/ObjectMacros.h" #include "CesiumMetadataPickingBlueprintLibrary.generated.h" -struct FCesiumMetadataValue; - UCLASS() class CESIUMRUNTIME_API UCesiumMetadataPickingBlueprintLibrary : public UBlueprintFunctionLibrary { diff --git a/Source/CesiumRuntime/Public/CesiumMetadataPropertyDetails.h b/Source/CesiumRuntime/Public/CesiumMetadataPropertyDetails.h index d48105968..5fc6a0ec7 100644 --- a/Source/CesiumRuntime/Public/CesiumMetadataPropertyDetails.h +++ b/Source/CesiumRuntime/Public/CesiumMetadataPropertyDetails.h @@ -75,7 +75,7 @@ struct CESIUMRUNTIME_API FCesiumMetadataPropertyDetails { Category = "Cesium", Meta = (EditCondition = - "(Type != ECesiumMetadataType::Invalid && Type != ECesiumMetadataType::Boolean && Type != ECesiumMetadataType::Enum && Type != ECesiumMetadataType::String) && (ComponentType != ECesiumMetadataComponentType::None && ComponentType != ECesiumMetadataComponentType::Float32 && ComponentType != ECesiumMetadataComponentType::Float64)")) + "Type != ECesiumMetadataType::Invalid && Type != ECesiumMetadataType::Boolean && Type != ECesiumMetadataType::Enum && Type != ECesiumMetadataType::String && ComponentType != ECesiumMetadataComponentType::None && ComponentType != ECesiumMetadataComponentType::Float32 && ComponentType != ECesiumMetadataComponentType::Float64")) bool bIsNormalized; // TODO: scale and offset, no data + default value diff --git a/Source/CesiumRuntime/Public/CesiumMetadataUtilityBlueprintLibrary.h b/Source/CesiumRuntime/Public/CesiumMetadataUtilityBlueprintLibrary.h index 832abe990..1b407f5e3 100644 --- a/Source/CesiumRuntime/Public/CesiumMetadataUtilityBlueprintLibrary.h +++ b/Source/CesiumRuntime/Public/CesiumMetadataUtilityBlueprintLibrary.h @@ -2,6 +2,8 @@ #pragma once +#include "CesiumFeatureIdAttribute.h" +#include "CesiumMetadataPrimitive.h" #include "CesiumMetadataValue.h" #include "CesiumPrimitiveMetadata.h" #include "Containers/UnrealString.h" @@ -9,8 +11,6 @@ #include "UObject/ObjectMacros.h" #include "CesiumMetadataUtilityBlueprintLibrary.generated.h" -struct FCesiumFeatureIdAttribute; - UCLASS() class CESIUMRUNTIME_API UCesiumMetadataUtilityBlueprintLibrary : public UBlueprintFunctionLibrary { diff --git a/Source/CesiumRuntime/Public/CesiumPrimitiveFeatures.h b/Source/CesiumRuntime/Public/CesiumPrimitiveFeatures.h index 1a6deef59..1a10fcf51 100644 --- a/Source/CesiumRuntime/Public/CesiumPrimitiveFeatures.h +++ b/Source/CesiumRuntime/Public/CesiumPrimitiveFeatures.h @@ -120,13 +120,12 @@ class CESIUMRUNTIME_API UCesiumPrimitiveFeaturesBlueprintLibrary int64 FaceIndex); /** - * Gets the feature ID associated with the given face and feature ID set. - * - * This does not interface well with feature ID textures or implicit feature - * IDs, since these feature ID types make it possible for a face to have - * multiple feature IDs. In these cases, the feature ID of the first - * vertex of the face is returned. + * Gets the feature ID associated with the given face. * + * 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, @@ -134,6 +133,6 @@ class CESIUMRUNTIME_API UCesiumPrimitiveFeaturesBlueprintLibrary Category = "Cesium|Primitive|Features") static int64 GetFeatureIDFromFace( UPARAM(ref) const FCesiumPrimitiveFeatures& PrimitiveFeatures, - UPARAM(ref) const FCesiumFeatureIdSet& FeatureIDSet, - int64 FaceIndex); + int64 FaceIndex, + int64 FeatureIDSetIndex = 0); }; diff --git a/Source/CesiumRuntime/Public/CesiumPrimitiveMetadata.h b/Source/CesiumRuntime/Public/CesiumPrimitiveMetadata.h index e6f780167..1c2cef99f 100644 --- a/Source/CesiumRuntime/Public/CesiumPrimitiveMetadata.h +++ b/Source/CesiumRuntime/Public/CesiumPrimitiveMetadata.h @@ -8,6 +8,8 @@ #include "CesiumPrimitiveMetadata.generated.h" namespace CesiumGltf { +struct Model; +struct MeshPrimitive; struct ExtensionMeshPrimitiveExtStructuralMetadata; } // namespace CesiumGltf @@ -33,7 +35,7 @@ struct CESIUMRUNTIME_API FCesiumPrimitiveMetadata { * @param model The model containing a EXT_structural_metadata extension * @param primitive The mesh primitive containing the EXT_feature_metadata * extension - * @param metadata The EXT_structural_metadata of the gltf mesh primitive. + * @param metadata The EXT_structural_metadata of the glTF mesh primitive. */ FCesiumPrimitiveMetadata( const CesiumGltf::Model& InModel,