void UPaperTerrainComponent::InsertConvexCollisionDataFromPolygon(const TArray<FVector2D>& ClosedPolyVertices2D) { if (CachedBodySetup != nullptr && ClosedPolyVertices2D.Num() >= 3) { // Simplify polygon TArray<float> EmptyOffsetsList; TArray<FVector2D> LocalPolyVertices = ClosedPolyVertices2D; SimplifyPolygon(LocalPolyVertices, EmptyOffsetsList); // Always CCW and facing forward regardless of spline winding TArray<FVector2D> CorrectedSplineVertices; PaperGeomTools::CorrectPolygonWinding(CorrectedSplineVertices, LocalPolyVertices, false); TArray<FVector2D> TriangulatedPolygonVertices; PaperGeomTools::TriangulatePoly(/*out*/TriangulatedPolygonVertices, CorrectedSplineVertices, false); TArray<TArray<FVector2D>> ConvexHulls; PaperGeomTools::GenerateConvexPolygonsFromTriangles(ConvexHulls, TriangulatedPolygonVertices); for (TArray<FVector2D> ConvexHull : ConvexHulls) { FKConvexElem Convex; for (int J = 0; J < ConvexHull.Num(); ++J) { FVector2D& Vert = ConvexHull[J]; new(Convex.VertexData) FVector(Vert.X, -0.5f * CollisionThickness, Vert.Y); new(Convex.VertexData) FVector(Vert.X, 0.5f * CollisionThickness, Vert.Y); } Convex.UpdateElemBox(); CachedBodySetup->AggGeom.ConvexElems.Add(Convex); } } }
void UPaperTerrainComponent::GenerateCollisionDataFromPolygon(const TArray<FVector2D>& SplinePolyVertices2D, const TArray<float>& TerrainOffsets, const TArray<FVector2D>& TriangulatedPolygonVertices) { if (CachedBodySetup != nullptr && TriangulatedPolygonVertices.Num() >= 3) { // Generate polygon collider TArray<TArray<FVector2D>> ConvexHulls; PaperGeomTools::GenerateConvexPolygonsFromTriangles(ConvexHulls, TriangulatedPolygonVertices); TArray<float> ConvexHullEdgeExtrusionAmount; for (TArray<FVector2D> ConvexHull : ConvexHulls) { ConvexHullEdgeExtrusionAmount.Empty(ConvexHull.Num()); // Find distances for each edge in this convex hull from the pair of points forming the edge // Not all edges will match edges in the original concave geometry, eg. newly created internal edges //TODO: Speed this up by using indices / vertex & edge identifiers instead of brute force search for (int ConvexHullPoint = 0; ConvexHullPoint < ConvexHull.Num(); ++ConvexHullPoint) { const FVector2D& A = ConvexHull[ConvexHullPoint]; const FVector2D& B = ConvexHull[(ConvexHullPoint + 1) % ConvexHull.Num()]; bool bFound = false; for (int Vertex = 0; Vertex < SplinePolyVertices2D.Num(); ++Vertex) { // The winding is might be different to the source polygon, compare both ways int NextVertexIndex = (Vertex + 1) % SplinePolyVertices2D.Num(); if ((A.Equals(SplinePolyVertices2D[Vertex], THRESH_POINTS_ARE_SAME) && B.Equals(SplinePolyVertices2D[NextVertexIndex], THRESH_POINTS_ARE_SAME)) || (B.Equals(SplinePolyVertices2D[Vertex], THRESH_POINTS_ARE_SAME) && A.Equals(SplinePolyVertices2D[NextVertexIndex], THRESH_POINTS_ARE_SAME))) { // Found an edge that matches the 2 vertex points ConvexHullEdgeExtrusionAmount.Add(TerrainOffsets[Vertex]); bFound = true; break; } } if (!bFound) { // Couldn't find this edge in the original polygon ConvexHullEdgeExtrusionAmount.Add(0); } } TArray<FVector2D> ExtrudedConvexHull; CreateExtrudedConvexHull(ExtrudedConvexHull, ConvexHull, ConvexHullEdgeExtrusionAmount); // ExtrudedConvexHull = ConvexHull; // Generate convex hull FKConvexElem Convex; for (int J = 0; J < ExtrudedConvexHull.Num(); ++J) { FVector2D& Vert = ExtrudedConvexHull[J]; new(Convex.VertexData) FVector(Vert.X, -0.5f * CollisionThickness, Vert.Y); new(Convex.VertexData) FVector(Vert.X, 0.5f * CollisionThickness, Vert.Y); } Convex.UpdateElemBox(); CachedBodySetup->AggGeom.ConvexElems.Add(Convex); } } }
void UBodySetup::RescaleSimpleCollision( FVector BuildScale ) { if( BuildScale3D != BuildScale ) { // Back out the old scale when applying the new scale const FVector ScaleMultiplier3D = (BuildScale / BuildScale3D); for (int32 i = 0; i < AggGeom.ConvexElems.Num(); i++) { FKConvexElem* ConvexElem = &(AggGeom.ConvexElems[i]); FTransform ConvexTrans = ConvexElem->GetTransform(); FVector ConvexLoc = ConvexTrans.GetLocation(); ConvexLoc *= ScaleMultiplier3D; ConvexTrans.SetLocation(ConvexLoc); ConvexElem->SetTransform(ConvexTrans); TArray<FVector>& Vertices = ConvexElem->VertexData; for (int32 VertIndex = 0; VertIndex < Vertices.Num(); ++VertIndex) { Vertices[VertIndex] *= ScaleMultiplier3D; } ConvexElem->UpdateElemBox(); } // @todo Deal with non-vector properties by just applying the max value for the time being const float ScaleMultiplier = ScaleMultiplier3D.GetMax(); for (int32 i = 0; i < AggGeom.SphereElems.Num(); i++) { FKSphereElem* SphereElem = &(AggGeom.SphereElems[i]); SphereElem->Center *= ScaleMultiplier3D; SphereElem->Radius *= ScaleMultiplier; } for (int32 i = 0; i < AggGeom.BoxElems.Num(); i++) { FKBoxElem* BoxElem = &(AggGeom.BoxElems[i]); BoxElem->Center *= ScaleMultiplier3D; BoxElem->X *= ScaleMultiplier3D.X; BoxElem->Y *= ScaleMultiplier3D.Y; BoxElem->Z *= ScaleMultiplier3D.Z; } for (int32 i = 0; i < AggGeom.SphylElems.Num(); i++) { FKSphylElem* SphylElem = &(AggGeom.SphylElems[i]); SphylElem->Center *= ScaleMultiplier3D; SphylElem->Radius *= ScaleMultiplier; SphylElem->Length *= ScaleMultiplier; } BuildScale3D = BuildScale; } }
/** Utility for adding one convex hull from the given verts */ void AddConvexGeomFromVertices( const TArray<FVector>& Verts, FKAggregateGeom* AggGeom, const TCHAR* ObjName ) { if(Verts.Num() == 0) { return; } FKConvexElem* ConvexElem = new(AggGeom->ConvexElems) FKConvexElem(); ConvexElem->VertexData = Verts; ConvexElem->UpdateElemBox(); }
void UPaperTerrainComponent::InsertConvexCollisionDataFromPolygon(const TArray<FVector2D>& ClosedPolyVertices2D) { if (CachedBodySetup != nullptr && ClosedPolyVertices2D.Num() >= 3) { // Simplify polygon TArray<float> EmptyOffsetsList; TArray<FVector2D> LocalPolyVertices = ClosedPolyVertices2D; // The merge / weld threshold should not be any lower / less than half the thickness float PolygonThickness = (ClosedPolyVertices2D[0] - ClosedPolyVertices2D[ClosedPolyVertices2D.Num() - 1]).Size(); float SimplifyThreshold = PolygonThickness * 0.5f; SimplifyPolygon(LocalPolyVertices, EmptyOffsetsList, SimplifyThreshold); // Always CCW and facing forward regardless of spline winding TArray<FVector2D> CorrectedSplineVertices; PaperGeomTools::CorrectPolygonWinding(CorrectedSplineVertices, LocalPolyVertices, false); TArray<FVector2D> TriangulatedPolygonVertices; if (!PaperGeomTools::TriangulatePoly(/*out*/TriangulatedPolygonVertices, CorrectedSplineVertices, false)) { // Triangulation failed, try triangulating the original non simplified polygon CorrectedSplineVertices.Empty(); PaperGeomTools::CorrectPolygonWinding(/*out*/CorrectedSplineVertices, ClosedPolyVertices2D, false); TriangulatedPolygonVertices.Empty(); PaperGeomTools::TriangulatePoly(/*out*/TriangulatedPolygonVertices, CorrectedSplineVertices, false); } TArray<TArray<FVector2D>> ConvexHulls; PaperGeomTools::GenerateConvexPolygonsFromTriangles(ConvexHulls, TriangulatedPolygonVertices); for (TArray<FVector2D> ConvexHull : ConvexHulls) { FKConvexElem Convex; for (int J = 0; J < ConvexHull.Num(); ++J) { FVector2D& Vert = ConvexHull[J]; new(Convex.VertexData) FVector(Vert.X, -0.5f * CollisionThickness, Vert.Y); new(Convex.VertexData) FVector(Vert.X, 0.5f * CollisionThickness, Vert.Y); } Convex.UpdateElemBox(); CachedBodySetup->AggGeom.ConvexElems.Add(Convex); } } }