절차적 애니메이션
이미 만들어져 있는 애니메이션을 사용하지 않고 실시간으로 시뮬레이션한 동작들로 애니메이션을 생성하는 방법입니다
절차적 애니메이션도 다양한 종류와 방법이 있겠지만 저는 4족보행 유닛의 동작을 개발할 생각으로 IK(Inverse kinematics)를 활용한 거미 형태의 움직임을 재현해보겠습니다
이동하는 모습을 애니메이션 없이 나타내려면 어떤식으로 진행될까 생각해본 결과입니다.
어떻게 만들어야 할까?
1. 우선 기본적인 IK를 적용한다.
2. 움직임에 관련된 파츠(본)들이 현재 재생중인 애니메이션이나 포즈에 영향을 받지 않아야한다.
3. 각 파츠(본)들은 정해진 조건을 만족할때 스스로 위치를 옮긴다.
4. 3번의 과정의 움직임을 디테일하게 수정한다.
절차적 애니메이션 1단계
우선 기본적인 IK 구현으로 높낮이에 대한 각 움직임 파츠의 계산을 진행합니다
Actor의 보조 기능으로 구현하기 때문에 ActorComponent로 만든 후 붙여주었습니다

구현 내용은 다리 bone 혹은 socket에서 최대 높이 ~ 최소 높이의 라인 트레이스를 검사한 후 감지되는 Hit Point를 발바닥의 위치로 변경하는 것입니다.
FVector vBoneLocation = pMesh->GetSocketLocation("다리본or소캣이름");
FVector vStart = FVector(vBoneLocation.X, vBoneLocation.Y, 최대높이);
FVector vEnd = FVector(vBoneLocation.X, vBoneLocation.Y, 최소높이);
//LineTrace
FHitResult stHitResult;
TArray<AActor*> vecIgnore;
vecIgnore.Add(pOwner);
bool isTrace = UKismetSystemLibrary::LineTraceSingle(GetWorld(), vStart, vEnd,
UEngineTypes::ConvertToTraceType(ECC_Visibility), true, vecIgnore, EDrawDebugTrace::None, stHitResult, true);
if (stHitResult.IsValidBlockingHit())
{
다리높이 = stHitResult.ImpactPoint.Z + 바닥과 다리본 높이 보정;
}
여기서 구해진 다리높이를 FVector의 Z값으로 담은 후 애니메이션 인스턴스가 사용할 수 있게 넘겨줍니다.

Animation Graph에서 Outpose로 내보내기 전 TWO Bone IK 혹은 FABRIK , CCDIK 등을 이용해 본의 위치를 변경해줍니다
후에 계산하며 위치를 World공간으로 사용하기 때문에 영향을 줄 공간으로 WorldLocation을 사용했습니다
링크 - TwoboneIK, FABRIK, CCDIK
(셋 다 IK의 각도 연산을 해서 적용해주는 기능인데 FABRIK이 Twobone보다 제어할 수 있는 부분이 좀 더 자세합니다 CCDIK의 경우 실험적인 기능으로 나와 사용하지 않았습니다
만약 본인이 완벽하게 생각하고 있는 자세를 지키며 IK 시키려면 계산을 따로 해주어야 하지 않을까 생각합니다)

1단계 - 포인트의 Z값으로 다리본의 높이가 조절된 모습
절차적 애니메이션 2단계
애니메이션으로 위치가 고정된 다리가 현재 위치를 기억하고 그곳으로 고정되게 변경합니다.

pMesh->GetSocketLocation(FName("다리본이름"))
2단계는 간단하게 다리bone 혹은 socket의 위치를 가져와 내보내는 FVector의 XY값을 넣어주면 됩니다 매번 기록되면 달라지는게 없으니 최초 한번만 기록합니다

다리가 스폰 위치로부터 고정되서 몸통의 움직임을 따르지 않는 모습입니다
절차적 애니메이션 3단계
움직임으로부터 분리 된 다리가 일정 이상 이동을 하면 정해진 위치로 이동하도록 변경합니다


저는 몸통을 기준으로 원래 위치의 소캣을 추가로 만들어 해당 위치를 거리비교 및 이동 포인트로 활용해보았습니다 기준이 되는 소캣과의 거리를 일정이상 초과할때 다리 고정 위치를 다시 구해줍니다
FVector vTargetLocation = pMesh->GetSocketLocation(FName("기준소캣"));
FVector vDst = FVector(현재다리위치.X, 현재다리위치.Y,0.f);
FVector vSrc = FVector(vTargetLocation.X, vTargetLocation.Y, 0.f);
//높이를 제외한 이동거리만 구했습니다
if ((vDst - vSrc).Length() > MAXDISTANCE )
{
넘겨줄 벡터에 다시 기록 = vTargetLocation;
}

일정 범위 이상 벗어났을때 다리가 다시 기준점을 찾아가는 상태
이 단계에서 기능은 완료되었지만 동작이 기괴합니다 이 모습을 일부러 사용하는 몬스터를 구현한다면 이상태에서 마무리 지어도 되겠습니다만 디테일을 찾아보겠습니다.
절차적 애니메이션 4단계
4단계는 이동 자체의 디테일입니다 원하는 퀄리티에 따라 더하셔도 덜하셔도 될 것 같습니다

제가 여기에 더하려는 내용은 다음과 같습니다
1. 정해진 위치로 이동이 아닌 진행방향으로 더 이동
2. 직선이 아닌 다리를 들어서 이동
이동위치 = 이동위치 + (기준점 - 현재위치).GetSafeNormal() * 원하는거리;
현재 이동 거리 = FInterpTo(현재위치,이동위치,델타타임,강도);
이동위치를 기준점이 아닌 기준점의 방향으로 더 이동하도록 변경해줍니다
순간이동이 아닌 선형보간 이동을 하도록 변경했습니다 이 과정에서 기존과 달리 보관해둘 변수 하나가 더 필요해집니다
커브를 그리며 이동하기 위해 Vector Curve 에셋을 만들어서 이 IK컴포넌트에 넣어주었습니다

0에서 시작해 1로 끝나는 그래프를 그렸고 Z값만 사용할거라면 Float Curve를 사용해도 좋습니다
Curve 데이터를 시간값을 이용해 넣어도 좋지만 이동시 현재 위치의 데이터만 구하면 되기 때문에 Timeline이라던가 Deltatime을 이용하지 않아도 됩니다
도착지점과의 거리 / 최대거리값을 이용해 0~1 값을 시간으로 써서 현재 Curve의 값을 구해올 수 있습니다

이동위치 진행방향 보정과 이동시 커브값이 활용된 모습 사진에선 다음 이동할 위치를 현재프레임 - 이전프레임의 위치로 다리 이동중 도착지점을 보정해준 모습입니다

그 외에도 다리가 짚는 위치에 대한 각도값이나 몸체의 위아래 평균값 등을 더해서 디테일을 얼마든지 올릴 수 있습니다.