9 #include "PhysicsEngine/BodySetup.h" 14 FVector BoxCenter, BoxExtents;
15 InBox.GetCenterAndExtents(BoxCenter, BoxExtents);
18 float BoxCenterDist = InPlane.PlaneDot(BoxCenter);
21 float BoxSize = FVector::BoxPushOut(InPlane, BoxExtents);
23 return (BoxCenterDist > BoxSize) ? 1 : ((BoxCenterDist < -BoxSize) ? -1 : 0);
31 if (FMath::IsNaN(Alpha) || !FMath::IsFinite(Alpha))
43 Result.
Color.R = FMath::Clamp(FMath::TruncToInt(FMath::Lerp(
float(V0.
Color.R),
float(V1.
Color.R), Alpha)), 0, 255);
44 Result.
Color.G = FMath::Clamp(FMath::TruncToInt(FMath::Lerp(
float(V0.
Color.G),
float(V1.
Color.G), Alpha)), 0, 255);
45 Result.
Color.B = FMath::Clamp(FMath::TruncToInt(FMath::Lerp(
float(V0.
Color.B),
float(V1.
Color.B), Alpha)), 0, 255);
46 Result.
Color.A = FMath::Clamp(FMath::TruncToInt(FMath::Lerp(
float(V0.
Color.A),
float(V1.
Color.A), Alpha)), 0, 255);
51 Result.
UVs.SetNum(V0.
UVs.Num());
64 FVector4 PolyNormal = FVector4(-InMatrix.GetUnitAxis(
EAxis::Z), 1.0f);
65 FVector PolyTangent = InMatrix.GetUnitAxis(
EAxis::X);
67 int32 NumUVs = OutMesh->NumUVChannels();
69 for (int32 VertexIndex = 0; VertexIndex < InPoly.Verts.Num(); VertexIndex++)
71 const FUtilVertex2D& InVertex = InPoly.Verts[VertexIndex];
75 int32 NewIndex = OutMesh->AddVertex(InMatrix.TransformPosition(FVector(InVertex.Pos.X, InVertex.Pos.Y, 0.f)));
76 OutMesh->SetNormal(NewIndex, PolyNormal);
77 OutMesh->SetTangent(NewIndex, PolyTangent);
78 OutMesh->SetColor(NewIndex, InVertex.Color);
80 NewVert.
UVs.SetNum(NumUVs);
83 OutMesh->SetUV(NewIndex,
Index, InVertex.UV);
91 int32 NumVerts = Mesh->NumVertices() - VertBase;
94 Mesh->AddIndex(FMath::Clamp(0 + VertBase, 0, NumVerts));
95 Mesh->AddIndex(FMath::Clamp(2 + VertBase, 0, NumVerts));
96 Mesh->AddIndex(FMath::Clamp(1 + VertBase, 0, NumVerts));
102 const int32 OriginalNumIndices = Mesh->NumIndices();
105 TArray<int32> VertIndices;
106 VertIndices.SetNumUninitialized(NumVerts);
107 for (
int VertIndex = 0; VertIndex < NumVerts; VertIndex++)
109 VertIndices[VertIndex] = VertBase + VertIndex;
113 while (VertIndices.Num() >= 3)
116 bool bFoundEar =
false;
117 for (int32 EarVertexIndex = 0; EarVertexIndex < VertIndices.Num(); EarVertexIndex++)
120 const int32 Index1 = (EarVertexIndex == 0) ? VertIndices.Num() - 1 : EarVertexIndex - 1;
121 const int32 Index2 = EarVertexIndex;
122 const int32 Index3 = (EarVertexIndex + 1) % VertIndices.Num();
131 const float Determinant = (Edge12 ^ Edge13) | PolyNormal;
132 if (Determinant > 0.
f)
137 bool bFoundVertInside =
false;
139 for (int32 VertexIndex = 0; VertexIndex < VertIndices.Num(); VertexIndex++)
143 if (VertexIndex != Index1 &&
144 VertexIndex != Index2 &&
145 VertexIndex != Index3 &&
148 bFoundVertInside =
true;
154 if (!bFoundVertInside)
156 Mesh->AddIndex(VertIndices[Index1]);
157 Mesh->AddIndex(VertIndices[Index3]);
158 Mesh->AddIndex(VertIndices[Index2]);
161 VertIndices.RemoveAt(EarVertexIndex);
171 Mesh->SetNumIndices(OriginalNumIndices);
181 FPlane SlicePlaneFlipped = SlicePlane.Flip();
184 TArray<FPlane> ConvexPlanes;
185 InConvex.GetPlanes(ConvexPlanes);
187 if (ConvexPlanes.Num() >= 4)
190 ConvexPlanes.Add(SlicePlaneFlipped);
193 FKConvexElem SlicedElem;
194 bool bSuccess = SlicedElem.HullFromPlanes(ConvexPlanes, InConvex.VertexData);
197 OutConvexVerts = SlicedElem.VertexData;
205 bool bCreateOtherHalf = OutOtherHalf !=
nullptr;
207 PlaneNormal.Normalize();
208 FPlane SlicePlane(PlanePosition, PlaneNormal);
211 TArray<TArray<FVector>> SlicedCollision;
212 TArray<TArray<FVector>> OtherSlicedCollision;
221 for (int32 ConvexIndex = 0; ConvexIndex < BodySetup->AggGeom.ConvexElems.Num(); ConvexIndex++)
223 FKConvexElem& BaseConvex = BodySetup->AggGeom.ConvexElems[ConvexIndex];
228 if (BoxCompare == -1)
230 if (bCreateOtherHalf)
232 OtherSlicedCollision.Add(BaseConvex.VertexData);
236 else if (BoxCompare == 1)
238 SlicedCollision.Add(BaseConvex.VertexData);
243 TArray<FVector> SlicedConvexVerts;
246 if (SlicedConvexVerts.Num() >= 4)
248 SlicedCollision.Add(SlicedConvexVerts);
252 if (bCreateOtherHalf)
254 TArray<FVector> OtherSlicedConvexVerts;
255 SliceConvexElem(BaseConvex, SlicePlane.Flip(), OtherSlicedConvexVerts);
256 if (OtherSlicedConvexVerts.Num() >= 4)
258 OtherSlicedCollision.Add(OtherSlicedConvexVerts);
268 if (bCreateOtherHalf)
276 bool bShouldCreateOtherHalf = OutOtherHalf.IsValid();
278 auto SourceMeshData = InRuntimeMesh->GetSectionReadonly(SectionIndex);
280 TSharedPtr<FRuntimeMeshBuilder> OtherMeshData = bShouldCreateOtherHalf ?
MakeRuntimeMeshBuilder(*SourceMeshData.Get()) : TSharedPtr<FRuntimeMeshBuilder>(
nullptr);
283 TMap<int32, int32> BaseToSlicedVertIndex;
284 TMap<int32, int32> BaseToOtherSlicedVertIndex;
286 const int32 NumBaseVerts = SourceMeshData->NumVertices();
289 TArray<float> VertDistance;
290 VertDistance.SetNumUninitialized(NumBaseVerts);
293 for (int32 BaseVertIndex = 0; BaseVertIndex < NumBaseVerts; BaseVertIndex++)
298 VertDistance[BaseVertIndex] = SlicePlane.PlaneDot(BaseVert.
Position);
301 if (VertDistance[BaseVertIndex] > 0.
f)
304 int32 SlicedVertIndex = NewMeshData->AddVertex(BaseVert);
307 BaseToSlicedVertIndex.Add(BaseVertIndex, SlicedVertIndex);
310 else if (bShouldCreateOtherHalf)
312 int32 SlicedVertIndex = OtherMeshData->AddVertex(BaseVert);
314 BaseToOtherSlicedVertIndex.Add(BaseVertIndex, SlicedVertIndex);
320 int32 NumBaseIndices = SourceMeshData->NumIndices();
321 for (int32 BaseIndex = 0; BaseIndex < NumBaseIndices; BaseIndex += 3)
325 int32* SlicedOtherV[3];
328 for (int32
i = 0;
i < 3;
i++)
331 BaseV[
i] = SourceMeshData->GetIndex(BaseIndex +
i);
333 SlicedV[
i] = BaseToSlicedVertIndex.Find(BaseV[
i]);
335 if (bShouldCreateOtherHalf)
337 SlicedOtherV[
i] = BaseToOtherSlicedVertIndex.Find(BaseV[i]);
339 check((SlicedV[i] !=
nullptr) != (SlicedOtherV[i] !=
nullptr));
344 if (SlicedV[0] !=
nullptr && SlicedV[1] !=
nullptr && SlicedV[2] !=
nullptr)
346 NewMeshData->AddIndex(*SlicedV[0]);
347 NewMeshData->AddIndex(*SlicedV[1]);
348 NewMeshData->AddIndex(*SlicedV[2]);
351 else if (SlicedV[0] ==
nullptr && SlicedV[1] ==
nullptr && SlicedV[2] ==
nullptr)
354 if (bShouldCreateOtherHalf)
356 OtherMeshData->AddIndex(*SlicedOtherV[0]);
357 OtherMeshData->AddIndex(*SlicedOtherV[1]);
358 OtherMeshData->AddIndex(*SlicedOtherV[2]);
365 int32 NumFinalVerts = 0;
367 int32 OtherFinalVerts[4];
368 int32 NumOtherFinalVerts = 0;
370 FUtilEdge3D NewClipEdge;
371 int32 ClippedEdges = 0;
374 PlaneDist[0] = VertDistance[BaseV[0]];
375 PlaneDist[1] = VertDistance[BaseV[1]];
376 PlaneDist[2] = VertDistance[BaseV[2]];
378 for (int32 EdgeIdx = 0; EdgeIdx < 3; EdgeIdx++)
380 int32 ThisVert = EdgeIdx;
383 if (SlicedV[ThisVert] !=
nullptr)
385 check(NumFinalVerts < 4);
386 FinalVerts[NumFinalVerts++] = *SlicedV[ThisVert];
389 else if (bShouldCreateOtherHalf)
391 check(NumOtherFinalVerts < 4);
392 OtherFinalVerts[NumOtherFinalVerts++] = *SlicedOtherV[ThisVert];
396 int32 NextVert = (EdgeIdx + 1) % 3;
398 if ((SlicedV[EdgeIdx] ==
nullptr) != (SlicedV[NextVert] ==
nullptr))
401 float Alpha = -PlaneDist[ThisVert] / (PlaneDist[NextVert] - PlaneDist[ThisVert]);
404 SourceMeshData->GetVertex(BaseV[ThisVert]),
405 SourceMeshData->GetVertex(BaseV[NextVert]),
406 FMath::Clamp(Alpha, 0.0
f, 1.0
f));
409 int32 InterpVertIndex = NewMeshData->AddVertex(InterpVert);
412 check(NumFinalVerts < 4);
413 FinalVerts[NumFinalVerts++] = InterpVertIndex;
416 if (bShouldCreateOtherHalf)
418 int32 OtherInterpVertIndex = OtherMeshData->AddVertex(InterpVert);
420 check(NumOtherFinalVerts < 4);
421 OtherFinalVerts[NumOtherFinalVerts++] = OtherInterpVertIndex;
425 check(ClippedEdges < 2);
426 if (ClippedEdges == 0)
428 NewClipEdge.V0 = InterpVert.
Position;
432 NewClipEdge.V1 = InterpVert.
Position;
440 for (int32 VertexIndex = 2; VertexIndex < NumFinalVerts; VertexIndex++)
442 NewMeshData->AddIndex(FinalVerts[0]);
443 NewMeshData->AddIndex(FinalVerts[VertexIndex - 1]);
444 NewMeshData->AddIndex(FinalVerts[VertexIndex]);
448 if (bShouldCreateOtherHalf)
450 for (int32 VertexIndex = 2; VertexIndex < NumOtherFinalVerts; VertexIndex++)
452 OtherMeshData->AddIndex(OtherFinalVerts[0]);
453 OtherMeshData->AddIndex(OtherFinalVerts[VertexIndex - 1]);
454 OtherMeshData->AddIndex(OtherFinalVerts[VertexIndex]);
458 check(ClippedEdges != 1);
461 if (ClippedEdges == 2)
463 ClipEdges.Add(NewClipEdge);
469 if (bShouldCreateOtherHalf && OtherMeshData->NumVertices() > 0 && OtherMeshData->NumIndices() > 0)
471 OutOtherHalf->CreateMeshSection(SectionIndex, MoveTemp(OtherMeshData));
475 if (NewMeshData->NumVertices() > 0 && NewMeshData->NumIndices() > 0)
477 InRuntimeMesh->UpdateMeshSection(SectionIndex, MoveTemp(NewMeshData));
481 InRuntimeMesh->ClearMeshSection(SectionIndex);
487 bool bShouldCreateOtherHalf = OutOtherHalf.IsValid();
489 int32 NewCapSectionIndex = InRuntimeMesh->GetLastSectionIndex() + 1;
490 if (bShouldCreateOtherHalf)
492 NewCapSectionIndex =
FMath::Max(NewCapSectionIndex, OutOtherHalf->GetLastSectionIndex() + 1);
498 TSharedPtr<FRuntimeMeshBuilder> CapSection;
499 int32 CapSectionIndex = INDEX_NONE;
504 CapSectionIndex = InRuntimeMesh->GetLastSectionIndex();
505 auto ExistingMesh = InRuntimeMesh->GetSectionReadonly(NewCapSectionIndex);
507 ExistingMesh->CopyTo(CapSection);
512 CapSection = MakeRuntimeMeshBuilder<FRuntimeMeshTangents, FVector2DHalf, uint16>();
513 CapSectionIndex = NewCapSectionIndex;
517 TArray<FUtilEdge2D> Edges2D;
518 FUtilPoly2DSet PolySet;
519 FGeomTools::ProjectEdges(Edges2D, PolySet.PolyToWorld, ClipEdges, SlicePlane);
522 FGeomTools::Buid2DPolysFromEdges(PolySet.Polys, Edges2D, FColor(255, 255, 255, 255));
525 int32 CapVertBase = CapSection->NumVertices();
526 int32 CapIndexBase = CapSection->NumIndices();
529 for (int32 PolyIdx = 0; PolyIdx < PolySet.Polys.Num(); PolyIdx++)
532 FGeomTools::GeneratePlanarTilingPolyUVs(PolySet.Polys[PolyIdx], 64.f);
535 int32 PolyVertBase = CapSection->NumVertices();
547 InRuntimeMesh->UpdateMeshSection(CapSectionIndex, MoveTemp(CapSection));
551 InRuntimeMesh->CreateMeshSection(CapSectionIndex, MoveTemp(CapSection));
555 if (bShouldCreateOtherHalf)
557 TSharedPtr<FRuntimeMeshBuilder> OtherCapSection;
558 int32 OtherCapSectionIndex = INDEX_NONE;
563 OtherCapSectionIndex = OutOtherHalf->GetLastSectionIndex();
564 auto ExistingMesh = OutOtherHalf->GetSectionReadonly(CapSectionIndex);
566 ExistingMesh->CopyTo(OtherCapSection);
571 OtherCapSection = MakeRuntimeMeshBuilder<FRuntimeMeshTangents, FVector2DHalf, uint16>();
572 OtherCapSectionIndex = NewCapSectionIndex;
576 int32 OtherCapVertBase = OtherCapSection->NumVertices();
579 int32 CapSectionLength = CapSection->NumVertices();
580 for (int32 VertIdx = CapVertBase; VertIdx < CapSectionLength; VertIdx++)
585 float Sign = OtherCapVert.
Normal.W;
586 OtherCapVert.
Normal *= -1.f;
587 OtherCapVert.
Normal.W = Sign;
591 OtherCapSection->AddVertex(OtherCapVert);
595 int32 VertOffset = OtherCapVertBase - CapVertBase;
598 int32 NumCapIndices = CapSection->NumIndices();
599 for (int32 IndexIdx = CapIndexBase; IndexIdx < NumCapIndices; IndexIdx += 3)
602 OtherCapSection->AddIndex(CapSection->GetIndex(IndexIdx + 0) + VertOffset);
603 OtherCapSection->AddIndex(CapSection->GetIndex(IndexIdx + 2) + VertOffset);
604 OtherCapSection->AddIndex(CapSection->GetIndex(IndexIdx + 1) + VertOffset);
610 OutOtherHalf->UpdateMeshSection(OtherCapSectionIndex, MoveTemp(OtherCapSection));
614 OutOtherHalf->CreateMeshSection(OtherCapSectionIndex, MoveTemp(OtherCapSection));
618 return NewCapSectionIndex;
630 PlaneNormal.Normalize();
631 FPlane SlicePlane(PlanePosition, PlaneNormal);
633 bool bShouldCreateOtherHalf = OutOtherHalf !=
nullptr;
636 TArray<FUtilEdge3D> ClipEdges;
638 for (int32 SectionIndex = 0; SectionIndex < InRuntimeMesh->
GetNumSections(); SectionIndex++)
649 if (MeshData->NumVertices() < 3 || MeshData->NumIndices() < 3)
663 if (BoxCompare == -1)
666 if (bShouldCreateOtherHalf)
671 SourceMeshData->CopyTo(NewBuilder);
681 check(BoxCompare == 0);
687 if (bShouldCreateOtherHalf && OtherHalfData->DoesSectionExist(SectionIndex))
693 int32 CapSectionIndex =
CapMeshSlice(InMeshData, OtherHalfData, ClipEdges, SlicePlane, PlaneNormal, CapOption);
698 if (bShouldCreateOtherHalf)
711 if (InRuntimeMesh && InRuntimeMesh->GetRuntimeMesh())
714 FTransform ComponentToWorld = InRuntimeMesh->GetComponentToWorld();
715 FVector LocalPlanePos = ComponentToWorld.InverseTransformPosition(PlanePosition);
716 FVector LocalPlaneNormal = ComponentToWorld.InverseTransformVectorNoScale(PlaneNormal);
717 LocalPlaneNormal = LocalPlaneNormal.GetSafeNormal();
720 if (bCreateOtherHalf)
722 OutOtherHalf = NewObject<URuntimeMeshComponent>(InRuntimeMesh->GetOuter());
723 OutOtherHalf->SetWorldTransform(InRuntimeMesh->GetComponentTransform());
726 SliceRuntimeMesh(InRuntimeMesh->GetRuntimeMesh(), LocalPlanePos, LocalPlaneNormal, bCreateOtherHalf ? OutOtherHalf->GetOrCreateRuntimeMesh() :
nullptr, CapOption, CapMaterial);
729 if (bCreateOtherHalf)
731 if (OutOtherHalf->GetNumSections() > 0)
733 OutOtherHalf->SetCollisionProfileName(InRuntimeMesh->GetCollisionProfileName());
734 OutOtherHalf->SetCollisionEnabled(InRuntimeMesh->GetCollisionEnabled());
735 OutOtherHalf->SetCollisionUseComplexAsSimple(InRuntimeMesh->IsCollisionUsingComplexAsSimple());
738 for (int32
Index = 0;
Index < InRuntimeMesh->GetNumOverrideMaterials();
Index++)
740 if (UMaterialInterface* Material = InRuntimeMesh->GetOverrideMaterial(
Index))
742 OutOtherHalf->SetMaterial(
Index, Material);
746 OutOtherHalf->RegisterComponent();
750 OutOtherHalf->DestroyComponent();
int32 GetNumSections() const
ERuntimeMeshSlicerCapOption
FRuntimeMeshDataRef GetRuntimeMeshData() const
void ClearMeshSection(int32 SectionIndex)
void CreateMeshSection(int32 SectionIndex, bool bWantsHighPrecisionTangents, bool bWantsHighPrecisionUVs, int32 NumUVs, bool bWants32BitIndices, bool bCreateCollision, EUpdateFrequency UpdateFrequency=EUpdateFrequency::Average)
static void SliceConvexElem(const FKConvexElem &InConvex, const FPlane &SlicePlane, TArray< FVector > &OutConvexVerts)
static void SliceRuntimeMesh(URuntimeMesh *InRuntimeMesh, FVector PlanePosition, FVector PlaneNormal, URuntimeMesh *OutOtherHalf, ERuntimeMeshSlicerCapOption CapOption, UMaterialInterface *CapMaterial)
static void Transform2DPolygonTo3D(const FUtilPoly2D &InPoly, const FMatrix &InMatrix, TSharedPtr< FRuntimeMeshAccessor > OutMesh)
FBox GetSectionBoundingBox(int32 SectionIndex)
static int32 CapMeshSlice(const FRuntimeMeshDataPtr &InRuntimeMesh, const FRuntimeMeshDataPtr &OutOtherHalf, TArray< FUtilEdge3D > &ClipEdges, const FPlane &SlicePlane, FVector PlaneNormal, ERuntimeMeshSlicerCapOption CapOption)
void SetSectionMaterial(int32 SectionId, UMaterialInterface *Material)
TSharedPtr< FRuntimeMeshData, ESPMode::ThreadSafe > FRuntimeMeshDataPtr
UMaterialInterface * GetSectionMaterial(int32 SectionId)
static void SliceRuntimeMeshConvexCollision(URuntimeMesh *InRuntimeMesh, URuntimeMesh *OutOtherHalf, FVector PlanePosition, FVector PlaneNormal)
static const textual_icon check
TUniquePtr< FRuntimeMeshScopedUpdater > GetSectionReadonly(int32 SectionId)
UBodySetup * GetBodySetup()
TArray< FVector2D, TInlineAllocator< RUNTIMEMESH_MAXTEXCOORDS > > UVs
bool DoesSectionExist(int32 SectionIndex) const
static int32 CompareBoxPlane(const FBox &InBox, const FPlane &InPlane)
static void SliceRuntimeMeshComponent(URuntimeMeshComponent *InRuntimeMesh, FVector PlanePosition, FVector PlaneNormal, bool bCreateOtherHalf, URuntimeMeshComponent *&OutOtherHalf, ERuntimeMeshSlicerCapOption CapOption, UMaterialInterface *CapMaterial)
static void SliceRuntimeMeshSection(const FRuntimeMeshDataPtr &InRuntimeMesh, const FRuntimeMeshDataPtr &OutOtherHalf, int32 SectionIndex, const FPlane &SlicePlane, TArray< FUtilEdge3D > &ClipEdges)
FORCEINLINE TSharedRef< FRuntimeMeshBuilder > MakeRuntimeMeshBuilder()
static FRuntimeMeshAccessorVertex InterpolateVert(const FRuntimeMeshAccessorVertex &V0, const FRuntimeMeshAccessorVertex &V1, float Alpha)
void SetCollisionConvexMeshes(const TArray< TArray< FVector >> &ConvexMeshes)
static bool TriangulatePoly(TSharedPtr< FRuntimeMeshAccessor > Mesh, int32 VertBase, const FVector &PolyNormal)