Files
UnrealEngine/Engine/Source/Runtime/Experimental/GeometryCollectionEngine/Private/GeometryCollection/GeometryCollectionDebugDraw.cpp
2025-05-18 13:04:45 +08:00

180 lines
7.9 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "GeometryCollection/GeometryCollectionDebugDraw.h"
#include "GeometryCollection/GeometryCollection.h"
#include "GeometryCollection/Facades/CollectionTransformFacade.h"
#include "GeometryCollection/Facades/CollectionHierarchyFacade.h"
#include "GeometryCollectionProxyData.h"
#include "PrimitiveDrawingUtils.h"
#include "PhysicsEngine/SphereElem.h"
#include "PhysicsEngine/SphylElem.h"
#include "PhysicsEngine/BoxElem.h"
#include "PhysicsEngine/ConvexElem.h"
#include "PhysicsEngine/AggregateGeom.h"
#include "Chaos/Sphere.h"
#include "Chaos/Capsule.h"
#include "Chaos/Box.h"
#include "Chaos/Convex.h"
#include "Chaos/ImplicitObjectScaled.h"
#include "Chaos/TriangleMeshImplicitObject.h"
#include "Chaos/HeightField.h"
namespace GeometryCollectionDebugDraw
{
void AddSphere(FKAggregateGeom& AggGeom, const Chaos::FImplicitSphere3& Sphere, const Chaos::FRigidTransform3& Transform)
{
FKSphereElem& SphereElem = AggGeom.SphereElems.AddDefaulted_GetRef();
SphereElem.Center = Transform.TransformPosition(FVector3d(Sphere.GetCenterf()));
SphereElem.Radius = (Transform.GetScale3D().Z * Sphere.GetRadiusf());
}
void AddCapsule(FKAggregateGeom& AggGeom, const Chaos::FImplicitCapsule3& Capsule, const Chaos::FRigidTransform3& Transform)
{
FKSphylElem& CapsuleElem = AggGeom.SphylElems.AddDefaulted_GetRef();
CapsuleElem.Center = Transform.TransformPosition(FVector3d(Capsule.GetCenterf()));
CapsuleElem.Rotation = (Transform.GetRotation() * FRotationMatrix::MakeFromZ(Capsule.GetAxis())).Rotator();
CapsuleElem.Length = (Transform.GetScale3D().Z * Capsule.GetHeightf());
CapsuleElem.Radius = (Transform.GetScale3D().X * Capsule.GetRadiusf());
}
void AddBox(FKAggregateGeom& AggGeom, const Chaos::FImplicitBox3& Box, const Chaos::FRigidTransform3& Transform)
{
FKBoxElem& BoxElem = AggGeom.BoxElems.AddDefaulted_GetRef();
BoxElem.Center = Transform.TransformPosition(Box.Center());
BoxElem.Rotation = Transform.Rotator();
BoxElem.X = Transform.GetScale3D().X * Box.Extents().X;
BoxElem.Y = Transform.GetScale3D().Y * Box.Extents().Y;
BoxElem.Z = Transform.GetScale3D().Z * Box.Extents().Z;
}
void AddConvex(FKAggregateGeom& AggGeom, const Chaos::FImplicitConvex3& Convex, const Chaos::FRigidTransform3& Transform)
{
FKConvexElem& ConvexElem = AggGeom.ConvexElems.AddDefaulted_GetRef();
ConvexElem.VertexData.Reserve(Convex.GetVertices().Num());
for (const FVector3f& Vtx : Convex.GetVertices())
{
ConvexElem.VertexData.Emplace(Transform.TransformPosition(FVector(Vtx)));
}
for (int32 PlaneIndex = 0; PlaneIndex < Convex.NumPlanes(); PlaneIndex++)
{
const int32 NumVertices = Convex.NumPlaneVertices(PlaneIndex);
if (NumVertices >= 3)
{
const int32 NumTriangles = (NumVertices - 2);
ConvexElem.IndexData.Reserve(ConvexElem.IndexData.Num() + (NumTriangles * 3));
for (int32 VtxIndex = 2; VtxIndex < NumVertices; VtxIndex++)
{
ConvexElem.IndexData.Emplace(Convex.GetPlaneVertex(PlaneIndex, 0));
ConvexElem.IndexData.Emplace(Convex.GetPlaneVertex(PlaneIndex, VtxIndex-1));
ConvexElem.IndexData.Emplace(Convex.GetPlaneVertex(PlaneIndex, VtxIndex));
}
}
}
}
void AddImplicitObject(FKAggregateGeom& AggGeom, const Chaos::FImplicitObject* Implicit, const Chaos::FRigidTransform3& Transform)
{
using namespace Chaos;
if (const FImplicitSphere3* Sphere = Implicit->AsA<FImplicitSphere3>())
{
AddSphere(AggGeom, *Sphere, Transform);
}
else if (const FImplicitCapsule3* Capsule = Implicit->AsA<FImplicitCapsule3>())
{
AddCapsule(AggGeom, *Capsule, Transform);
}
else if (const FImplicitBox3* Box = Implicit->AsA<FImplicitBox3>())
{
AddBox(AggGeom, *Box, Transform);
}
else if (const FImplicitConvex3* Convex = Implicit->AsA<FImplicitConvex3>())
{
AddConvex(AggGeom, *Convex, Transform);
}
else if (const FTriangleMeshImplicitObject* TriMesh = Implicit->AsA<FTriangleMeshImplicitObject>())
{
ensure(false); // unsupported for geometry collection
}
else if (const FHeightField* HeightField = Implicit->AsA<FHeightField>())
{
ensure(false); // unsupported for geometry collection
}
else if (const FImplicitObjectInstanced* Instanced = Implicit->AsA<FImplicitObjectInstanced>())
{
AddImplicitObject(AggGeom, Instanced->GetInnerObject().Get(), Transform);
}
else if (const FImplicitObjectScaled* Scaled = Implicit->AsA<FImplicitObjectScaled>())
{
const FRigidTransform3 ScaledTransform = FRigidTransform3(Transform.GetTranslation(), Transform.GetRotation(), Transform.GetScale3D() * Scaled->GetScale());
AddImplicitObject(AggGeom, Scaled->GetInnerObject().Get(), ScaledTransform);
}
else if (const FImplicitObjectUnion* Union = Implicit->AsA<FImplicitObjectUnion>())
{
ensure(false);
}
}
void Draw(const FGeometryCollection& Collection, const FTransform& CollectionWorldTransform, FMeshElementCollector& MeshCollector, int32 ViewIndex, const FMaterialRenderProxy* MaterialProxy, const FColor& Color, bool bDrawSolid)
{
const FName MassToLocalAttributeName = "MassToLocal";
const TManagedArray<FTransform>* MassToLocalPtr = Collection.FindAttribute<FTransform>(MassToLocalAttributeName, FTransformCollection::TransformGroup);
const TManagedArray<Chaos::FImplicitObjectPtr>* ImplicitsPtr = Collection.FindAttribute<Chaos::FImplicitObjectPtr>(FGeometryDynamicCollection::ImplicitsAttribute, FTransformCollection::TransformGroup);
if (MassToLocalPtr && ImplicitsPtr)
{
const TManagedArray<FTransform>& MassToLocal = *MassToLocalPtr;
const TManagedArray<Chaos::FImplicitObjectPtr>& Implicits = *ImplicitsPtr;
// let's take advantage of the existing method for rendering Aggregate geometry
FKAggregateGeom AggGeom;
const GeometryCollection::Facades::FCollectionTransformFacade TransformFacade(Collection);
const Chaos::Facades::FCollectionHierarchyFacade HierarchyFacade(Collection);
TArray<int32> TransformIndices = TransformFacade.GetRootIndices();
for (int32 Index = 0; Index < TransformIndices.Num(); Index++)
{
const int32 TransformIndex = TransformIndices[Index];
if (const Chaos::FImplicitObjectPtr ImplicitPtr = Implicits[TransformIndex])
{
// TODO : use the root bone transform * component transform
const Chaos::FRigidTransform3 CollectionSpaceTransform = TransformFacade.ComputeCollectionSpaceTransform(TransformIndex);
const Chaos::FRigidTransform3 CollectionSpaceParticleTransform = MassToLocal[TransformIndex] * CollectionSpaceTransform;
ImplicitPtr->VisitLeafObjects(
[&](const Chaos::FImplicitObject* LeafImplicitObject, const Chaos::FRigidTransform3& LeafRelativeTransform, const int32 UnusedRootObjectIndex, const int32 UnusedObjectIndex, const int32 UnusedLeafObjectIndex)
{
const Chaos::FRigidTransform3 LeafTransform = LeafRelativeTransform * CollectionSpaceParticleTransform;
AddImplicitObject(AggGeom, LeafImplicitObject, LeafTransform);
});
}
else
{
// no implicit , so we need to use the children ones
TransformIndices.Append(HierarchyFacade.GetChildrenAsArray(TransformIndex));
}
}
// collect the rendering data through the collector
AggGeom.GetAggGeom(CollectionWorldTransform, Color, MaterialProxy, /*bPerHullColor*/false, bDrawSolid, /*bOutputVelocity*/false, ViewIndex, MeshCollector);
}
}
void DrawSolid(const FGeometryCollection& Collection, const FTransform& CollectionWorldTransform, FMeshElementCollector& MeshCollector, int32 ViewIndex, const FMaterialRenderProxy* MaterialProxy)
{
Draw(Collection, CollectionWorldTransform, MeshCollector, ViewIndex, MaterialProxy, /*Color*/FColor::White, /*bDrawSolid*/true);
}
void DrawWireframe(const FGeometryCollection& Collection, const FTransform& CollectionWorldTransform, FMeshElementCollector& MeshCollector, int32 ViewIndex, const FColor& Color)
{
Draw(Collection, CollectionWorldTransform, MeshCollector, ViewIndex, /*MaterialProxy*/nullptr, Color, /*bDrawSolid*/false);
}
}