Files
UnrealEngineUWP/Engine/Plugins/Experimental/MeshModelingToolset/Source/MeshModelingTools/Private/Physics/ExtractCollisionGeometryTool.cpp
lonnie li 71d5092007 ModelingTools: Refactor SingleSelectionTool to ToolTargets (pt.2)
#rb ryan.schmidt jimmy.andrews
#jira none
#rnx
#preflight 605a54c0e8944a0001585162

[CL 15799514 by lonnie li in ue5-main branch]
2021-03-24 11:11:02 -04:00

322 lines
12 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Physics/ExtractCollisionGeometryTool.h"
#include "InteractiveToolManager.h"
#include "ToolBuilderUtil.h"
#include "ToolSetupUtil.h"
#include "AssetGenerationUtil.h"
#include "Selection/ToolSelectionUtil.h"
#include "Drawing/PreviewGeometryActor.h"
#include "Util/ColorConstants.h"
#include "PreviewMesh.h"
#include "DynamicMeshEditor.h"
#include "MeshNormals.h"
#include "Generators/SphereGenerator.h"
#include "Generators/MinimalBoxMeshGenerator.h"
#include "Generators/CapsuleGenerator.h"
#include "MeshTransforms.h"
#include "Parameterization/DynamicMeshUVEditor.h"
#include "Physics/PhysicsDataCollection.h"
#include "Physics/CollisionGeometryVisualization.h"
// physics data
#include "Engine/Classes/Engine/StaticMesh.h"
#include "Engine/Classes/Components/StaticMeshComponent.h"
#include "Engine/Classes/PhysicsEngine/BodySetup.h"
#include "Engine/Classes/PhysicsEngine/AggregateGeom.h"
#include "TargetInterfaces/MaterialProvider.h"
#include "TargetInterfaces/MeshDescriptionCommitter.h"
#include "TargetInterfaces/MeshDescriptionProvider.h"
#include "TargetInterfaces/PrimitiveComponentBackedTarget.h"
#include "TargetInterfaces/StaticMeshBackedTarget.h"
#include "ExplicitUseGeometryMathTypes.h" // using UE::Geometry::(math types)
using namespace UE::Geometry;
#define LOCTEXT_NAMESPACE "UExtractCollisionGeometryTool"
const FToolTargetTypeRequirements& UExtractCollisionGeometryToolBuilder::GetTargetRequirements() const
{
static FToolTargetTypeRequirements TypeRequirements({
UMaterialProvider::StaticClass(),
UMeshDescriptionCommitter::StaticClass(),
UMeshDescriptionProvider::StaticClass(),
UPrimitiveComponentBackedTarget::StaticClass(),
UStaticMeshBackedTarget::StaticClass()
});
return TypeRequirements;
}
USingleSelectionMeshEditingTool* UExtractCollisionGeometryToolBuilder::CreateNewTool(const FToolBuilderState& SceneState) const
{
return NewObject<UExtractCollisionGeometryTool>(SceneState.ToolManager);
}
void UExtractCollisionGeometryTool::Setup()
{
UInteractiveTool::Setup();
// create preview mesh
IPrimitiveComponentBackedTarget* TargetComponent = Cast<IPrimitiveComponentBackedTarget>(Target);
PreviewMesh = NewObject<UPreviewMesh>(this);
PreviewMesh->bBuildSpatialDataStructure = false;
PreviewMesh->CreateInWorld(TargetWorld, FTransform::Identity);
PreviewMesh->SetTransform(TargetComponent->GetWorldTransform());
PreviewMesh->SetMaterial(ToolSetupUtil::GetDefaultSculptMaterial(GetToolManager()));
PreviewMesh->SetOverrideRenderMaterial(ToolSetupUtil::GetSelectionMaterial(GetToolManager()));
PreviewMesh->SetTriangleColorFunction([this](const FDynamicMesh3* Mesh, int TriangleID)
{
return LinearColors::SelectFColor(Mesh->GetTriangleGroup(TriangleID));
});
VizSettings = NewObject<UCollisionGeometryVisualizationProperties>(this);
VizSettings->RestoreProperties(this);
AddToolPropertySource(VizSettings);
VizSettings->WatchProperty(VizSettings->LineThickness, [this](float NewValue) { bVisualizationDirty = true; });
VizSettings->WatchProperty(VizSettings->Color, [this](FColor NewValue) { bVisualizationDirty = true; });
const UStaticMeshComponent* Component = CastChecked<UStaticMeshComponent>(TargetComponent->GetOwnerComponent());
const UStaticMesh* StaticMesh = Component->GetStaticMesh();
if (ensure(StaticMesh && StaticMesh->GetBodySetup()))
{
PhysicsInfo = MakeShared<FPhysicsDataCollection>();
PhysicsInfo->InitializeFromComponent(Component, true);
PreviewElements = NewObject<UPreviewGeometry>(this);
FTransform TargetTransform = TargetComponent->GetWorldTransform();
//PhysicsInfo->ExternalScale3D = TargetTransform.GetScale3D();
//TargetTransform.SetScale3D(FVector::OneVector);
PreviewElements->CreateInWorld(TargetComponent->GetOwnerActor()->GetWorld(), TargetTransform);
UE::PhysicsTools::InitializePreviewGeometryLines(*PhysicsInfo, PreviewElements,
VizSettings->Color, VizSettings->LineThickness, 0.0f, 16);
ObjectProps = NewObject<UPhysicsObjectToolPropertySet>(this);
UE::PhysicsTools::InitializePhysicsToolObjectPropertySet(PhysicsInfo.Get(), ObjectProps);
AddToolPropertySource(ObjectProps);
}
SetToolDisplayName(LOCTEXT("ToolName", "Collision To Mesh"));
GetToolManager()->DisplayMessage(
LOCTEXT("OnStartTool", "Convert Collision geometry to Static Mesh"),
EToolMessageLevel::UserNotification);
}
void UExtractCollisionGeometryTool::Shutdown(EToolShutdownType ShutdownType)
{
VizSettings->SaveProperties(this);
UE::Geometry::FTransform3d Transform(PreviewMesh->GetTransform());
PreviewElements->Disconnect();
PreviewMesh->SetVisible(false);
PreviewMesh->Disconnect();
PreviewMesh = nullptr;
if (ShutdownType == EToolShutdownType::Accept)
{
UMaterialInterface* UseMaterial = UMaterial::GetDefaultMaterial(MD_Surface);
FString NewName = Target->IsValid() ?
FString::Printf(TEXT("%s_Collision"), *Cast<IPrimitiveComponentBackedTarget>(Target)->GetOwnerComponent()->GetName()) : TEXT("CollisionGeo");
GetToolManager()->BeginUndoTransaction(LOCTEXT("CreateCollisionMesh", "Collision To Mesh"));
AActor* NewActor = AssetGenerationUtil::GenerateStaticMeshActor(
AssetAPI, TargetWorld,
&CurrentMesh, Transform, NewName, UseMaterial);
if (NewActor != nullptr)
{
ToolSelectionUtil::SetNewActorSelection(GetToolManager(), NewActor);
}
GetToolManager()->EndUndoTransaction();
}
}
bool UExtractCollisionGeometryTool::CanAccept() const
{
return Super::CanAccept() && CurrentMesh.TriangleCount() > 0;
}
void UExtractCollisionGeometryTool::OnTick(float DeltaTime)
{
if (bResultValid == false)
{
RecalculateMesh();
}
if (bVisualizationDirty)
{
UpdateVisualization();
bVisualizationDirty = false;
}
}
void UExtractCollisionGeometryTool::UpdateVisualization()
{
float UseThickness = VizSettings->LineThickness / 10.0f;
FColor UseColor = VizSettings->Color;
PreviewElements->UpdateAllLineSets([&](ULineSetComponent* LineSet)
{
LineSet->SetAllLinesThickness(UseThickness);
LineSet->SetAllLinesColor(UseColor);
});
}
void UExtractCollisionGeometryTool::RecalculateMesh()
{
int32 SphereResolution = 16;
CurrentMesh = FDynamicMesh3(EMeshComponents::FaceGroups);
CurrentMesh.EnableAttributes();
FDynamicMeshEditor Editor(&CurrentMesh);
const FKAggregateGeom& AggGeom = PhysicsInfo->AggGeom;
for (const FKSphereElem& Sphere : AggGeom.SphereElems)
{
FSphereGenerator SphereGen;
SphereGen.Radius = Sphere.Radius;
SphereGen.NumPhi = SphereGen.NumTheta = SphereResolution;
SphereGen.bPolygroupPerQuad = false;
SphereGen.Generate();
FDynamicMesh3 SphereMesh(&SphereGen);
MeshTransforms::Translate(SphereMesh, FVector3d(Sphere.Center));
FMeshIndexMappings Mappings;
Editor.AppendMesh(&SphereMesh, Mappings);
}
for (const FKBoxElem& Box : AggGeom.BoxElems)
{
FMinimalBoxMeshGenerator BoxGen;
BoxGen.Box = FOrientedBox3d(
FFrame3d(FVector3d(Box.Center), FQuaterniond(Box.Rotation.Quaternion())),
0.5*FVector3d(Box.X, Box.Y, Box.Z));
BoxGen.Generate();
FDynamicMesh3 BoxMesh(&BoxGen);
// transform not applied because it is just the Center/Rotation
FMeshIndexMappings Mappings;
Editor.AppendMesh(&BoxMesh, Mappings);
}
for (const FKSphylElem& Capsule: AggGeom.SphylElems)
{
FCapsuleGenerator CapsuleGen;
CapsuleGen.Radius = Capsule.Radius;
CapsuleGen.SegmentLength = Capsule.Length;
CapsuleGen.NumHemisphereArcSteps = SphereResolution/4+1;
CapsuleGen.NumCircleSteps = SphereResolution;
CapsuleGen.bPolygroupPerQuad = false;
CapsuleGen.Generate();
FDynamicMesh3 CapsuleMesh(&CapsuleGen);
MeshTransforms::Translate(CapsuleMesh, FVector3d(0,0,-0.5*Capsule.Length) );
UE::Geometry::FTransform3d Transform(Capsule.GetTransform());
MeshTransforms::ApplyTransform(CapsuleMesh, Transform);
FMeshIndexMappings Mappings;
Editor.AppendMesh(&CapsuleMesh, Mappings);
}
for (const FKConvexElem& Convex : AggGeom.ConvexElems)
{
UE::Geometry::FTransform3d ElemTransform(Convex.GetTransform());
FDynamicMesh3 ConvexMesh(EMeshComponents::None);
int32 NumVertices = Convex.VertexData.Num();
for (int32 k = 0; k < NumVertices; ++k)
{
ConvexMesh.AppendVertex( FVector3d(Convex.VertexData[k]) );
}
int32 NumTriangles = Convex.IndexData.Num() / 3;
for (int32 k = 0; k < NumTriangles; ++k)
{
ConvexMesh.AppendTriangle(Convex.IndexData[3*k], Convex.IndexData[3*k+1], Convex.IndexData[3*k+2]);
}
ConvexMesh.ReverseOrientation();
ConvexMesh.EnableTriangleGroups(0);
ConvexMesh.EnableAttributes();
FDynamicMeshUVEditor UVEditor(&ConvexMesh, 0, true);
UVEditor.SetPerTriangleUVs();
FMeshIndexMappings Mappings;
Editor.AppendMesh(&ConvexMesh, Mappings);
}
FMeshNormals::InitializeMeshToPerTriangleNormals(&CurrentMesh);
PreviewMesh->UpdatePreview(&CurrentMesh);
//PreviewGeom->CreateOrUpdateLineSet(TEXT("Capsules"), AggGeom.SphylElems.Num(), [&](int32 Index, TArray<FRenderableLine>& LinesOut)
//{
// const FKSphylElem& Capsule = AggGeom.SphylElems[Index];
// FTransform ElemTransform = Capsule.GetTransform();
// ElemTransform.ScaleTranslation(PhysicsData.ExternalScale3D);
// FTransform3f ElemTransformf(ElemTransform);
// const float HalfLength = Capsule.GetScaledCylinderLength(PhysicsData.ExternalScale3D) * .5f;
// const float Radius = Capsule.GetScaledRadius(PhysicsData.ExternalScale3D);
// FVector3f Top(0, 0, HalfLength), Bottom(0, 0, -HalfLength);
// // top and bottom circles
// UE::Geometry::GenerateCircleSegments<float>(CircleSteps, Radius, Top, FVector3f::UnitX(), FVector3f::UnitY(), ElemTransformf,
// [&](const FVector3f& A, const FVector3f& B) { LinesOut.Add(FRenderableLine((FVector)A, (FVector)B, CapsuleColor, LineThickness, DepthBias)); });
// UE::Geometry::GenerateCircleSegments<float>(CircleSteps, Radius, Bottom, FVector3f::UnitX(), FVector3f::UnitY(), ElemTransformf,
// [&](const FVector3f& A, const FVector3f& B) { LinesOut.Add(FRenderableLine((FVector)A, (FVector)B, CapsuleColor, LineThickness, DepthBias)); });
// // top dome
// UE::Geometry::GenerateArcSegments<float>(CircleSteps, Radius, 0.0, PI, Top, FVector3f::UnitY(), FVector3f::UnitZ(), ElemTransformf,
// [&](const FVector3f& A, const FVector3f& B) { LinesOut.Add(FRenderableLine((FVector)A, (FVector)B, CapsuleColor, LineThickness, DepthBias)); });
// UE::Geometry::GenerateArcSegments<float>(CircleSteps, Radius, 0.0, PI, Top, FVector3f::UnitX(), FVector3f::UnitZ(), ElemTransformf,
// [&](const FVector3f& A, const FVector3f& B) { LinesOut.Add(FRenderableLine((FVector)A, (FVector)B, CapsuleColor, LineThickness, DepthBias)); });
// // bottom dome
// UE::Geometry::GenerateArcSegments<float>(CircleSteps, Radius, 0.0, -PI, Bottom, FVector3f::UnitY(), FVector3f::UnitZ(), ElemTransformf,
// [&](const FVector3f& A, const FVector3f& B) { LinesOut.Add(FRenderableLine((FVector)A, (FVector)B, CapsuleColor, LineThickness, DepthBias)); });
// UE::Geometry::GenerateArcSegments<float>(CircleSteps, Radius, 0.0, -PI, Bottom, FVector3f::UnitX(), FVector3f::UnitZ(), ElemTransformf,
// [&](const FVector3f& A, const FVector3f& B) { LinesOut.Add(FRenderableLine((FVector)A, (FVector)B, CapsuleColor, LineThickness, DepthBias)); });
// // connecting lines
// for (int k = 0; k < 2; ++k)
// {
// FVector DX = (k < 1) ? FVector(-Radius, 0, 0) : FVector(Radius, 0, 0);
// LinesOut.Add(FRenderableLine(
// ElemTransform.TransformPosition((FVector)Top + DX),
// ElemTransform.TransformPosition((FVector)Bottom + DX), CapsuleColor, LineThickness, DepthBias));
// FVector DY = (k < 1) ? FVector(0, -Radius, 0) : FVector(0, Radius, 0);
// LinesOut.Add(FRenderableLine(
// ElemTransform.TransformPosition((FVector)Top + DY),
// ElemTransform.TransformPosition((FVector)Bottom + DY), CapsuleColor, LineThickness, DepthBias));
// }
//});
}
#undef LOCTEXT_NAMESPACE