Rigid Body 시뮬레이션
FBodyInstance를 통한 강체 시뮬레이션의 핵심 파라미터와 제어 방법
FBodyInstance와 Simulate Physics
강체 물리의 출발점
UE5에서 물리 시뮬레이션의 기본 단위는 FBodyInstance입니다. 모든 UPrimitiveComponent는 하나 이상의 FBodyInstance를 가지며, 이를 통해 Chaos 솔버와 상호작용합니다.
// StaticMeshComponent에서 물리 시뮬레이션 활성화
UStaticMeshComponent* MeshComp = CreateDefaultSubobject<UStaticMeshComponent>("MeshComp");
MeshComp->SetSimulatePhysics(true);
// FBodyInstance에 직접 접근
FBodyInstance* Body = MeshComp->GetBodyInstance();
if (Body)
{
Body->bSimulatePhysics = true;
Body->SetMassOverrideInKg(NAME_None, 50.0f, true);
Body->SetLinearVelocity(FVector(0, 0, 500.0f));
}
| FBodyInstance 속성 | 타입 | 설명 | 기본값 |
|---|---|---|---|
bSimulatePhysics |
bool | 물리 시뮬레이션 활성화 | false |
MassInKgOverride |
float | 질량 오버라이드 (kg) | 자동 계산 |
LinearDamping |
float | 선형 감쇠 (이동 저항) | 0.01 |
AngularDamping |
float | 각 감쇠 (회전 저항) | 0.0 |
bEnableGravity |
bool | 중력 적용 여부 | true |
bLockXRotation |
bool | X축 회전 잠금 | false |
MassInKgOverride를 설정하지 않으면 엔진이 콜리전 형상의 체적 x 밀도로 질량을 자동 계산합니다. Physical Material의 Density 값이 이 계산에 영향을 줍니다. 의도치 않게 매우 큰 질량이 설정될 수 있으므로, 중요한 물리 객체는 질량을 명시적으로 지정하는 것이 좋습니다.
힘과 충격량 적용
AddForce, AddImpulse, AddTorque의 차이와 활용
리지드 바디에 운동을 가하는 방법은 크게 힘(Force), 충격량(Impulse), 토크(Torque)로 나뉩니다. 각각의 특성을 이해하고 상황에 맞게 사용해야 합니다.
| 메서드 | 단위 | 적용 방식 | 사용 예시 |
|---|---|---|---|
AddForce() |
N (뉴턴) | 매 프레임 누적, DeltaTime 의존 | 엔진 추력, 바람, 지속적 밀기 |
AddImpulse() |
kg*cm/s | 즉시 속도 변경, 단발성 | 폭발, 점프, 총알 충격 |
AddTorqueInRadians() |
N*cm | 회전력 적용, 매 프레임 누적 | 프로펠러, 팽이 회전 |
AddAngularImpulseInRadians() |
kg*cm^2/s | 즉시 각속도 변경 | 충돌 후 회전, 스핀 공격 |
AddForceAtLocation() |
N | 특정 위치에 힘 적용 (토크 유발) | 비대칭 충격, 로켓 추력 |
// 지속적인 힘 적용 (Tick에서 호출)
void APhysicsActor::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
// 위쪽으로 지속적인 힘 (로켓 추력처럼)
MeshComp->AddForce(
FVector(0, 0, 980.0f) * MeshComp->GetMass(),
NAME_None,
false // bAccelChange = false: 질량에 영향받음
);
}
// 순간 충격량 적용 (이벤트에서 호출)
void APhysicsActor::OnExplosion(FVector ExplosionOrigin)
{
FVector Direction = GetActorLocation() - ExplosionOrigin;
Direction.Normalize();
// 폭발 충격 - 즉시 속도 변경
MeshComp->AddImpulse(
Direction * 5000.0f,
NAME_None,
true // bVelChange = true: 질량 무시, 순수 속도 변경
);
}
bAccelChange=true로 설정하면 질량에 관계없이 동일한 가속도를 적용합니다. 마찬가지로 bVelChange=true는 질량과 무관하게 속도를 직접 변경합니다. 질량이 다른 다양한 오브젝트에 동일한 효과를 주고 싶을 때 유용합니다.
질량, 관성 텐서, 무게중심
강체 물리의 핵심 물성
리지드 바디의 동작은 질량(Mass), 관성 텐서(Inertia Tensor), 무게중심(Center of Mass) 세 가지 물성에 의해 결정됩니다.
void APhysicsActor::ConfigurePhysicsBody()
{
FBodyInstance* Body = MeshComp->GetBodyInstance();
// 질량 설정 (kg)
Body->SetMassOverrideInKg(NAME_None, 100.0f, true);
// 무게중심 오프셋 (로컬 좌표)
Body->COMNudge = FVector(0, 0, -20.0f); // 아래로 이동 → 안정적
// 관성 텐서 스케일 (기본값: 1,1,1)
Body->InertiaTensorScale = FVector(1.0f, 1.0f, 0.5f);
// Z축 관성 감소 → Z축 회전이 더 쉬워짐
// 질량 정보 업데이트
Body->UpdateMassProperties();
// 현재 질량 확인
float Mass = Body->GetBodyMass();
FVector COM = Body->GetCOMPosition();
UE_LOG(LogTemp, Log, TEXT("Mass: %f kg, COM: %s"), Mass, *COM.ToString());
}
| 물성 | 효과 | 게임 플레이 영향 |
|---|---|---|
| 질량 증가 | 같은 힘에 대해 덜 움직임 | 무거운 느낌, 충돌 시 상대를 밀어냄 |
| COM 아래로 이동 | 복원력 증가 | 쓰러지지 않는 안정적 오브젝트 |
| COM 위로 이동 | 불안정한 균형 | 쉽게 넘어지는 오브젝트 |
| 관성 텐서 축소 | 해당 축 회전이 쉬움 | 빠른 회전, 반응적 움직임 |
| 관성 텐서 확대 | 해당 축 회전에 저항 | 느린 회전, 무거운 느낌 |
UE5에서 거리는 cm, 질량은 kg, 시간은 초(s)를 사용합니다. 따라서 힘의 단위는 kg*cm/s^2이고, 충격량은 kg*cm/s입니다. 기본 중력 가속도는 -980 cm/s^2 (= -9.8 m/s^2)입니다.
감쇠, 잠금, Sleep
시뮬레이션 제어와 성능 최적화
실제 게임에서는 무한히 움직이는 물리 객체보다, 적절히 감쇠되고 정지하는 객체가 필요합니다. Damping, Lock, Sleep 메커니즘으로 이를 제어합니다.
void APhysicsActor::SetupDamping()
{
FBodyInstance* Body = MeshComp->GetBodyInstance();
// 선형 감쇠: 0 = 감쇠 없음, 높을수록 빨리 정지
Body->LinearDamping = 0.5f;
// 각 감쇠: 회전 저항
Body->AngularDamping = 1.0f;
// 최대 속도 제한
Body->MaxAngularVelocity = 3600.0f; // degree/s
// 축별 이동 잠금
Body->bLockXTranslation = false;
Body->bLockYTranslation = false;
Body->bLockZTranslation = true; // Z축 이동 잠금 (2D 게임용)
// 축별 회전 잠금
Body->bLockXRotation = true;
Body->bLockYRotation = true;
Body->bLockZRotation = false; // Z축 회전만 허용
Body->UpdateMassProperties();
}
// Sleep 상태 제어
void APhysicsActor::ManageSleep()
{
FBodyInstance* Body = MeshComp->GetBodyInstance();
// Sleep 임계값 설정
Body->SleepFamily = ESleepFamily::Normal;
// 수동으로 깨우기
Body->WakeInstance();
// 수동으로 재우기
Body->PutInstanceToSleep();
}
정지 상태의 물리 객체는 자동으로 Sleep 상태에 들어가 시뮬레이션 비용이 거의 0이 됩니다. 수백 개의 물리 객체가 있는 씬에서도 움직이는 객체만 연산하므로 성능이 유지됩니다. SleepFamily를 Sensitive로 설정하면 더 빠르게 잠들지만, Custom을 사용해 직접 임계값을 지정할 수도 있습니다.
핵심 요약
FBodyInstance는 UE5 물리 시뮬레이션의 기본 단위이며, 모든UPrimitiveComponent에 존재합니다.- Force는 매 프레임 누적되는 지속적 힘, Impulse는 즉시 속도를 변경하는 단발성 충격입니다.
- 질량, 관성 텐서, 무게중심이 강체의 동적 특성을 결정합니다.
- Damping으로 감속을, Lock으로 축별 자유도를 제한하고, Sleep으로 성능을 최적화합니다.
bAccelChange/bVelChange플래그를 사용하면 질량과 무관한 균일한 물리 효과를 줄 수 있습니다.
도전 과제
배운 내용을 직접 실습해보세요
Static Mesh Actor 5개를 레벨에 배치하고 각각 다른 Mass(1kg, 10kg, 50kg, 100kg, 500kg)를 설정하세요. 동일한 Impulse를 가해 질량에 따른 반응 차이를 비교하세요.
경사면 위에 박스를 배치하고 Linear Damping(0, 0.5, 2.0, 5.0)과 Angular Damping(0, 1.0, 5.0)을 조합하여 미끄러짐/굴림 특성의 차이를 관찰하세요. Sleep 상태 전환 시점도 확인하세요.
C++로 AddForce와 AddImpulse를 매 프레임 시각화하는 디버그 액터를 구현하세요. 힘의 방향과 크기를 화살표로 표시하고, 속도 벡터 변화를 그래프로 기록하는 시스템을 만드세요.