// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "TransformCollection.h" #include "Misc/Crc.h" #include "GeometryCollection/GeometryCollectionConvexPropertiesInterface.h" #include "GeometryCollection/GeometryCollectionProximityPropertiesInterface.h" #include "GeometryCollection/ManagedArrayAccessor.h" #include "GeometryCollection/Facades/CollectionUVFacade.h" namespace Chaos { class FChaosArchive; } class FGeometryCollectionConvexPropertiesInterface; class FGeometryCollectionProximityPropertiesInterface; struct FGeometryCollectionDefaults { FLinearColor DefaultVertexColor = FLinearColor::White; }; /** * FGeometryCollection (FTransformCollection) */ class FGeometryCollection : public FTransformCollection, public FGeometryCollectionConvexPropertiesInterface, public FGeometryCollectionProximityPropertiesInterface { public: typedef FTransformCollection Super; CHAOS_API FGeometryCollection(FGeometryCollectionDefaults InDefaults = FGeometryCollectionDefaults() ); CHAOS_API ~FGeometryCollection(); FGeometryCollection(FGeometryCollection &) = delete; FGeometryCollection& operator=(const FGeometryCollection &) = delete; FGeometryCollection(FGeometryCollection &&) = default; FGeometryCollection& operator=(FGeometryCollection &&) = default; MANAGED_ARRAY_COLLECTION_INTERNAL(FGeometryCollection); /*** * Attribute Groups * * These attribute groups are predefined data member of the FGeometryCollection. * * VerticesGroup ("Vertices") * * FVectorArray Vertex = GetAttribute("Vertex", VerticesGroup) * FInt32Array BoneMap = GetAttribute("BoneMap", VerticesGroup, {"Transform"}) * FVectorArray Normal = GetAttribute("Normal", MaterialGroup) * FVector2DArray UVs = GetAttribute>("UVs", MaterialGroup) * FVectorArray TangentU = GetAttribute("TangentU", MaterialGroup) * FVectorArray TangentV = GetAttribute("TangentV", MaterialGroup) * FLinearColorArray Color = GetAttribute("Color", MaterialGroup) * * The VerticesGroup will store per-vertex information about the geometry. For * example, the "Position" attribute stores a FVector array for the relative * offset of a vertex from the geometries geometric center, and the "BoneMap" * attribute stores an index in to the TransformGroups Transform array so that * the local space vertices may be mapped in to world space positions. * * FacesGroup ("Faces") * Default Attributes : * * FIntVectorArray Indices = GetAttribute("Indices", FacesGroup, {"Faces"}) * FBoolArray Visible = GetAttribute("Visible", FacesGroup) * FInt32Array MaterialIndex = GetAttribute("MaterialIndex", FacesGroup) * FInt32Array MaterialID = GetAttribute("MaterialID", FacesGroup) * * The FacesGroup will store the triangulated face data, and any other information * that is associated with the faces of the geometry. The "Triangle" attribute is * stored as Vector, and represents the vertices of a individual triangle. * * GeometryGroup ("Geometry") * Default Attributes : * * FInt32Array TransformIndex = GetAttribute("TransformIndex", GeometryGroup, {"Transform"}) * FBoxArray BoundingBox = GetAttribute("BoundingBox", GeometryGroup) * FIntArray FaceStart = GetAttribute("FaceStart", GeometryGroup) * FIntArray FaceCount = GetAttribute("FaceCount", GeometryGroup) * FIntArray VertexStart = GetAttribute("VertexStart", GeometryGroup) * FIntArray VertexCount = GetAttribute("VertexCount", GeometryGroup) * * The GeometryGroup will store the transform indices, bounding boxes and any other information * that is associated with the geometry. * * MaterialGroup ("Material") * Default Attributes : * * FGeometryCollectionSection Sections = GetAttribute("Sections", MaterialGroup) * * The set of triangles which are rendered with the same material */ static CHAOS_API const FName VerticesGroup; // Vertices static CHAOS_API const FName FacesGroup; // Faces static CHAOS_API const FName GeometryGroup; // Geometry static CHAOS_API const FName BreakingGroup; // Breaking static CHAOS_API const FName MaterialGroup; // Materials static CHAOS_API const FName SimulatableParticlesAttribute; static CHAOS_API const FName SimulationTypeAttribute; static CHAOS_API const FName StatusFlagsAttribute; static CHAOS_API const FName ExternalCollisionsAttribute; static CHAOS_API const FName ColorAttribute; static CHAOS_API const FName BoneColorAttribute; static CHAOS_API const FName TransformToGeometryIndexAttribute; static CHAOS_API const FName BoundingBoxAttribute; static CHAOS_API const FName TransformIndexAttribute; static CHAOS_API const FName VertexStartAttribute; static CHAOS_API const FName VertexCountAttribute; static CHAOS_API const FName InnerRadiusAttribute; static CHAOS_API const FName OuterRadiusAttribute; static CHAOS_API const FName FaceStartAttribute; static CHAOS_API const FName FaceCountAttribute; static CHAOS_API const FName FaceIndicesAttribute; static CHAOS_API const FName FaceVisibleAttribute; static CHAOS_API const FName MaterialIndexAttribute; static CHAOS_API const FName MaterialIDAttribute; static CHAOS_API const FName VertexPositionAttribute; static CHAOS_API const FName VertexNormalAttribute; static CHAOS_API const FName VertexTangentUAttribute; static CHAOS_API const FName VertexTangentVAttribute; static CHAOS_API const FName VertexBoneMapAttribute; enum ESimulationTypes : uint8 { FST_None = 0, FST_Rigid = 1, FST_Clustered = 2, FST_Max = 3 }; enum ENodeFlags : uint32 { // additional flags FS_None = 0, // identify nodes that should be removed from the simulation instead of becoming a fractured body FS_RemoveOnFracture = 0x00000004, FS_IgnoreCollisionInParentCluster = 0x00000008 }; static CHAOS_API bool AreCollisionParticlesEnabled(); /** * Create a GeometryCollection from Vertex and Indices arrays */ static CHAOS_API FGeometryCollection* NewGeometryCollection(const TArray& RawVertexArray, const TArray& RawIndicesArray, bool ReverseVertexOrder = true, FGeometryCollectionDefaults InDefaults = FGeometryCollectionDefaults()); static CHAOS_API void Init(FGeometryCollection* Collection, const TArray& RawVertexArray, const TArray& RawIndicesArray, bool ReverseVertexOrder = true); static CHAOS_API void DefineGeometrySchema(FManagedArrayCollection&); /** * Create a GeometryCollection from Vertex, Indices, BoneMap, Transform, BoneHierarchy arrays */ static CHAOS_API FGeometryCollection* NewGeometryCollection(const TArray& RawVertexArray, const TArray& RawIndicesArray, const TArray& RawBoneMapArray, const TArray& RawTransformArray, const TManagedArray& RawLevelArray, const TManagedArray& RawParentArray, const TManagedArray>& RawChildrenArray, const TManagedArray& RawSimulationTypeArray, const TManagedArray& RawStatusFlagsArray, FGeometryCollectionDefaults InDefaults = FGeometryCollectionDefaults()); /** * Append a FGeometryCollection to a FGeometryCollection */ CHAOS_API void AppendCollection(const FGeometryCollection& InCollection); /** * Append a single geometric object to a FGeometryCollection */ CHAOS_API int32 AppendGeometry(const FGeometryCollection & GeometryCollection, int32 MaterialIDOffset = 0, bool ReindexAllMaterials = true, const FTransform& TransformRoot = FTransform::Identity); /** * Append single embedded geometry. Returns true if the operation succeeds. */ CHAOS_API bool AppendEmbeddedInstance(int32 InExemplarIndex, int32 InParentIndex, const FTransform& InTransform = FTransform::Identity); /** * Reindex exemplar indices to reflect removed exemplars. */ CHAOS_API void ReindexExemplarIndices(TArray& SortedRemovedIndices); /** * Remove Geometry and update dependent elements */ CHAOS_API virtual void RemoveElements(const FName & Group, const TArray& SortedDeletionList, FProcessingParameters Params = FProcessingParameters()) override; /** * Empty each managed array in each group in order to reset the collection to an initial (empty) state. */ CHAOS_API void Empty(); /** * reset internal state */ CHAOS_API virtual void Reset() override; /** * Reorders elements in a group. NewOrder must be the same length as the group. */ CHAOS_API virtual void ReorderElements(FName Group, const TArray& NewOrder) override; // // // // Initialize any interfaces on the geometry collection (i.e., the FGeometryCollectionConvexPropertiesInterface) CHAOS_API virtual void InitializeInterfaces(); /** * Update bounding box entries for the geometry */ CHAOS_API void UpdateBoundingBox(); static CHAOS_API void UpdateBoundingBox(FManagedArrayCollection&, bool bSkipCheck=false); /** * GetBoundingBox */ CHAOS_API FBoxSphereBounds GetBoundingBox() const; /** * Update the visibility of specified geometry nodes */ CHAOS_API void UpdateGeometryVisibility(const TArray& NodeList, bool VisibilityState); /** * Reindex sections to keep polys with same materials together to reduce the number of draw calls */ CHAOS_API void ReindexMaterials(); static CHAOS_API void ReindexMaterials(FManagedArrayCollection&); /** * Builds mesh sections for a given index buffer that could be a subset. * Currently, this call assumes that the indices are ordered by MaterialID * #todo(dmp): Refactor this and ReindexMaterials to share code */ CHAOS_API TArray BuildMeshSections(const TArray &Indices, const TArray& BaseMeshOriginalIndicesIndex, TArray &RetIndices) const; // // // /** Returns true if there is anything to render */ CHAOS_API bool HasVisibleGeometry() const; /** Returns true if the vertices are contiguous*/ CHAOS_API bool HasContiguousVertices() const; /** Returns true if the faces are contiguous*/ CHAOS_API bool HasContiguousFaces() const; /** Returns true if the render faces are contiguous*/ CHAOS_API bool HasContiguousRenderFaces() const; /** Returns number of UV layers represented by UV array. A Valid Geometry Collection has the same count for every vertex */ CHAOS_API int32 NumUVLayers() const; /** Update a geometry collection to have the target number of UV layers (must be in the range [1, MAX_UV_LAYERS)) */ CHAOS_API bool SetNumUVLayers(int32 NumLayers); FORCEINLINE bool IsGeometry(int32 Element) const { return TransformToGeometryIndex[Element] != INDEX_NONE; } FORCEINLINE bool IsClustered(int32 Element) const { const TManagedArray& SimType = SimulationType; return !!(SimType[Element] == ESimulationTypes::FST_Clustered); } FORCEINLINE bool IsRigid(int32 Element) const { const TManagedArray& SimType = SimulationType; return !!(SimType[Element] == ESimulationTypes::FST_Rigid); } FORCEINLINE bool IsTransform(int32 Element) const { return !IsGeometry(Element); } FORCEINLINE void SetFlags(int32 Element, int32 InFlags) { TManagedArray& Status = StatusFlags; Status[Element] |= InFlags; } FORCEINLINE void ClearFlags(int32 Element, int32 InFlags) { TManagedArray& Status = StatusFlags; Status[Element] = Status[Element] & ~InFlags; } FORCEINLINE bool HasFlags(int32 Element, int32 InFlags) const { const TManagedArray& Status = StatusFlags; return (Status[Element] & InFlags) != 0; } /** Return true if the Element contains any visible faces. */ CHAOS_API bool IsVisible(int32 Element) const; /** Connection of leaf geometry */ CHAOS_API TArray> ConnectionGraph(); // // // /** Serialize */ CHAOS_API void Serialize(Chaos::FChaosArchive& Ar); /** */ CHAOS_API void WriteDataToHeaderFile(const FString &Name, const FString &Path); /** */ CHAOS_API void WriteDataToOBJFile(const FString &Name, const FString &Path, const bool WriteTopology=true, const bool WriteAuxStructures=true); // // // FGeometryCollectionDefaults Defaults; CHAOS_API virtual void SetDefaults(FName Group, uint32 StartSize, uint32 NumElements) override; // Transform Group TManagedArray TransformToGeometryIndex; TManagedArray SimulationType; TManagedArray StatusFlags; TManagedArray InitialDynamicState; TManagedArray ExemplarIndex; // Vertices Group TManagedArray Vertex; // Note: UVs have been reworked, and unfortunately there is not a safe path to provide the original UVs managed array as a deprecated accessor. // They are now stored in dynamically allocated attributes per UV channel (/ layer) // See Facades/CollectionUVFacade.h for a more complete interface to access UV layers, // but accesses of the form Collection.UVs[Vertex][Layer] can be replaced with Collection.GetUV(Vertex, Layer) (or ModifyUV) FVector2f& ModifyUV(int32 VertexIndex, int32 UVLayer) { return GeometryCollection::UV::ModifyUVLayer(*this, UVLayer)[VertexIndex]; } const FVector2f& GetUV(int32 VertexIndex, int32 UVLayer) const { return GeometryCollection::UV::GetUVLayer(*this, UVLayer)[VertexIndex]; } inline TManagedArray* FindUVLayer(int32 UVLayer) { return GeometryCollection::UV::FindUVLayer(*this, UVLayer); } inline const TManagedArray* FindUVLayer(int32 UVLayer) const { return GeometryCollection::UV::FindUVLayer(*this, UVLayer); } TManagedArray Color; TManagedArray TangentU; TManagedArray TangentV; TManagedArray Normal; TManagedArray BoneMap; // Faces Group TManagedArray Indices; TManagedArray Visible; TManagedArray MaterialIndex; TManagedArray MaterialID; TManagedArray Internal; // Geometry Group TManagedArray TransformIndex; TManagedArray BoundingBox; TManagedArray InnerRadius; TManagedArray OuterRadius; TManagedArray VertexStart; TManagedArray VertexCount; TManagedArray FaceStart; TManagedArray FaceCount; // Material Group TManagedArray Sections; protected: /** * Virtual helper function called by CopyMatchingAttributesFrom; adds attributes 'default, but optional' attributes that are present in InCollection * This is used by FGeometryCollection to make sure all UV layers are copied over by CopyMatchingAttributesFrom() */ virtual void MatchOptionalDefaultAttributes(const FManagedArrayCollection& InCollection) override { GeometryCollection::UV::MatchUVLayerCount(*this, InCollection); } CHAOS_API void Construct(); /** * Remove Geometry elements i.e. verts, faces, etc, leaving the transform nodes intact */ CHAOS_API void RemoveGeometryElements(const TArray& SortedGeometryIndicesToDelete); /** * Update Face Attributes based on changes in the group. */ CHAOS_API bool BuildFaceToGeometryMapping(bool InSaved=false); CHAOS_API void UpdateFaceGroupElements(); /** * Build and Update Vertex Attributes based on changes in the group. */ CHAOS_API bool BuildVertexToGeometryMapping(bool InSaved = false); CHAOS_API void UpdateVerticesGroupElements(); /** * Reorder geometry elements. i.e. verts faces etc are reordered so we can get contiguous memory access */ CHAOS_API void ReorderGeometryElements(const TArray& NewOrder); /** * Reorder geometry elements based on the new transform order. i.e. verts faces etc are reordered so we can get contiguous memory access */ CHAOS_API void ReorderTransformElements(const TArray& NewOrder); /** * @return the latest Version number used in serialization */ constexpr int32 GetLatestVersionNumber() const { return 10; } CHAOS_API virtual void Append(const FManagedArrayCollection& InCollection) override; public: /* Backwards compatibility */ CHAOS_API void UpdateOldAttributeNames(); CHAOS_API TArray TransformSelectionToGeometryIndices(const TArray& Transforms); }; FORCEINLINE Chaos::FChaosArchive& operator<<(Chaos::FChaosArchive& Ar, FGeometryCollection& Value) { Value.Serialize(Ar); return Ar; }