Unity Animation Rigging IK 체인 구성 완전 가이드
Unity Animation Rigging 패키지는 런타임 IK와 컨스트레인트를 구현합니다. 애니메이션 클립과 독립적으로 동작하여 표면 적응, 조준, 손 위치 보정 등을 실시간으로 처리할 수 있습니다.
설치: Package Manager → com.unity.animation.rigging
1. 기본 설정
섹션 제목: “1. 기본 설정”캐릭터 오브젝트 구조: Character ├── Rig 1 (Rig 컴포넌트 + RigBuilder 컴포넌트를 Character에 추가) │ ├── TwoBoneIK_RightHand │ ├── TwoBoneIK_LeftHand │ └── AimIK_Head └── Armature └── (스켈레톤 본)RigBuilder 설정: Character 오브젝트에 Rig Builder 컴포넌트 추가 → Rigs 리스트에 Rig 오브젝트 추가
2. Two Bone IK — 손/팔 IK
섹션 제목: “2. Two Bone IK — 손/팔 IK”// 에디터 설정 후 런타임 제어using UnityEngine;using UnityEngine.Animations.Rigging;
public class HandIKController : MonoBehaviour{ [Header("IK 컨스트레인트")] [SerializeField] private TwoBoneIKConstraint rightHandIK; [SerializeField] private TwoBoneIKConstraint leftHandIK;
[Header("무기 그립 위치")] [SerializeField] private Transform rightGrip; [SerializeField] private Transform leftGrip;
private float _ikWeight = 0f; private bool _isHoldingWeapon = false;
void Update() { // IK 무게 스무스 전환 float targetWeight = _isHoldingWeapon ? 1f : 0f; _ikWeight = Mathf.MoveTowards(_ikWeight, targetWeight, Time.deltaTime * 5f);
rightHandIK.weight = _ikWeight; leftHandIK.weight = _ikWeight;
// 손 위치를 무기 그립으로 이동 if (rightGrip != null) rightHandIK.data.target.position = rightGrip.position; if (leftGrip != null) leftHandIK.data.target.position = leftGrip.position; }
public void PickUpWeapon(Transform weaponRightGrip, Transform weaponLeftGrip) { rightGrip = weaponRightGrip; leftGrip = weaponLeftGrip; _isHoldingWeapon = true; }}3. AimConstraint — 조준 시스템
섹션 제목: “3. AimConstraint — 조준 시스템”public class AimSystem : MonoBehaviour{ [SerializeField] private MultiAimConstraint spineAim; // 척추 조준 [SerializeField] private MultiAimConstraint headAim; // 머리 조준 [SerializeField] private Transform aimTarget; // 조준점
[SerializeField] private float aimSmoothSpeed = 10f;
private Vector3 _targetPosition; private bool _isAiming;
void Update() { if (_isAiming) { // 조준 무게 증가 spineAim.weight = Mathf.Lerp(spineAim.weight, 1f, Time.deltaTime * aimSmoothSpeed); headAim.weight = Mathf.Lerp(headAim.weight, 0.8f, Time.deltaTime * aimSmoothSpeed);
// 조준점 이동 aimTarget.position = Vector3.Lerp( aimTarget.position, _targetPosition, Time.deltaTime * aimSmoothSpeed); } else { spineAim.weight = Mathf.Lerp(spineAim.weight, 0f, Time.deltaTime * 5f); headAim.weight = Mathf.Lerp(headAim.weight, 0f, Time.deltaTime * 5f); } }
public void SetAimTarget(Vector3 worldPosition) { _targetPosition = worldPosition; _isAiming = true; }
public void StopAiming() => _isAiming = false;}4. 발 IK — 지형 적응
섹션 제목: “4. 발 IK — 지형 적응”public class FootIKSystem : MonoBehaviour{ [SerializeField] private TwoBoneIKConstraint leftFootIK; [SerializeField] private TwoBoneIKConstraint rightFootIK; [SerializeField] private Transform leftFootTarget; [SerializeField] private Transform rightFootTarget;
[SerializeField] private float footHeightOffset = 0.1f; [SerializeField] private LayerMask groundMask;
void LateUpdate() { AdaptFootToGround(leftFootTarget, leftFootIK); AdaptFootToGround(rightFootTarget, rightFootIK); }
void AdaptFootToGround(Transform footTarget, TwoBoneIKConstraint constraint) { Ray ray = new Ray(footTarget.position + Vector3.up * 0.5f, Vector3.down);
if (Physics.Raycast(ray, out RaycastHit hit, 1.5f, groundMask)) { // 발을 지면에 붙임 Vector3 targetPos = hit.point + Vector3.up * footHeightOffset; footTarget.position = Vector3.Lerp( footTarget.position, targetPos, Time.deltaTime * 15f);
// 법선 방향으로 발 회전 Quaternion targetRot = Quaternion.FromToRotation( footTarget.up, hit.normal) * footTarget.rotation; footTarget.rotation = Quaternion.Lerp( footTarget.rotation, targetRot, Time.deltaTime * 15f);
constraint.weight = 1f; } else { constraint.weight = Mathf.Lerp(constraint.weight, 0f, Time.deltaTime * 5f); } }}5. OverrideTransform — 본 직접 제어
섹션 제목: “5. OverrideTransform — 본 직접 제어”public class HeadLookAt : MonoBehaviour{ [SerializeField] private OverrideTransform headConstraint; [SerializeField] private Transform lookAtTarget;
void Update() { // 머리가 바라볼 방향 계산 Vector3 direction = lookAtTarget.position - headConstraint.transform.position;
headConstraint.data.target.rotation = Quaternion.LookRotation(direction); headConstraint.weight = 0.7f; // 70% 영향 (애니메이션 30% 유지) }}6. 런타임 Rig 가중치 제어
섹션 제목: “6. 런타임 Rig 가중치 제어”public class RigController : MonoBehaviour{ [SerializeField] private Rig combatRig; [SerializeField] private Rig idleRig;
private RigBuilder _rigBuilder;
void Awake() { _rigBuilder = GetComponent<RigBuilder>(); }
public void SwitchToCombat() { combatRig.weight = 1f; idleRig.weight = 0f; }
public void SwitchToIdle() { StartCoroutine(BlendRigs()); }
IEnumerator BlendRigs() { float t = 0f; while (t < 1f) { t += Time.deltaTime * 3f; combatRig.weight = 1f - t; idleRig.weight = t; yield return null; } }}| 컨스트레인트 | 용도 |
|---|---|
TwoBoneIKConstraint | 팔/다리 2본 IK |
ChainIKConstraint | 꼬리/촉수 다본 IK |
MultiAimConstraint | 본이 타겟을 바라봄 |
OverrideTransform | 본 위치/회전 직접 덮어쓰기 |
MultiParentConstraint | 여러 부모의 영향 혼합 |