IKComponent๋ฅผ ํตํด Character์ ๋ฐ๋ฐ๋ฅ๊ณผ ์งํ์ด ์์ฐ์ค๋ฝ๊ฒ ๋ง๋ฟ์ ์ ์๋๋ก FootIK ์ ์ฉํ๊ธฐ
์์ฝ
- ์ฃผ์ ๋ชฉํ : ์งํ๊ณผ ์ด์ฐ๋ฌ์ง๋ ์์ง์์ ์ํด FootIK ์ ์ฉํ๊ธฐ
- ๐ซ๋ฐ์ ๋ฌธ์ : Skeletal Mesh์
Scale์ ์กฐ์จํ ๊ฒฝ์ฐFoot Effecter๊ฐ์ ์ค์ฐจ ๋ฐ์ - ํด๊ฒฐ ๋ฐฉ์ :
- Skeletal Mesh์
Foot๋ณธ์ ์ถ๊ฐํ Socket์์๋ถํฐ ์ง๋ฉด์ ํฅํ ์ค์๊ฐ ์์งLine Trace๋ก ์ง๋ฉด๊ณผ Foot์ ์์น์ ๊ฐ๋ ์ฐจ์ด๋ฅผ ๋ฐํ๋ฐ์ ABP์์Bone Transform๊ณผ2 Bone IKํจ์๋ก ํ์ฒด ์ฃผ์ Bone์ ์ ์ฉ OwnerCharacter๋ก๋ถํฐGetActorScale์Z๊ฐ์ ๋ฐํ๋ฐ์ ๊ฐFoot Effector์ ๋๋๊ธฐ
- Skeletal Mesh์
- ์ด๋ฃจ์ด๋ธ ์ฑ๊ณผ :
- ๊ฐ๊ธฐ ๋ค๋ฅธ Skeletal Mesh์ Scale ๊ตฌ์ฑ์ ๋ฐ๋ฅธ ์ค์ฐจ์๋ ์ผ๊ด ์ ์ฉ๊ฐ๋ฅํ IKComponent ๊ตฌํ
- ๊ณ๋จ ๋๋ ๊ตด๊ณก์๋ ์งํ์ ์ ์ด์ฐ๋ฌ์ง๋ ์์ง์ ๊ตฌํ
Bone Transform๊ณผ2 Bone IK์ ๋ํ ์ดํด
- Line Trace์ ์์์ ์ Socket์ ์์น์ง๋ง, ์ค์ Skeletal Mesh์ Foot ๋ณธ์ ์์น๊ฐ ์๋ ๋ฐ๋ฐ๋ฅ๋ฉด์ ์์น์ธ Mesh์ Location๊ณผ Hit๋ Impact Point ๊ฐ ๊ฑฐ๋ฆฌ ์ธก์
ํ์ดํ์ ์ ์๊ฑฐ๋ ๋ฐ๊ฟ์น๊ฐ ๋ฉ์ํ๊ฑฐ๋ ๋ค์ํ ํํ์ Mesh์๋ ์ ์ฉ์ด ๊ฐ๋ฅํ๋ค - ๋ฐ๋ฅ๊ณผ ๋์ด์ฐจ๊ฐ ๋ ํฐ ๊ฐ ๋งํผ Pelvis๋ฅผ ๋ด๋ ค ์๋์ ์ผ๋ก ์์ ์์นํ ๋ค๋ฆฌ์๋ง ๋ณํ์ ์ค๋ค Skeletal Mesh์ Pelvis ์์น, ํ์ฒด ๊ธธ์ด ๋น์จ ๋ฑ ๋ณ์์ ์ํฅ์ด ์๋ค
- LineTrace Hit๋ ์ง๋ฉด์ Normal๋ฒกํฐ๋ฅผ ํตํด ์ง๋ฉด์ด ๊ธฐ์ธ์ด์ง ์ ๋๋ฅผ atan2๋ก ๊ตฌํ ์ ์๋ค
- ์ง๋ฉด์ ๊ธฐ์ธ๊ธฐ๋ก ๋ฐ๋ชฉ์ Yaw ํ์ ์ด ์ผ์ด๋๋ ๊ฒฝ์ฐ๋ ์ ์ด ์๋ตํ๊ณ Roll, Pitchํ์ ๊ฐ์ ์ ์ฉ
Settings
- Bone Transform์ ์ํด ๋ณ๋๋์ง ์์ ๊ณ ์ ๊ฐ์ ์ํด ๊ฐ
Foot๋ณธ์ ์์ผ ์ถ๊ฐ -
IK์ ๋ณด๋ฅผ ๋ด์ ABP์ ์ ๋ฌํด์ค ๊ตฌ์กฐ์ฒด
FootIKData์์ฑ๊ตฌ๋ถ ์ด๋ฆ ๋ด์ฉ float DisplacementZ Pelvis์ ์ ์ฉํ Location.Z vector IKEffector_L
IKEffector_RFoot_L๋๋ Foot_R์ Effector Location์ผ๋ก ์ ์ฉ๋ ๋ฒกํฐ rotator Rot_L
Rot_RFoot_L ๋๋ Foot_R์ ์ ์ฉํ Rotator๊ฐ IKComponent์ปดํฌ๋ํธ ์์ฑ -> ์บ๋ฆญํฐ์ ์ปดํฌ๋ํธ ์ถ๊ฐ
Blueprint IKComponent
FootIK์ ๊ฐ๋
๊ณผ ๊ตฌํ๋ฐฉ๋ฒ์ ๊ด๋ จ Unreal Engine Documentation 1 ์ Ryan Laley์ YouTube ์ฑ๋ IK์๋ฆฌ์ฆ 2 ๋ฅผ ์ฐธ๊ณ ํ๊ณ , ์ฌ์ฉํ๋ Mannequin์ height ๋ฑ Mesh Asset์ ๊ธฐ๋ณธ๊ฐ์ผ๋ก ์ธํ ์ค์ฐจ๋ฅผ ์ต์ํํ๊ธฐ ์ํด ๋ณ์๋ฅผ ๋ค๋ฅด๊ฒ ์ ์ฉํ๋ค
์บ๋ฆญํฐ๊ฐ ์ ํ๋ ๊ณต์ค์ ๋ ์๋ ์ํ๊ฐ ์๋๊ฒฝ์ฐ์๋ง FootIK๊ฐ ์ ์ฉ๋๋๋ก Branch๋ฅผ ๊ฑธ์ด์ค ๋ค SetIKํจ์๋ฅผ Tick๋ง๋ค ํธ์ถ
-
Variables
๊ตฌ๋ถ ์ด๋ฆ ๋ด์ฉ Character OwnerCharacter IKComponent๋ฅผ ์์ ํ ์บ๋ฆญํฐ ์กํฐ (struct)FootIKData FootIKData IKComponent์์ ๊ณ์ฐ ์๋ฃ๋์ด ABP๋ก ์ ๋ฌํด ์ค Transform ๋ฐ์ดํฐ float Displacement FootIKData.DisplacementZ์ set ๋ Pelvis๊ฐ Z์ด๋ํด์ผ ํ ๊ฐfloat LFootEffector
RFootEffectorFootIKData.IKEffector_L.X๋๋FootIKData.IKEffector_R.X์ set ๋
Foot_L๊ณผ ์ง๋ฉด์ ๋์ด ์ฐจ(์์๋๊ฐ ๋ค์ง์ด์ง Foot_R๋ณธ์ผ๋ก ์ธํด * -1.0f)rotator LFootRotator
RFootRotatorFootIKData.Rot_L๋๋FootIKData.Rot_R์ set๋ ์ง๋ฉด ๋ ธ๋ง๋ฒกํฐ์ ์ญ๊ฐfloat CharacterScale Scale์ ์ฉ์ผ๋ก ์ธํ ์ค์ฐจ๊ณ์ฐ์ฉ OwnerCharacter์ActorWorldScale3D.Z -
Functions
์ด๋ฆ ๋ด์ฉ LineTrace ์ ๋ ฅ๋ฐ๋ socket์ด๋ฆ์์๋ถํฐ ์ง๋ฉด์ ํฅํด ์์ง Line Trace ํ ๋ค
Hit๋ ์ง์ ์Impact Point์Normal๋ก ๋ฐ์ ์์น์ ์ง๋ฉด์ ๊ฑฐ๋ฆฌ, ์ญ๊ฐ์ ๋ฐํํด์ค ํจ์SetIK Tick๋ง๋ค ์ ๋ฐ์ LineTrace๋ฐํ๊ฐ์ผ๋ก FootIKData๋ฅผ Setํด์ฃผ๋ ํจ์
LineTrace
- Input
InSocketName:LineTrace๋ฅผ ์์ํ Socket์ ์ด๋ฆ
- Return
FootTraceZ: Socket๊ณผ ์ง๋ฉด์ ๊ฑฐ๋ฆฌ(๋์ด) ์ฐจ์ดFootRot: ๋ง๋ฟ์ ์ง๋ฉด์Normal Vector๋ฅผ ์ญ๊ฐ์ผ๋ก ๊ณ์ฐํ Rotation๊ฐ
*Fullscreen๋๋ Ctrl+๋ง์ฐ์คํ ๋ก ZoomIn/Out ๊ฐ๋ฅ
Foot_IK๋ณธ์ Location๋ฅผ Line Trace์Start์ง์ ์ผ๋ก,End์ง์ ์Foot_IK์ X,Y ๊ฐ๊ณผ ํ๋จ์์ง๋ฐฉํฅ์ธOwnerCharacter์Mesh์ Z +Max Step Height๋ก SetMax Step Height๋ฅผ ์ ์ฉํ ์ด์ ๋ ์บ๋ฆญํฐ๊ฐ ์ ํ์์ด ์ค๋ฅด๊ฑฐ๋ ์ถ๋ฝ์ด ์๋ ๊ฑธ์์ผ๋ก ๋ด๋ ค๊ฐ ์ ์๋ ๋์ด๊น์ง๋ง ๋ฐ์ ์ฌ๋ฆฌ๊ฑฐ๋ ๋ด๋ฆฌ๋ ๊ฒ ์์ฐ์ค๋ฌ์ ๋ณด์ด๊ธฐ ๋๋ฌธ์ด๋ค
- Hit๊ฐ
false์ผ ๋ ์ด๊ธฐ๊ฐ(0) ๋ฐํ - Hit๋
Impact Point๋ฒกํฐ์์ ์บ๋ฆญํฐMesh์ ์์น๊น์ง ๊ฑฐ๋ฆฌ๋ฒกํฐ๋ฅผ ๊ตฌํ ๋คHeight๊ฐ ๋Z๊ฐ์FootTraceZ๋ก ๋ฐํ - Hit๋
Normal๋ฒกํฐ๋ฅผ ์ญ๊ฐ์ผ๋ก ๊ณ์ฐํด์ฃผ๊ธฐ์ํดatan2๋กPitch์Roll๊ฐ ์ฐ์ถ
SetIK
- Input
InDeltaTime: Tickํจ์์์ ๋ฐํ๋ฐ๋ DeltaSeconds ์ ๋ฌ
*Fullscreen๋๋ Ctrl+๋ง์ฐ์คํ ๋ก ZoomIn/Out ๊ฐ๋ฅ
- ๊ฐ ๋ฐ์ IK๊ณ์ฐ์ ์ํด ์ถ๊ฐํ
Socket์ ์ธ์๋กLineTrace๋ฐ๋ง๋ค ํธ์ถ LineTrace๋ก ๋ฐํ ๋ฐ์FootTraceZ๊ฐ์ ํด๋น ๋ฐ์FootEffector์ Set- ๊ฐ์์ค๋ฐ ์์น์ ์ฉ์ด ์ด์ํ ์ ์์ด(โ๋ฌ!โํ๊ณ ๋๊น์ง ํ ์ฌ์ด์ ๋ฐ๋์ด ์๋ ์์น)
FInterp์ผ๋ก ๋ณด๊ฐ ์ ์ฉ LineTrace๋ก ๋ฐํ ๋ฐ์FootRot๊ฐ์ ํด๋น ๋ฐ์FootRotation์RInterp์ผ๋ก Set- ๊ฐ Interp speed๋ ๋ฐํ์ ํ์ธ ํ
10.0f๊ฐ ๊ฐ์ฅ ์ ์ ํ์ฌ ์์ Set LFootEffector์RFootEffector์ ์ ๋๊ฐ ์ค ๋ ํฐ ๊ฐ ๋งํผ Pelvis๋ฅผ ์ด๋ํ ์ ์๊ฒDisplacement์FInterpSetFootIKData.DisplacementZ์Displacement๋ฅผ * -1.0f ํด์ Set : Pelvis๋ฅผ ๋ด๋ ค์ค๋คFootIKData.IKEffector_L.X์ ๋ด๋ ค์ค Pelvis๋งํผ ๋ ๋ด๋ฆฌ๊ธฐ ์ํดLFootEffector์Displacement๋ฅผ ๋บFootIKData.IKEffector_R.X์๋RFootEffector์์Displacement๋ฅผ ๋นผ์ค ๋ค ๋ค์ง์ด์งFoot_R์ X์ถ์ ๋ง๊ฒ * -1.0fScale์ด ํฌ๊ฑฐ๋ ์์ Skeletal Mesh์ ๊ฒฝ์ฐ๋ฅผ ์ํดCharacterScale๊ฐ์ ๊ฐ ๋ฐ์ ๋๋ ์ค- Scale์ด ์ปค์ง ๊ฒฝ์ฐ ํด๋น Scale๋งํผ ๋ฐ๊ณผ ์ง๋ฉด์ WorldSpace์์์์ ๊ฑฐ๋ฆฌ์ฐจ๊ฐ ์ปค์ง์ง๋ง BoneSpace๋ Scale์ ์ํฅ์ ๋ฐ์ง ์์ผ๋ฏ๋ก์ ์ญ์ฐํด์ค๋ค
C++ IKComponent
// CFootIKComponent.h
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "Kismet/KismetSystemLibrary.h"
#include "CIKComponent.generated.h"
USTRUCT(BlueprintType)
struct FFootIKData
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintReadOnly, Category = "FootIK")
FVector IKEffector_L;
UPROPERTY(BlueprintReadOnly, Category = "FootIK")
FVector IKEffector_R;
UPROPERTY(BlueprintReadOnly, Category = "FootIK")
FVector DisplacementZ;
UPROPERTY(BlueprintReadOnly, Category = "FootIK")
FRotator Rot_L;
UPROPERTY(BlueprintReadOnly, Category = "FootIK")
FRotator Rot_R;
};
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class UE4_TPSProject UCIKComponent : public UActorComponent
{
GENERATED_BODY()
public:
UCIKComponent();
protected:
virtual void BeginPlay() override;
public:
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
private: // Functions
void LineTrace(FName InSocketName, float& OutFootTraceZ, FRotator& OutFootRot);
public: // Inline
FORCEINLINE FFootIKData GetData() { return FootIKData; }
private: // UProperty Members
UPROPERTY(EditAnywhere, Category = "LineTrace")
TEnumAsByte<EDrawDebugTrace::Type> DrawDebug;
UPROPERTY(EditAnywhere, Category = "LineTrace")
float Displacement = 0.0f;
UPROPERTY(EditAnywhere, Category = "LineTrace")
float LFootEffector = 50.0f;
UPROPERTY(EditAnywhere, Category = "TraLineTracece")
float RFootEffector = 5.0f;
UPROPERTY(EditAnywhere, Category = "LineTrace")
FName LeftSocketName = "Foot_L_IK";
UPROPERTY(EditAnywhere, Category = "LineTrace")
FName RightSocketName = "Foot_R_IK";
private: // Private Members
class ACharacter* OwnerCharacter;
FFootIKData FootIKData;
float InterpSpeed = 10.0f;
float CharacterScale = 1.0f;
};
// CFootIKComponent.cpp
#include "02_Components/CFootIKComponent.h"
#include "Global.h" // Utilities
#include "GameFramework/Character.h"
#include "Components/SkeletalMeshComponent.h"
#include "Components/CapsuleComponent.h"
#define LOG_UCFootIKComponent // Debug Log
UCFootIKComponent::UCFootIKComponent()
{
PrimaryComponentTick.bCanEverTick = true;
}
void UCFootIKComponent::BeginPlay()
{
Super::BeginPlay();
OwnerCharacter = Cast<ACharacter>(GetOwner());
}
LineTrace
// CFootIKComponent.cpp
void UCFootIKComponent::LineTrace(FName InSocketName, float& OutFootTraceZ, FRotator& OutFootRot)
{
// Trace Start
FVector start = OwnerCharacter->GetMesh()->GetSocketLocation(InSocketName);
// Trace End
FVector meshLocation = OwnerCharacter->GetMesh()->GetWorldLocation();
float z = meshLocation.Z - OwnerCharacter->GetCharacterMovementComponent().MaxStepHeight;
FVector end = FVector(socketLocation.X, socketLocation.Y, z);
// LineTrace
TArray<AActor*> ignores;
ignores.Add(OwnerCharacter);
FHitResult hitResult;
UKismetSystemLibrary::LineTraceSingle(GetWorld(), start, end, ETraceTypeQuery::TraceTypeQuery1, true, ignores, DrawDebug, hitResult, true,FLinearColor::Green, FLinearColor::Red);
// Init Outputs
OutFootTraceZ = 0.0f;
OutFootRot = FRotator::ZeroRotator;
// Check Validity
CheckFalse(hitResult.bBlockingHit);
// OutFootTraceZ
FVector distance = (hitResult.ImpactPoint - OwnerCharacter->GetMesh()->GetWorldLocation());
OutFootTraceZ = distance.Z;
// OutFootRot
float roll = UKismetMathLibrary::DegAtan2(hitResult.Normal.Y, hitResult.Normal.Z);
float pitch = UKismetMathLibrary::DegAtan2(hitResult.Normal.X, hitResult.Normal.Z) * -1.0f; // -1 to Rotate in opposite direction
OutRotation = FRotator(pitch, 0, roll);
}
Tick(SetIK)
// CFootIKComponent.cpp
void UCFootIKComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
// Check isFalling
CheckFalse(OwnerCharacter->GetCharacterMovementComponent()->IsFalling());
// Temp Variables
float leftTrace = 0.0f;
float rightTrace = 0.0f;
float displacement = 0.0f;
FRotator leftRot;
FRotator rightRot;
// Character Scale Check
CharacterScale = OwnerCharacter->GetActorWorldScale3D().Z;
// LineTrace from both Sockets
LineTrace(LeftSocketName, leftTrace, leftRot);
LineTrace(RightSocketName, rightTrace, rightRot);
// Pelvis
displacement = FMath::Max(Abs(leftTrace), Abs(rightTrace));
FootIKData.DisplacementZ.Z = UKismetMathLibrary::FInterpTo(FootIKData.DisplacementZ.Z, displacement, DeltaTime, InterpSpeed);
// Left Foot
FootIKData.IKEffector_L.X = UKismetMathLibrary::FInterpTo(FootIKData.IKEffector_L.X, (leftTrace-displacement) / CharacterScale, DeltaTime, InterpSpeed);
FootIKData.Rot_L = UKismetMathLibrary::RInterpTo(FootIKData.Rot_L, leftRot, DeltaTime, InterpSpeed);
// Right Foot
FootIKData.IKEffector_R.X = UKismetMathLibrary::FInterpTo(FootIKData.IKEffector_R.X, -(rightTrace-displacement) / CharacterScale, DeltaTime, InterpSpeed); // -rightTrace due to opposite bone direction
FootIKData.Rot_R = UKismetMathLibrary::RInterpTo(FootIKData.Rot_R, rightRot, DeltaTime, InterpSpeed);
#ifdef LOG_UCFootIKComponent
CLog::Print(FootIKData.DisplacementZ, 11);
CLog::Print(FootIKData.IKEffector_L, 12);
CLog::Print(FootIKData.Rot_L, 13);
CLog::Print(FootIKData.IKEffector_R, 14);
CLog::Print(FootIKData.Rot_R, 15);
#endif // LOG_UCFootIKComponent
}
Animation Blueprint
- Variables
component IKComp:OwnerCharacter๋ฅผ ํตํด ๊ฐ์ ธ์จ IKComponent ๋ณ์๋ก Set(struct)FootIKData FootIKData:IKComp๊ฐ ์ ํจํ ๊ฒฝ์ฐ Getter๋ก ๊ฐ์ ธ์ ๋ณ์๋ก Setbool IKSpace: IK ์คํ์ด ๊ฐ๋ฅํ ์ํฉ ์ฒดํฌ๋ฅผ ์ํ bool
ex) Player์ ๊ฒฝ์ฐ Parkour ์งํ ์ IK ์ ์ฉํด์
- Animation Layer
- ์ต์ข
์ ๋๋ฉ์ด์
ํฌ์ฆ ๋ฐํ ์ง์
IKLayer๋งํฌ IKSpace์ ๊ฐ์ ๋ฐ๋ผ bool๋ก ํฌ์ฆ๋ธ๋๋ฉ
- ์ต์ข
์ ๋๋ฉ์ด์
ํฌ์ฆ ๋ฐํ ์ง์
SetUpBasicData
BlueprintUpdateAnimationEvent๋ฅผ ํตํด Update๋ง๋ค OwnerCharacter์ IKComponent๋ฅผ ํตํด FootIKData๋ฅผ Setํด์ฃผ๊ณ ์บ๋ฆญํฐ์ ์ํ์ ๋ฐ๋ผ ์ ํจ์ฑ ํ์ธ์ ์ํด bool IKSpace ์ฒดํฌ
IKLayer
์
๋ ฅ๋ฐ์ ํฌ์ฆ์ ๋ณธ์ ๋ณํ์ ์ค ์ ์๋ ์ปดํฌ๋ํธ Space๋ก ์ ํํด Bone Transform๊ณผ 2 Bone IKํจ์๋ก IK ์ ์ฉ๋ ํฌ์ฆ ๊ตฌํ
- Pelvis
Bone Transform:
Translation ๊ธฐ์กด ์์น์์ WorldSpace๊ธฐ์คFootIKData.DisplacementZAdd to Existing - Foot_L
2 Bone IK:
Effector Location - Foot_L ๋ณธ์ ๊ธฐ์กด ์์น์์ BoneSpace๊ธฐ์คFootIKData.IKEffector_L์ ๋ ฅ
Joit Target Location - Calf_L ๋ณธ์ ๊ธฐ์กด ์์น์์ ์ด์ง ์์ผ๋ก ํฅํ ์ ์๊ฒ BoneSpace๊ธฐ์ค์ผ๋ก ์ ์ฉ
๋ฐํ์์ผ๋ก ํ์ธ ํ X=0.0, Y=30.0, Z=-5.0 ์ ๋๊ฐ ์ ์ ํ์ฌ ์ ์ฉBone Transform:
Rotation ๊ธฐ์กด ํ์ ๊ฐ์์ WorldSpace๊ธฐ์คFootIKData.Rot_LAdd to Existing
- Foot_R
Foot_L๊ณผ ๋์ผํ๊ฒ ํด๋นํ๋ ๋ณธ์FootIKData์ ์ ๋ณด ์ ์ฉ
2 Bone IKํจ์ Joint Target Location์ Calf_R๋ ๋ฐ๋์ชฝ ๋ค๋ฆฌ์ ์๋ฐ๋ ์ถ์ ๊ฐ์ง๊ณ ์์ด X=0.0, Y=-30.0, Z=5.0 ์ ๋๊ฐ ์ ์
์๊ฐ์ ๋ฆฌ
๊ธฐ๋ณธ์ ์ถฉ์คํ๊ธฐ
๊ธฐ๋ณธ์ ์ผ๋ก ๋ฌด๋ฃ๋ก ์ ๊ณต๋๋ ํ๋ฅญํ IK Plugin๋ค์ด ์์ผ๋ ์ญ์๋ ๋ฐ๋ํ ๊ฐ๋ฐ์์ฌ์ ํ๋ํ๋ ๋ง์ ธ๋ณด๊ณ ๊ฒฐ๊ตญ ์ํ๋ ๋ชจ์ต์ ๊ตฌํํด ๋ฟ๋ฏํ๋ค
FootIK๋ฅผ ์ ์ฉํด์ฃผ๊ธฐ ์ํด ์ฌ๋ฌ Tutorial๋ค์ ๋ณด์์ผ๋,
์ธ๋ฆฌ์ผ์์ง์ ๋ํดํธ 3rd Person Character ๋๋ ๊ฐ์ธ์ ์ผ๋ก ์ ์ฉํ ํน์ Skeletal Mesh ๊ฒฝ์ฐ์ ์ ์ฉ๋ Foot IK๋ก ํค ์ฐจ์ด ๋ฑ์ offset์ ์์๋ก ์ ์ฉํ๋ ์ผ์ด์ค๋ค ๋ฟ์ด์๋ค
์บ๋ฆญํฐ๋ค์ด ๋ณ์ ํ๊ณ Scale๋ ๋ณํ๋๋๋ก ์ค์ ํ ๋ด ํ๋ก์ ํธ์์ ์ด๋ฌํ ์์๊ฐ์ ์ต๋ํ ์ค์ด๊ณ ์ ๊ณ ๋ฏผ์ ๋ง์ดํ๋ค
๊ฒฐ๊ตญ ๊ธฐ๋ณธ ๊ฐ๋
์ ๋ค์ ์ ๋ฆฌํด ์ต๋ํ ๊ฐ๋จํ ๊ตฌํํ๋ ๊ณผ์ ์์ ์ฑ๊ณตํ๊ฒ ๋์๊ณ ์ญ์ ๊ธฐ๋ณธ๊ธฐ๊ฐ ํํํด์ผ ํ์ฉ์ ๊ฐํด์ง ์ ์์์ ๋ค์๊ธ ๊นจ๋ซ๋ ์๊ฐ์ด์๋ค