// Copyright Epic Games, Inc. All Rights Reserved. #include "GeometryCollection/Facades/CollectionCurveFacade.h" #include "GeometryCollection/GeometryCollection.h" namespace GeometryCollection::Facades { // Curves facade Groups const FName FCollectionCurveGeometryFacade::CurvesGroup("Curves"); const FName FCollectionCurveGeometryFacade::PointsGroup("Points"); // Curves geometry facade attributes const FName FCollectionCurveGeometryFacade::CurvePointOffsetsAttribute("PointOffset"); const FName FCollectionCurveGeometryFacade::PointCurveIndicesAttribute("CurveIndex"); const FName FCollectionCurveGeometryFacade::GeometryCurveOffsetsAttribute("CurveOffset"); const FName FCollectionCurveGeometryFacade::CurveGeometryIndicesAttribute("GeometryIndex"); const FName FCollectionCurveGeometryFacade::PointRestOrientationsAttribute("RestOrientation"); const FName FCollectionCurveGeometryFacade::PointRestPositionsAttribute("RestPosition"); const FName FCollectionCurveGeometryFacade::GeometryGroupNamesAttribute("GroupName"); const FName FCollectionCurveGeometryFacade::GeometryCurveThicknessAttribute("CurveThickness"); const FName FCollectionCurveGeometryFacade::CurveSourceIndicesAttribute("SourceIndices"); // Curves hierarchy facade attributes const FName FCollectionCurveHierarchyFacade::CurveParentIndicesAttribute("ParentIndices"); const FName FCollectionCurveHierarchyFacade::CurveLodIndicesAttribute("LodIndices"); FCollectionCurveGeometryFacade::FCollectionCurveGeometryFacade(FManagedArrayCollection& InCollection) : ConstCollection(InCollection), Collection(&InCollection), PointRestOrientations(InCollection, PointRestOrientationsAttribute, PointsGroup), PointRestPositions(InCollection, PointRestPositionsAttribute, PointsGroup), CurvePointOffsets(InCollection, CurvePointOffsetsAttribute, CurvesGroup), GeometryCurveOffsets(InCollection, GeometryCurveOffsetsAttribute, FGeometryCollection::GeometryGroup), PointCurveIndices(InCollection, PointCurveIndicesAttribute, PointsGroup), CurveGeometryIndices(InCollection, CurveGeometryIndicesAttribute, CurvesGroup), GeometryGroupNames(InCollection, GeometryGroupNamesAttribute, FGeometryCollection::GeometryGroup), GeometryCurveThickness(InCollection, GeometryCurveThicknessAttribute, FGeometryCollection::GeometryGroup), CurveSourceIndices(InCollection, CurveSourceIndicesAttribute, CurvesGroup) { DefineSchema(); } FCollectionCurveGeometryFacade::FCollectionCurveGeometryFacade(const FManagedArrayCollection& InCollection) : ConstCollection(InCollection), Collection(nullptr), PointRestOrientations(InCollection, PointRestOrientationsAttribute, PointsGroup), PointRestPositions(InCollection, PointRestPositionsAttribute, PointsGroup), CurvePointOffsets(InCollection, CurvePointOffsetsAttribute, CurvesGroup), GeometryCurveOffsets(InCollection, GeometryCurveOffsetsAttribute, FGeometryCollection::GeometryGroup), PointCurveIndices(InCollection, PointCurveIndicesAttribute, PointsGroup), CurveGeometryIndices(InCollection, CurveGeometryIndicesAttribute, CurvesGroup), GeometryGroupNames(InCollection, GeometryGroupNamesAttribute, FGeometryCollection::GeometryGroup), GeometryCurveThickness(InCollection, GeometryCurveThicknessAttribute, FGeometryCollection::GeometryGroup), CurveSourceIndices(InCollection, CurveSourceIndicesAttribute, CurvesGroup) { } bool FCollectionCurveGeometryFacade::IsValid() const { return PointRestOrientations.IsValid() && PointRestPositions.IsValid() && CurvePointOffsets.IsValid() && GeometryCurveOffsets.IsValid() && PointCurveIndices.IsValid() && CurveGeometryIndices.IsValid() && GeometryGroupNames.IsValid() && GeometryCurveThickness.IsValid() && CurveSourceIndices.IsValid(); } void FCollectionCurveGeometryFacade::DefineSchema() { check(!IsConst()); PointRestOrientations.Add(); PointRestPositions.Add(); CurvePointOffsets.Add(); GeometryCurveOffsets.Add(); PointCurveIndices.Add(); CurveGeometryIndices.Add(); GeometryGroupNames.Add(); GeometryCurveThickness.Add(); CurveSourceIndices.Add(); } void FCollectionCurveGeometryFacade::InitCurvesCollection(const TArray& InPointRestPositions, const TArray& InCurvePointOffsets, const TArray& InGeometryCurveOffsets, const TArray& InGeometryGroupNames, const TArray& InGeometryCurveThickness, const TArray& InCurveSourceIndices) { if(Collection) { // Curves group Collection->EmptyGroup(CurvesGroup); Collection->AddElements(InCurvePointOffsets.Num(), CurvesGroup); // Geometry group Collection->EmptyGroup(FGeometryCollection::GeometryGroup); Collection->AddElements(InGeometryCurveOffsets.Num(), FGeometryCollection::GeometryGroup); // Points group Collection->EmptyGroup(PointsGroup); Collection->AddElements(InPointRestPositions.Num(), PointsGroup); // Fill attributes SetGeometryCurveOffsets(InGeometryCurveOffsets); SetCurvePointOffsets(InCurvePointOffsets); SetPointRestPositions(InPointRestPositions); SetGeometryGroupNames(InGeometryGroupNames); SetGeometryCurveThickness(InGeometryCurveThickness); SetCurveSourceIndices(InCurveSourceIndices); // Build the geometry collection BuildGeometryCollection(); } } void FCollectionCurveGeometryFacade::BuildGeometryCollection() { if(Collection) { FGeometryCollection::DefineGeometrySchema(*Collection); // Transform group Collection->EmptyGroup(FGeometryCollection::TransformGroup); Collection->AddElements(GetNumGeometry(), FGeometryCollection::TransformGroup); // Vertices group Collection->EmptyGroup(FGeometryCollection::VerticesGroup); Collection->AddElements(GetNumPoints() * 2, FGeometryCollection::VerticesGroup); // Faces group Collection->EmptyGroup(FGeometryCollection::FacesGroup); Collection->AddElements((GetNumPoints() - GetNumCurves()) * 2, FGeometryCollection::FacesGroup); // Material group Collection->EmptyGroup(FGeometryCollection::MaterialGroup); // Vertices Attributes TManagedArray& VertexPositions = Collection->ModifyAttribute(FGeometryCollection::VertexPositionAttribute, FGeometryCollection::VerticesGroup); TManagedArray& VertexNormals = Collection->ModifyAttribute(FGeometryCollection::VertexNormalAttribute, FGeometryCollection::VerticesGroup); TManagedArray& VertexTangentU = Collection->ModifyAttribute(FGeometryCollection::VertexTangentUAttribute, FGeometryCollection::VerticesGroup); TManagedArray& VertexTangentV = Collection->ModifyAttribute(FGeometryCollection::VertexTangentVAttribute, FGeometryCollection::VerticesGroup); TManagedArray& VertexColors = Collection->ModifyAttribute(FGeometryCollection::ColorAttribute, FGeometryCollection::VerticesGroup); TManagedArray& VertexTransforms = Collection->ModifyAttribute(FGeometryCollection::VertexBoneMapAttribute, FGeometryCollection::VerticesGroup); // Faces Attributes TManagedArray& FaceIndices = Collection->ModifyAttribute(FGeometryCollection::FaceIndicesAttribute, FGeometryCollection::FacesGroup); TManagedArray& FaceVisibles = Collection->ModifyAttribute(FGeometryCollection::FaceVisibleAttribute, FGeometryCollection::FacesGroup); // Geometry Group TManagedArray& TransformIndex = Collection->ModifyAttribute(FGeometryCollection::TransformIndexAttribute, FGeometryCollection::GeometryGroup); TManagedArray& BoundingBox = Collection->ModifyAttribute(FGeometryCollection::BoundingBoxAttribute, FGeometryCollection::GeometryGroup); TManagedArray& VertexStart = Collection->ModifyAttribute(FGeometryCollection::VertexStartAttribute, FGeometryCollection::GeometryGroup); TManagedArray& VertexCount = Collection->ModifyAttribute(FGeometryCollection::VertexCountAttribute, FGeometryCollection::GeometryGroup); TManagedArray& FaceStart = Collection->ModifyAttribute(FGeometryCollection::FaceStartAttribute, FGeometryCollection::GeometryGroup); TManagedArray& FaceCount = Collection->ModifyAttribute(FGeometryCollection::FaceCountAttribute, FGeometryCollection::GeometryGroup); TManagedArray& InnerRadius =Collection->ModifyAttribute(FGeometryCollection::InnerRadiusAttribute, FGeometryCollection::GeometryGroup); TManagedArray& OuterRadius = Collection->ModifyAttribute(FGeometryCollection::OuterRadiusAttribute, FGeometryCollection::GeometryGroup); // Transform group TManagedArray& BoneGeometry = Collection->ModifyAttribute(FTransformCollection::GeometryIndexAttribute, FTransformCollection::TransformGroup); TManagedArray& BoneTransforms = Collection->ModifyAttribute(FTransformCollection::TransformAttribute, FTransformCollection::TransformGroup); TManagedArray& BoneNames = Collection->ModifyAttribute(FTransformCollection::BoneNameAttribute, FTransformCollection::TransformGroup); TManagedArray& BoneColors = Collection->ModifyAttribute(FTransformCollection::BoneColorAttribute , FTransformCollection::TransformGroup); TManagedArray& BoneParent = Collection->ModifyAttribute(FTransformCollection::ParentAttribute, FTransformCollection::TransformGroup); const int32 NumGeometry = GetNumGeometry(); VertexTangentU.Fill(FVector3f::Zero()); VertexTangentV.Fill(FVector3f::Zero()); int32 PointOffset = 0; int32 CurveOffset = 0; for(int32 GeometryIndex = 0; GeometryIndex < NumGeometry; ++GeometryIndex) { const FLinearColor GeometryColor = FLinearColor::IntToDistinctColor(GeometryIndex, 0.75f, 1.0f, 90.0f); // Init geometry/transform attributes BoundingBox[GeometryIndex] = FBox(ForceInitToZero); TransformIndex[GeometryIndex] = GeometryIndex; BoneGeometry[GeometryIndex] = GeometryIndex; BoneTransforms[GeometryIndex] = FTransform3f::Identity; BoneParent[GeometryIndex] = INDEX_NONE; BoneColors[GeometryIndex] = GeometryColor; BoneNames[GeometryIndex] = GeometryGroupNames[GeometryIndex]; VertexStart[GeometryIndex] = PointOffset * 2; FaceStart[GeometryIndex] = (PointOffset-CurveOffset) * 2; VertexCount[GeometryIndex] = 0; FaceCount[GeometryIndex] = 0; InnerRadius[GeometryIndex] = GeometryCurveThickness[GeometryIndex]; OuterRadius[GeometryIndex] = GeometryCurveThickness[GeometryIndex]; for(int32 CurveIndex = CurveOffset, CurveEnd = GeometryCurveOffsets[GeometryIndex]; CurveIndex < CurveEnd; ++CurveIndex) { for (int32 PointIndex = PointOffset, PointEnd = CurvePointOffsets[CurveIndex]; PointIndex < PointEnd; ++PointIndex) { // Build 2 vertices for each points const int32 VertexIndex = 2 * PointIndex; // Build positions for each curve points const FVector3f SideVector = PointRestOrientations[PointIndex].GetAxisX(); VertexPositions[VertexIndex] = PointRestPositions[PointIndex] + SideVector * GeometryCurveThickness[GeometryIndex]; VertexPositions[VertexIndex+1] = PointRestPositions[PointIndex] - SideVector * GeometryCurveThickness[GeometryIndex]; // Build normals along the up vector const FVector3f NormalVector = PointRestOrientations[PointIndex].GetAxisZ(); VertexNormals[VertexIndex] = NormalVector; VertexNormals[VertexIndex+1] = NormalVector; // Build the vertex colors VertexColors[VertexIndex] = GeometryColor; VertexColors[VertexIndex+1] = GeometryColor; // Build the vertex transform indices VertexTransforms[VertexIndex] = GeometryIndex; VertexTransforms[VertexIndex+1] = GeometryIndex; // Expand the bounding box BoundingBox[GeometryIndex] += FVector(VertexPositions[VertexIndex]); BoundingBox[GeometryIndex] += FVector(VertexPositions[VertexIndex+1]); VertexCount[GeometryIndex] += 2; // Build 2 faces for each edges perpendicular to the up-vector curve if(PointIndex < (PointEnd-1)) { const int32 FaceIndex = 2 * (PointIndex - CurveIndex); FaceIndices[FaceIndex] = FIntVector(VertexIndex, VertexIndex + 1, VertexIndex + 3); FaceIndices[FaceIndex+1] = FIntVector(VertexIndex, VertexIndex + 3, VertexIndex + 2); FaceVisibles[FaceIndex] = true; FaceVisibles[FaceIndex+1] = true; FaceCount[GeometryIndex] += 2; } } PointOffset = CurvePointOffsets[CurveIndex]; } CurveOffset = GeometryCurveOffsets[GeometryIndex]; } } } void FCollectionCurveGeometryFacade::UpdateCurveGeometryIndices() { const int32 NumGeometry = GetNumGeometry(); int32 CurveOffset = 0; for(int32 GeometryIndex = 0; GeometryIndex < NumGeometry; ++GeometryIndex) { for(int32 CurveIndex = CurveOffset, CurveEnd = GeometryCurveOffsets[GeometryIndex]; CurveIndex < CurveEnd; ++CurveIndex) { CurveGeometryIndices.ModifyAt(CurveIndex,GeometryIndex); } CurveOffset = GeometryCurveOffsets[GeometryIndex]; } } void FCollectionCurveGeometryFacade::UpdatePointCurveIndices() { const int32 NumCurves = GetNumCurves(); int32 PointOffset = 0; for(int32 CurveIndex = 0; CurveIndex < NumCurves; ++CurveIndex) { for (int32 PointIndex = PointOffset, PointEnd = CurvePointOffsets[CurveIndex]; PointIndex < PointEnd; ++PointIndex) { PointCurveIndices.ModifyAt(PointIndex, CurveIndex); } PointOffset = CurvePointOffsets[CurveIndex]; } } void FCollectionCurveGeometryFacade::UpdatePointRestOrientations() { const int32 NumCurves = GetNumCurves(); int32 EdgeOffset = 0; int32 PointOffset = 0; for(int32 CurveIndex = 0; CurveIndex < NumCurves; ++CurveIndex) { FVector3f TangentPrev = FVector3f(0.,0.,1.), TangentNext = FVector3f::Zero(); FQuat4f EdgeOrientation = FQuat4f::Identity; const int32 NumEdges = (CurvePointOffsets[CurveIndex] - PointOffset)-1; for (int32 EdgeIndex = 0; EdgeIndex < NumEdges; ++EdgeIndex) { TangentPrev = TangentNext; TangentNext = (PointRestPositions[PointOffset+EdgeIndex+1]-PointRestPositions[PointOffset+EdgeIndex]).GetSafeNormal(); EdgeOrientation = (FQuat4f::FindBetweenNormals(TangentPrev,TangentNext) * EdgeOrientation).GetNormalized(); PointRestOrientations.ModifyAt(EdgeOffset+EdgeIndex, EdgeOrientation); } PointRestOrientations.ModifyAt(EdgeOffset+NumEdges, EdgeOrientation); EdgeOffset += NumEdges+1; PointOffset = CurvePointOffsets[CurveIndex]; } } FCollectionCurveHierarchyFacade::FCollectionCurveHierarchyFacade(FManagedArrayCollection& InCollection) : ConstCollection(InCollection), Collection(&InCollection), CurveParentIndices(InCollection, CurveParentIndicesAttribute, FCollectionCurveGeometryFacade::CurvesGroup), CurveLodIndices(InCollection, CurveLodIndicesAttribute, FCollectionCurveGeometryFacade::CurvesGroup) { DefineSchema(); } FCollectionCurveHierarchyFacade::FCollectionCurveHierarchyFacade(const FManagedArrayCollection& InCollection) : ConstCollection(InCollection), Collection(nullptr), CurveParentIndices(InCollection, CurveParentIndicesAttribute, FCollectionCurveGeometryFacade::CurvesGroup), CurveLodIndices(InCollection, CurveLodIndicesAttribute, FCollectionCurveGeometryFacade::CurvesGroup) { } bool FCollectionCurveHierarchyFacade::IsValid() const { return CurveParentIndices.IsValid() && CurveLodIndices.IsValid(); } void FCollectionCurveHierarchyFacade::DefineSchema() { check(!IsConst()); CurveParentIndices.Add(); CurveLodIndices.Add(); } }