添加 Source/FLESH/Private/SoftBodyPhysicsTool.cpp

This commit is contained in:
2025-04-21 18:02:22 +08:00
parent 541f2513f0
commit 37cc1a148d

View File

@@ -0,0 +1,384 @@
#include "SoftBodyPhysicsTool.h"
#include "Components/SkeletalMeshComponent.h"
#include "Components/StaticMeshComponent.h"
#include "PhysicsEngine/PhysicsConstraintComponent.h"
#include "Engine/StaticMesh.h"
#include "Engine/SkeletalMesh.h"
#include "PhysicsEngine/PhysicsAsset.h"
#include "PhysicsEngine/BodySetup.h"
USoftBodyPhysicsTool::USoftBodyPhysicsTool()
{
// Initialize default values
}
bool USoftBodyPhysicsTool::InitializeSoftBodyPhysics(USkeletalMeshComponent* TargetMesh, const FSoftBodySimulationSettings& SimulationSettings)
{
// Validate input
if (!TargetMesh || !TargetMesh->GetSkeletalMeshAsset())
{
UE_LOG(LogTemp, Error, TEXT("SoftBodyPhysicsTool: Invalid target mesh"));
return false;
}
// Store references
TargetMeshComponent = TargetMesh;
CurrentSettings = SimulationSettings;
// Clear existing physics setup
ClearPhysicsConstraints();
// Enable physics on the target mesh
TargetMesh->SetSimulatePhysics(SimulationSettings.bEnableSimulation);
// Create physics constraints based on current configuration
CreatePhysicsConstraints();
return true;
}
bool USoftBodyPhysicsTool::AddAnchorPoint(const FSoftBodyAnchorPoint& AnchorPoint)
{
// Validate target mesh
if (!TargetMeshComponent)
{
UE_LOG(LogTemp, Error, TEXT("SoftBodyPhysicsTool: No target mesh set"));
return false;
}
// Add anchor point to the list
AnchorPoints.Add(AnchorPoint);
// Update physics constraints
UpdatePhysicsConstraints();
return true;
}
bool USoftBodyPhysicsTool::AddLineChain(const FSoftBodyLineChain& LineChain)
{
// Validate target mesh
if (!TargetMeshComponent)
{
UE_LOG(LogTemp, Error, TEXT("SoftBodyPhysicsTool: No target mesh set"));
return false;
}
// Validate line chain
if (LineChain.Points.Num() < 2)
{
UE_LOG(LogTemp, Error, TEXT("SoftBodyPhysicsTool: Line chain must have at least 2 points"));
return false;
}
// Add line chain to the list
LineChains.Add(LineChain);
// Update physics constraints
UpdatePhysicsConstraints();
return true;
}
bool USoftBodyPhysicsTool::AddTetrahedron(const FSoftBodyTetrahedron& Tetrahedron)
{
// Validate target mesh
if (!TargetMeshComponent)
{
UE_LOG(LogTemp, Error, TEXT("SoftBodyPhysicsTool: No target mesh set"));
return false;
}
// Validate tetrahedron
if (Tetrahedron.Points.Num() != 4)
{
UE_LOG(LogTemp, Error, TEXT("SoftBodyPhysicsTool: Tetrahedron must have exactly 4 points"));
return false;
}
// Add tetrahedron to the list
Tetrahedra.Add(Tetrahedron);
// Update physics constraints
UpdatePhysicsConstraints();
return true;
}
bool USoftBodyPhysicsTool::AddPlaneConstraint(const FSoftBodyPlaneConstraint& PlaneConstraint)
{
// Validate target mesh
if (!TargetMeshComponent)
{
UE_LOG(LogTemp, Error, TEXT("SoftBodyPhysicsTool: No target mesh set"));
return false;
}
// Add plane constraint to the list
PlaneConstraints.Add(PlaneConstraint);
// Update physics constraints
UpdatePhysicsConstraints();
return true;
}
void USoftBodyPhysicsTool::UpdateSimulationSettings(const FSoftBodySimulationSettings& SimulationSettings)
{
// Store new settings
CurrentSettings = SimulationSettings;
// Update target mesh physics
if (TargetMeshComponent)
{
TargetMeshComponent->SetSimulatePhysics(SimulationSettings.bEnableSimulation);
}
// Update physics constraints
UpdatePhysicsConstraints();
}
void USoftBodyPhysicsTool::SetSimulationEnabled(bool bEnable)
{
// Update settings
CurrentSettings.bEnableSimulation = bEnable;
// Update target mesh physics
if (TargetMeshComponent)
{
TargetMeshComponent->SetSimulatePhysics(bEnable);
}
}
void USoftBodyPhysicsTool::CreatePhysicsConstraints()
{
if (!TargetMeshComponent)
{
return;
}
// Get the owner actor
AActor* Owner = TargetMeshComponent->GetOwner();
if (!Owner)
{
return;
}
// Create various physics constraints
CreateAnchorConstraints(Owner);
CreateLineChainConstraints(Owner);
CreateTetrahedronConstraints(Owner);
CreatePlaneConstraints(Owner);
}
void USoftBodyPhysicsTool::CreateAnchorConstraints(AActor* Owner)
{
if (!Owner || !TargetMeshComponent)
{
return;
}
// Create anchor point constraints
for (const FSoftBodyAnchorPoint& AnchorPoint : AnchorPoints)
{
// Create a static mesh component for the anchor
UStaticMeshComponent* AnchorComponent = NewObject<UStaticMeshComponent>(Owner, *FString::Printf(TEXT("AnchorComponent_%d"), AnchorPoints.IndexOfByKey(AnchorPoint)));
AnchorComponent->SetupAttachment(TargetMeshComponent);
AnchorComponent->RegisterComponent();
// Set anchor properties
AnchorComponent->SetWorldLocation(TargetMeshComponent->GetComponentTransform().TransformPosition(AnchorPoint.Location));
AnchorComponent->SetCollisionEnabled(ECollisionEnabled::NoCollision);
AnchorComponent->SetVisibility(false);
// Create a physics constraint
UPhysicsConstraintComponent* ConstraintComponent = NewObject<UPhysicsConstraintComponent>(Owner, *FString::Printf(TEXT("ConstraintComponent_%d"), AnchorPoints.IndexOfByKey(AnchorPoint)));
ConstraintComponent->SetupAttachment(TargetMeshComponent);
ConstraintComponent->RegisterComponent();
// Configure constraint
ConstraintComponent->SetConstrainedComponents(TargetMeshComponent, AnchorPoint.BoneName, AnchorComponent, NAME_None);
// Set constraint properties based on stiffness
ConstraintComponent->SetLinearXLimit(ELinearConstraintMotion::LCM_Limited, AnchorPoint.Radius);
ConstraintComponent->SetLinearYLimit(ELinearConstraintMotion::LCM_Limited, AnchorPoint.Radius);
ConstraintComponent->SetLinearZLimit(ELinearConstraintMotion::LCM_Limited, AnchorPoint.Radius);
// Set stiffness
ConstraintComponent->SetLinearDriveParams(AnchorPoint.Stiffness * 1000.0f, AnchorPoint.Stiffness * 100.0f, 0.0f);
// Store components
AnchorComponents.Add(AnchorComponent);
ConstraintComponents.Add(ConstraintComponent);
}
}
void USoftBodyPhysicsTool::CreateLineChainConstraints(AActor* Owner)
{
if (!Owner || !TargetMeshComponent)
{
return;
}
// Create line chain constraints
for (const FSoftBodyLineChain& LineChain : LineChains)
{
for (int32 i = 0; i < LineChain.Points.Num() - 1; ++i)
{
// Create a physics constraint between adjacent points
UPhysicsConstraintComponent* ConstraintComponent = NewObject<UPhysicsConstraintComponent>(Owner, *FString::Printf(TEXT("LineChainConstraint_%d_%d"), LineChains.IndexOfByKey(LineChain), i));
ConstraintComponent->SetupAttachment(TargetMeshComponent);
ConstraintComponent->RegisterComponent();
// Configure constraint
// Note: In a real implementation, we would need to find the closest bones or vertices
// For now, we'll use a simplified approach
FName BoneName1 = FindClosestBone(LineChain.Points[i]);
FName BoneName2 = FindClosestBone(LineChain.Points[i + 1]);
// Configure constraint
ConstraintComponent->SetConstrainedComponents(TargetMeshComponent, BoneName1, TargetMeshComponent, BoneName2);
// Set constraint properties based on stiffness
ConstraintComponent->SetLinearXLimit(ELinearConstraintMotion::LCM_Limited, LineChain.Thickness);
ConstraintComponent->SetLinearYLimit(ELinearConstraintMotion::LCM_Limited, LineChain.Thickness);
ConstraintComponent->SetLinearZLimit(ELinearConstraintMotion::LCM_Limited, LineChain.Thickness);
// Set stiffness
ConstraintComponent->SetLinearDriveParams(LineChain.Stiffness * 1000.0f, LineChain.Stiffness * 100.0f, 0.0f);
// Store component
ConstraintComponents.Add(ConstraintComponent);
}
}
}
void USoftBodyPhysicsTool::CreateTetrahedronConstraints(AActor* Owner)
{
if (!Owner || !TargetMeshComponent)
{
return;
}
// Create tetrahedron constraints
for (const FSoftBodyTetrahedron& Tetrahedron : Tetrahedra)
{
// Create constraints between all pairs of points (6 constraints total)
for (int32 i = 0; i < 4; ++i)
{
for (int32 j = i + 1; j < 4; ++j)
{
// Create a physics constraint between points
UPhysicsConstraintComponent* ConstraintComponent = NewObject<UPhysicsConstraintComponent>(Owner, *FString::Printf(TEXT("TetrahedronConstraint_%d_%d_%d"), Tetrahedra.IndexOfByKey(Tetrahedron), i, j));
ConstraintComponent->SetupAttachment(TargetMeshComponent);
ConstraintComponent->RegisterComponent();
// Configure constraint
// Note: In a real implementation, we would need to find the closest bones or vertices
// For now, we'll use a simplified approach
FName BoneName1 = FindClosestBone(Tetrahedron.Points[i]);
FName BoneName2 = FindClosestBone(Tetrahedron.Points[j]);
// Configure constraint
ConstraintComponent->SetConstrainedComponents(TargetMeshComponent, BoneName1, TargetMeshComponent, BoneName2);
// Set constraint properties based on stiffness
ConstraintComponent->SetLinearXLimit(ELinearConstraintMotion::LCM_Limited, 1.0f);
ConstraintComponent->SetLinearYLimit(ELinearConstraintMotion::LCM_Limited, 1.0f);
ConstraintComponent->SetLinearZLimit(ELinearConstraintMotion::LCM_Limited, 1.0f);
// Set stiffness
ConstraintComponent->SetLinearDriveParams(Tetrahedron.Stiffness * 1000.0f, Tetrahedron.Stiffness * 100.0f, 0.0f);
// Store component
ConstraintComponents.Add(ConstraintComponent);
}
}
}
}
void USoftBodyPhysicsTool::CreatePlaneConstraints(AActor* Owner)
{
if (!Owner || !TargetMeshComponent)
{
return;
}
// Create plane constraints
for (const FSoftBodyPlaneConstraint& PlaneConstraint : PlaneConstraints)
{
// Create a static mesh component for the plane
UStaticMeshComponent* PlaneComponent = NewObject<UStaticMeshComponent>(Owner, *FString::Printf(TEXT("PlaneComponent_%d"), PlaneConstraints.IndexOfByKey(PlaneConstraint)));
PlaneComponent->SetupAttachment(TargetMeshComponent);
PlaneComponent->RegisterComponent();
// Set plane properties
PlaneComponent->SetWorldLocation(TargetMeshComponent->GetComponentTransform().TransformPosition(PlaneConstraint.Location));
PlaneComponent->SetWorldRotation(FRotationMatrix::MakeFromZ(PlaneConstraint.Normal).ToQuat());
PlaneComponent->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
PlaneComponent->SetCollisionResponseToAllChannels(ECR_Block);
PlaneComponent->SetVisibility(false);
// Store component
AnchorComponents.Add(PlaneComponent);
}
}
void USoftBodyPhysicsTool::UpdatePhysicsConstraints()
{
// Clear existing constraints
ClearPhysicsConstraints();
// Create new constraints
CreatePhysicsConstraints();
}
void USoftBodyPhysicsTool::ClearPhysicsConstraints()
{
// Destroy all anchor components
for (UStaticMeshComponent* AnchorComponent : AnchorComponents)
{
if (AnchorComponent)
{
AnchorComponent->DestroyComponent();
}
}
AnchorComponents.Empty();
// Destroy all constraint components
for (UPhysicsConstraintComponent* ConstraintComponent : ConstraintComponents)
{
if (ConstraintComponent)
{
ConstraintComponent->DestroyComponent();
}
}
ConstraintComponents.Empty();
}
FName USoftBodyPhysicsTool::FindClosestBone(const FVector& Point)
{
FName ClosestBoneName = NAME_None;
float ClosestDist = MAX_FLT;
USkeletalMesh* SkelMesh = TargetMeshComponent->GetSkeletalMeshAsset();
if (SkelMesh)
{
const FReferenceSkeleton& RefSkeleton = SkelMesh->GetRefSkeleton();
for (int32 BoneIdx = 0; BoneIdx < RefSkeleton.GetNum(); ++BoneIdx)
{
FName CurrBoneName = RefSkeleton.GetBoneName(BoneIdx);
FTransform BoneTransform = TargetMeshComponent->GetBoneTransform(BoneIdx);
FVector BonePos = BoneTransform.GetLocation();
float Dist = FVector::DistSquared(BonePos, TargetMeshComponent->GetComponentTransform().TransformPosition(Point));
if (Dist < ClosestDist)
{
ClosestDist = Dist;
ClosestBoneName = CurrBoneName;
}
}
}
return ClosestBoneName;
}