Physics Constraint
UPhysicsConstraintComponent를 활용한 조인트, 모터, 파괴 가능 연결
Physics Constraint 개요
두 물리 바디를 연결하는 구속 조건
UPhysicsConstraintComponent는 두 개의 물리 바디를 연결하여 상대적 움직임을 제한하는 컴포넌트입니다. 경첩(Hinge), 볼 조인트(Ball Joint), 프리즘(Prismatic) 등 다양한 조인트 유형을 구현할 수 있습니다.
| 자유도(DOF) | Linear (X/Y/Z) | Angular (Swing1/Swing2/Twist) | 조인트 유형 |
|---|---|---|---|
| 고정 (Fixed) | 모두 Locked | 모두 Locked | 용접, 고정 연결 |
| 경첩 (Hinge) | 모두 Locked | Twist만 Limited/Free | 문, 뚜껑 |
| 볼 (Ball Socket) | 모두 Locked | Swing Free, Twist Limited | 관절, 체인 |
| 프리즘 (Prismatic) | 1축만 Limited | 모두 Locked | 슬라이더, 피스톤 |
| 자유 (Free) | 모두 Free | 모두 Free | 제약 없음 (스프링만) |
// 경첩 조인트 생성 예제
UPhysicsConstraintComponent* HingeConstraint;
HingeConstraint = CreateDefaultSubobject<UPhysicsConstraintComponent>("HingeConstraint");
HingeConstraint->SetupAttachment(RootComponent);
// 연결할 두 컴포넌트 지정
HingeConstraint->ComponentName1.ComponentName = "FrameMesh";
HingeConstraint->ComponentName2.ComponentName = "DoorMesh";
// Linear: 모두 잠금
HingeConstraint->SetLinearXLimit(ELinearConstraintMotion::LCM_Locked, 0);
HingeConstraint->SetLinearYLimit(ELinearConstraintMotion::LCM_Locked, 0);
HingeConstraint->SetLinearZLimit(ELinearConstraintMotion::LCM_Locked, 0);
// Angular: Twist만 제한 범위 설정 (경첩)
HingeConstraint->SetAngularSwing1Limit(EAngularConstraintMotion::ACM_Locked, 0);
HingeConstraint->SetAngularSwing2Limit(EAngularConstraintMotion::ACM_Locked, 0);
HingeConstraint->SetAngularTwistLimit(EAngularConstraintMotion::ACM_Limited, 90.0f);
Motor와 Drive
능동적으로 움직이는 Constraint
Constraint에 Motor(Drive)를 설정하면 수동적 제약을 넘어 능동적으로 목표 위치/속도를 추적하는 조인트를 만들 수 있습니다. 로봇 팔, 자동문, 물리 기반 애니메이션 등에 활용됩니다.
// 자동 닫히는 문 (Angular Motor)
void APhysicsDoor::SetupDoorMotor()
{
// Angular Drive 활성화
Constraint->SetAngularDriveMode(EAngularDriveMode::TwistAndSwing);
// Twist Drive 파라미터
Constraint->SetAngularDriveParams(
500.0f, // Spring (강도) - 높을수록 빨리 복원
50.0f, // Damping (감쇠) - 높을수록 진동 감소
0.0f // MaxForce (0 = 무한)
);
// 목표 회전 설정 (닫힌 상태 = 0도)
Constraint->SetAngularOrientationTarget(FRotator::ZeroRotator);
}
// 문 열기 (목표 회전 변경)
void APhysicsDoor::OpenDoor()
{
Constraint->SetAngularOrientationTarget(FRotator(0, 90, 0));
}
// Linear Motor 예제 (엘리베이터)
void AElevator::SetupLinearMotor()
{
Constraint->SetLinearPositionDrive(false, false, true); // Z축만
Constraint->SetLinearDriveParams(
10000.0f, // Spring
1000.0f, // Damping
0.0f // MaxForce
);
// 목표 위치 설정
Constraint->SetLinearPositionTarget(FVector(0, 0, 500.0f));
}
| Drive 파라미터 | 효과 | 높은 값 | 낮은 값 |
|---|---|---|---|
| Spring | 목표를 추적하는 강도 | 빠르고 강한 복원 | 느리고 부드러운 복원 |
| Damping | 진동 억제 | 진동 없이 도달 | 목표 근처에서 진동 |
| MaxForce | 최대 힘 제한 (0=무한) | 제한 없음 | 외력에 의해 목표 이탈 가능 |
파괴 가능 Constraint
일정 힘 이상에서 끊어지는 연결
Constraint의 Breakable 옵션을 활성화하면 특정 힘이 가해졌을 때 연결이 끊어집니다. 체인, 로프, 부서지는 구조물 등에 활용됩니다.
void ABreakableChain::SetupBreakableConstraint()
{
// 파괴 임계값 설정
Constraint->ConstraintInstance.ProfileInstance.bLinearBreakable = true;
Constraint->ConstraintInstance.ProfileInstance.LinearBreakThreshold = 5000.0f;
Constraint->ConstraintInstance.ProfileInstance.bAngularBreakable = true;
Constraint->ConstraintInstance.ProfileInstance.AngularBreakThreshold = 3000.0f;
// 파괴 이벤트 바인딩
Constraint->OnConstraintBroken.AddDynamic(
this, &ABreakableChain::OnChainBroken
);
}
void ABreakableChain::OnChainBroken(int32 ConstraintIndex)
{
UE_LOG(LogTemp, Warning, TEXT("Constraint %d broken!"), ConstraintIndex);
// 파괴 이펙트 스폰, 사운드 재생 등
}
LinearBreakThreshold의 단위는 kg*cm/s^2(뉴턴이 아님)입니다. 적절한 값을 찾으려면 p.Chaos.Solver.Joint.DebugDrawSettings 1 콘솔 명령으로 디버그 정보를 확인하면서 조절하세요.
런타임 Constraint 생성
C++에서 동적으로 물리 연결 만들기
void AGrappleHook::AttachToSurface(FHitResult& Hit)
{
// 런타임에 Constraint 컴포넌트 생성
UPhysicsConstraintComponent* NewConstraint =
NewObject<UPhysicsConstraintComponent>(this);
NewConstraint->RegisterComponent();
NewConstraint->AttachToComponent(
RootComponent,
FAttachmentTransformRules::KeepWorldTransform
);
// 위치 설정
NewConstraint->SetWorldLocation(Hit.ImpactPoint);
// Linear: Z축 제한 거리 내에서 자유 이동 (로프 길이)
NewConstraint->SetLinearXLimit(ELinearConstraintMotion::LCM_Limited, 500.0f);
NewConstraint->SetLinearYLimit(ELinearConstraintMotion::LCM_Limited, 500.0f);
NewConstraint->SetLinearZLimit(ELinearConstraintMotion::LCM_Limited, 500.0f);
// Angular: 자유 회전
NewConstraint->SetAngularSwing1Limit(EAngularConstraintMotion::ACM_Free, 0);
NewConstraint->SetAngularSwing2Limit(EAngularConstraintMotion::ACM_Free, 0);
NewConstraint->SetAngularTwistLimit(EAngularConstraintMotion::ACM_Free, 0);
// 두 바디 연결
NewConstraint->SetConstrainedComponents(
PlayerMesh, NAME_None,
Hit.GetComponent(), Hit.BoneName
);
ActiveConstraint = NewConstraint;
}
핵심 요약
UPhysicsConstraintComponent로 두 물리 바디를 다양한 방식(Fixed, Hinge, Ball, Prismatic)으로 연결합니다.- Linear/Angular Limit의 Locked/Limited/Free 조합으로 원하는 조인트 유형을 구현합니다.
- Motor(Drive)로 Spring/Damping 기반의 능동적 목표 추적이 가능합니다.
- Breakable Constraint로 일정 힘 이상에서 끊어지는 파괴 가능한 연결을 만들 수 있습니다.
SetConstrainedComponents()로 런타임에 동적으로 Constraint를 생성하고 연결할 수 있습니다.
도전 과제
배운 내용을 직접 실습해보세요
Physics Constraint Actor를 사용하여 두 물리 객체를 Hinge Joint로 연결하세요. Angular Limit를 설정하여 문(Door)처럼 동작하는 오브젝트를 만들고, Angular Motor로 자동 닫히는 문을 구현하세요.
10개의 물리 박스를 Physics Constraint로 체인처럼 연결하세요. 각 Constraint의 Linear/Angular Limit과 Damping을 조정하고, 특정 힘 이상에서 끊어지는 Break Force를 설정하세요.
C++로 벽돌벽을 Physics Constraint로 연결된 그리드 구조로 제작하세요. 각 Constraint에 Break Threshold를 설정하고, Impulse에 의한 연쇄 파괴 시스템을 구현하세요.