드론의 움직임에 대한 물리적 고민

이제 이러한 다양한 물리적인 상황을 반영해서 드론이 자연스럽게 움직일 수있도록 구현을 해보도록 하겠다.

먼저, 드론이 어떻게 공중에서 움직이는지 물리적인 측면에서 속도 계산을 어떻게 할 수 있을지를 먼저 고민을 해봤다. 기존의 움직임 관련 Movement 컴포넌트나 Physics 세팅, Youtube 영상이나 Github 오픈소스 코드를 찾아보면서 다른 비행체들이 어떻게 물리적 구현을 했는지를 살펴보았다.

기존의 언리얼 MovementComponentPhysics 설정은 주로 캐릭터나 차량같이 지면을 움직이는 구조에 최적화 되어 있어, 공중에서 6DOF로 움직이는 드론의 경우에는 한계가 보였다. 다른 오픈소스를 참고하여 비행체를 시뮬레이션하는 코드를 확인했을 때, 추력 (Thrust), 중력 (Gravity), 항력 (Drag), 감속 보간 (Damping), 질량 (Mass) 등의 요소를 직접 계산해서 각 가속도나 힘을 계산하고 있었다.

일단, 내가 구현한 방식은 입력값이 들어오면 3방향으로 들어오는 힘을 계산하고, 여기서 중력을 감안해서 이걸 바탕으로 가속도를 재현하고 가속도를 바탕으로 속도를 구현하는데, 속도의 경우에는 고려해야 할 부분이 최대 속도나 최소 속도를 넘겼거나, 혹은 지면이나 벽면 혹은 천장에 닿아 XY 축이나 혹은 벽면에서 부드럽게 앞으로 나아가거나 (혹은 떨어지게 하거나) 하는 부분이었다.

기존의 언리얼 코드에서는 MovementComponent나 FlyingMovementSimulation 같은 파일을 찾아보다보면 이런 처리에 대해서 다루고 있다. 솔직히 거기에 있는 물리 공식에 대해서 엄청 자세히 알진 못했지만, SlideAlongSurface의 경우 SafeMoveUpdateComponent 에서 시도한 이동 벡터 중에서 언제 충돌이 발생했는지를 Hit.Time으로 알려주고 이게 0.0 ~ 1.0 사이의 비율로 나온다. 1.0이면 충돌이 없고 0.0이면 즉시 충돌을 했다는 것을 알려준다. 그 다음에 충돌 시점까지 얼마나 남았는지를 계산해서 남은 벡터를 평면에 투영해서 표면을 따라 움직을 수 있게 방향을 계산하는 방식을 사용하고 있다.

/*  기존의 언리얼 MovementComponent 코드에서  */

FVector SlideDelta = ComputeSlideVector(Delta, Time, Normal, Hit);
// 여기서 ... 벡터에 투영해서 방향 계산

SafeMoveUpdatedComponent(SlideDelta, Rotation, true, Hit);
// 이게 이동 ...

TwoWallAdjust(SlideDelta, Hit, OldHitNormal);
// 이게 충돌이 한 번 더 발생했을 때 갱신하는 것

SafeMoveUpdatedComponent(SlideDelta, Rotation, true, Hit);
// 다시 이동...

이제 아래에서 MoveDrone 함수에서 이 Slide Along Surface 함수를 호출해서 드론의 이동을 구현할 수 있다.


void UDroneMovementComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
	Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
	if (!PawnOwner || !UpdatedComponent) return;

	UpdateMovementInput();
	CalculateDroneForce();
	UpdateVelocity(DeltaTime);
	ClampVelocity();

	MoveDrone(DeltaTime); // 여기서 활용! 
	ApplyRotation(DeltaTime);

	UpdateGroundState();
	ClearInput();
}

이제 드론의 움직임에 사용한 물리 계산을 마지막으로 설명을 해보면:

입력 값을 바탕으로 방향을 설정하고

image.png

Force를 계산한다. 여기서 drag가 사실 AirControl과 비슷한 역할을 하지만, 기존의 공기저항 값은 속도에 살짝 감속을 줄 때 사용하고 AirControl은 따로 설정하여 공중에 있을 때 지면보다 더 감속이 되도록 설정하였다. (30%)