애니메이션 테스트

This commit is contained in:
2026-08-26 09:47:39 +09:00
parent 7204afae54
commit 65024110df
3 changed files with 116 additions and 14 deletions

View File

@@ -56,6 +56,9 @@ public class HeadLookAt : MonoBehaviour
Transform neck;
Transform root;
// 기준(정지) 자세. 회전 누적을 막기 위해 매 프레임 여기로 되돌린 뒤 적용한다.
Quaternion restHead, restNeck;
Vector2 currentAngles; // x = yaw, y = pitch
float lastSeenTime = -999f;
@@ -66,11 +69,15 @@ void Awake()
if (animator == null) animator = GetComponentInChildren<Animator>();
if (viewCamera == null) viewCamera = Camera.main;
if (window == null) window = FindFirstObjectByType<TransparentWindow>();
ResolveBones();
}
void ResolveBones()
// Awake 가 아니라 첫 LateUpdate 에서 해석한다. VRM 컨트롤 리그가 만들어지는
// 시점에 Animator.avatar 가 교체되므로, 그보다 먼저 캐시하면 곧 무효가 될
// 실제 메시 본을 잡게 된다.
bool resolved;
bool warned;
bool TryResolveBones()
{
if (headOverride != null)
{
@@ -82,17 +89,26 @@ void ResolveBones()
neck = animator.GetBoneTransform(HumanBodyBones.Neck); // 없는 리그도 있다
}
if (head == null)
if (head != null)
{
Debug.LogWarning("[HeadLookAt] 머리 본을 찾지 못했습니다. " +
"FBX 임포트 설정에서 Animation Type = Humanoid 인지 확인하거나 " +
"Head Override 를 직접 지정하세요.");
enabled = false;
restHead = head.localRotation;
if (neck != null) restNeck = neck.localRotation;
resolved = true;
return true;
}
if (!warned)
{
warned = true;
Debug.LogWarning("[HeadLookAt] 머리 본을 찾지 못했습니다. " +
"휴머노이드 리그인지, Head Override 지정이 필요한지 확인하세요.");
}
return false;
}
void LateUpdate()
{
if (!resolved && !TryResolveBones()) return;
if (head == null) return;
Vector2 desired;
@@ -165,6 +181,11 @@ void ApplyRotation()
float neckPart = neck != null ? neckShare : 0f;
float headPart = 1f - neckPart;
// 매 프레임 기준 자세로 되돌린다. 이걸 빼면 델타가 누적되어 목이 계속 돌아간다.
// (Animator 가 포즈를 써주면 불필요하지만, 클립이 없는 지금은 되돌릴 주체가 없다)
head.localRotation = restHead;
if (neck != null) neck.localRotation = restNeck;
if (neck != null)
{
neck.rotation = Delta(yaw * neckPart, pitch * neckPart) * neck.rotation;