2024. 2. 20. 23:20ㆍ강의/UE5 기타 강의들
- 언리얼 5의 기본 Foot IK를 살펴보면, Alpha Interpolate 노드를 찾아 볼 수 있습니다.
- 여기서 ZOffset_R_Target은 발에서 쏜 레이의 HitLocation을 의미합니다.
- 하지만, 인풋값이 하나라서 이것이 보간한다는건 알겠지만, 어떻게 동작하는지 이해하기 어려웠습니다.
- 언리얼 내부 코드(5.3)에서 Alpha Interpolate 의 구현을 엿볼 수 있습니다.
1. Alpha Interpolate
FRigVMFunction_AlphaInterp()
{
Value = Result = 0.f;
ScaleBiasClamp = FInputScaleBiasClamp();
bMapRange = ScaleBiasClamp.bMapRange;
bClampResult = ScaleBiasClamp.bClampResult;
bInterpResult = ScaleBiasClamp.bInterpResult;
InRange = ScaleBiasClamp.InRange;
OutRange = ScaleBiasClamp.OutRange;
Scale = ScaleBiasClamp.Scale;
Bias = ScaleBiasClamp.Bias;
ClampMin = ScaleBiasClamp.ClampMin;
ClampMax = ScaleBiasClamp.ClampMax;
InterpSpeedIncreasing = ScaleBiasClamp.InterpSpeedIncreasing;
InterpSpeedDecreasing = ScaleBiasClamp.InterpSpeedDecreasing;
}
FRigVMFunction_AlphaInterp_Execute()
{
ScaleBiasClamp.bMapRange = bMapRange;
ScaleBiasClamp.bClampResult = bClampResult;
ScaleBiasClamp.bInterpResult = bInterpResult;
ScaleBiasClamp.InRange = InRange;
ScaleBiasClamp.OutRange = OutRange;
ScaleBiasClamp.ClampMin = ClampMin;
ScaleBiasClamp.ClampMax = ClampMax;
ScaleBiasClamp.Scale = Scale;
ScaleBiasClamp.Bias = Bias;
ScaleBiasClamp.InterpSpeedIncreasing = InterpSpeedIncreasing;
ScaleBiasClamp.InterpSpeedDecreasing = InterpSpeedDecreasing;
Result = ScaleBiasClamp.ApplyTo(Value, ExecuteContext.GetDeltaTime());
}
- 위 코드를 보면, 이 노드는 FInputScaleBiasClamp라는 구조체를 통해, 알고리즘을 실행한다는 것을 알 수 있습니다.
- 구조체에서 변수들을 저장해서 가지고 있다는 것 또한 알 수 있죠. (그래서 인풋값이 하나여도 동작)
2. FInputScaleBiasClamp
https://github.com/EpicGames/UnrealEngine/blob/072300df18a94f18077ca20a14224b5d99fee872/Engine/Source/Runtime/Engine/Classes/Animation/InputScaleBias.h#L77
FInputScaleBiasClamp()
: bMapRange(false)
, bClampResult(false)
, bInterpResult(false)
, bInitialized(false)
, Scale(1.0f)
, Bias(0.0f)
, ClampMin(0.f)
, ClampMax(1.f)
, InterpSpeedIncreasing(10.f)
, InterpSpeedDecreasing(10.f)
, InterpolatedResult(0.f)
// https://github.com/EpicGames/UnrealEngine/blob/072300df18a94f18077ca20a14224b5d99fee872/Engine/Source/Runtime/Engine/Private/Animation/InputScaleBias.cpp#L116
float FInputScaleBiasClamp::ApplyTo(float Value, float InDeltaTime) const
{
float Result = Value;
if (bMapRange)
{
Result = FMath::GetMappedRangeValueUnclamped(InRange.ToVector2f(), OutRange.ToVector2f(), Result);
}
Result = Result * Scale + Bias;
if (bClampResult)
{
Result = FMath::Clamp<float>(Result, ClampMin, ClampMax);
}
if (bInterpResult)
{
if (bInitialized)
{
const float InterpSpeed = (Result >= InterpolatedResult) ? InterpSpeedIncreasing : InterpSpeedDecreasing;
Result = FMath::FInterpTo(InterpolatedResult, Result, InDeltaTime, InterpSpeed);
}
InterpolatedResult = Result;
}
bInitialized = true;
return Result;
}
- FInputScaleBiasClamp는 내부적으로 InterpolateResult를 가지고 있으며, 초기값은 0.0 입니다.
- 그리고 ApplyTo가 실행될 때 마다 이 값과 Target 사이를 보간해나갑니다.
- 그렇게 우리는 최종적으로 Target이라는 값을 부드럽게 얻어낼 수 있습니다.
/** Interpolate float from Current to Target. Scaled by distance to Target, so it has a strong start speed and ease out. */
template<typename T1, typename T2 = T1, typename T3 = T2, typename T4 = T3>
UE_NODISCARD static auto FInterpTo( T1 Current, T2 Target, T3 DeltaTime, T4 InterpSpeed )
{
using RetType = decltype(T1() * T2() * T3() * T4());
// If no interp speed, jump to target value
if( InterpSpeed <= 0.f )
{
return static_cast<RetType>(Target);
}
// Distance to reach
const RetType Dist = Target - Current;
// If distance is too small, just set the desired location
if( FMath::Square(Dist) < UE_SMALL_NUMBER )
{
return static_cast<RetType>(Target);
}
// Delta Move, Clamp so we do not over shoot.
const RetType DeltaMove = Dist * FMath::Clamp<RetType>(DeltaTime * InterpSpeed, 0.f, 1.f);
return Current + DeltaMove;
}
- FInterpTo 함수는 위와 같이 거리를 구하고, 이 거리를 일정 비율만큼 이동시킵니다.
- 여기서, Current는 항상 업데이트되므로, Current 와 Target이 가까울 수 록 ease out
- 즉 처음엔 빠르지만, 점점 속도가 낮아지는 보간을 수행합니다.
---
소스코드 링크
---
'강의 > UE5 기타 강의들' 카테고리의 다른 글
[UE5] Crouch 상태일 때 Foot IK 문제 해결 (1) | 2024.02.20 |
---|---|
[UE5] Lyra의 Crouch 카메라 보정 (0) | 2024.02.18 |
[UE5] 애니메이션 적용 (0) | 2024.02.15 |