添加 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