添加 Source/FLESH/Private/SoftBodyPhysicsTool.cpp
This commit is contained in:
384
Source/FLESH/Private/SoftBodyPhysicsTool.cpp
Normal file
384
Source/FLESH/Private/SoftBodyPhysicsTool.cpp
Normal 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;
|
||||||
|
}
|
Reference in New Issue
Block a user