169 lines
7.2 KiB
C#
169 lines
7.2 KiB
C#
using UnityEngine;
|
|
using System.Collections.Generic;
|
|
|
|
[DefaultExecutionOrder(2)]
|
|
public class FingerShapedController : MonoBehaviour
|
|
{
|
|
private Animator animator;
|
|
private HumanPoseHandler humanPoseHandler;
|
|
|
|
// 손가락을 제외한 모든 본의 로컬 회전 저장용 (SetHumanPose 호출 시 몸 복원용)
|
|
private Dictionary<HumanBodyBones, Quaternion> savedBoneLocalRotations = new Dictionary<HumanBodyBones, Quaternion>();
|
|
|
|
// 손가락을 제외한 모든 휴먼본 목록
|
|
private static readonly HumanBodyBones[] nonFingerBones = new HumanBodyBones[]
|
|
{
|
|
HumanBodyBones.Hips,
|
|
HumanBodyBones.Spine,
|
|
HumanBodyBones.Chest,
|
|
HumanBodyBones.UpperChest,
|
|
HumanBodyBones.Neck,
|
|
HumanBodyBones.Head,
|
|
HumanBodyBones.LeftShoulder,
|
|
HumanBodyBones.LeftUpperArm,
|
|
HumanBodyBones.LeftLowerArm,
|
|
HumanBodyBones.LeftHand,
|
|
HumanBodyBones.RightShoulder,
|
|
HumanBodyBones.RightUpperArm,
|
|
HumanBodyBones.RightLowerArm,
|
|
HumanBodyBones.RightHand,
|
|
HumanBodyBones.LeftUpperLeg,
|
|
HumanBodyBones.LeftLowerLeg,
|
|
HumanBodyBones.LeftFoot,
|
|
HumanBodyBones.LeftToes,
|
|
HumanBodyBones.RightUpperLeg,
|
|
HumanBodyBones.RightLowerLeg,
|
|
HumanBodyBones.RightFoot,
|
|
HumanBodyBones.RightToes,
|
|
HumanBodyBones.LeftEye,
|
|
HumanBodyBones.RightEye,
|
|
HumanBodyBones.Jaw
|
|
};
|
|
|
|
[Header("왼손 제어 값")]
|
|
[Range(-1, 1)] public float leftPinkyCurl; // 새끼손가락 구부리기
|
|
[Range(-1, 1)] public float leftRingCurl; // 약지 구부리기
|
|
[Range(-1, 1)] public float leftMiddleCurl; // 중지 구부리기
|
|
[Range(-1, 1)] public float leftIndexCurl; // 검지 구부리기
|
|
[Range(-1, 1)] public float leftThumbCurl; // 엄지 구부리기
|
|
[Range(-1, 1)] public float leftSpreadFingers; // 손가락 벌리기
|
|
|
|
[Header("오른손 제어 값")]
|
|
[Range(-1, 1)] public float rightPinkyCurl; // 새끼손가락 구부리기
|
|
[Range(-1, 1)] public float rightRingCurl; // 약지 구부리기
|
|
[Range(-1, 1)] public float rightMiddleCurl; // 중지 구부리기
|
|
[Range(-1, 1)] public float rightIndexCurl; // 검지 구부리기
|
|
[Range(-1, 1)] public float rightThumbCurl; // 엄지 구부리기
|
|
[Range(-1, 1)] public float rightSpreadFingers; // 손가락 벌리기
|
|
|
|
public bool leftHandEnabled = false; // 왼손 제어 활성화 상태
|
|
public bool rightHandEnabled = false; // 오른손 제어 활성화 상태
|
|
|
|
private void Reset()
|
|
{
|
|
// 컴포넌트가 처음 추가될 때 자동으로 비활성화
|
|
enabled = false;
|
|
leftHandEnabled = false;
|
|
rightHandEnabled = false;
|
|
}
|
|
|
|
private void Awake()
|
|
{
|
|
animator = GetComponent<Animator>();
|
|
humanPoseHandler = new HumanPoseHandler(animator.avatar, animator.transform);
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
if (humanPoseHandler != null)
|
|
{
|
|
humanPoseHandler.Dispose();
|
|
}
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
UpdateMuscleValues();
|
|
}
|
|
|
|
private void UpdateMuscleValues()
|
|
{
|
|
// 1. 손가락을 제외한 모든 본의 로컬 회전 저장 (SetHumanPose 호출 전)
|
|
savedBoneLocalRotations.Clear();
|
|
for (int i = 0; i < nonFingerBones.Length; i++)
|
|
{
|
|
Transform bone = animator.GetBoneTransform(nonFingerBones[i]);
|
|
if (bone != null)
|
|
{
|
|
savedBoneLocalRotations[nonFingerBones[i]] = bone.localRotation;
|
|
}
|
|
}
|
|
|
|
// 2. HumanPose 가져오기 및 손가락 머슬 설정
|
|
HumanPose humanPose = new HumanPose();
|
|
humanPoseHandler.GetHumanPose(ref humanPose);
|
|
|
|
// 왼손 제어
|
|
SetHandMuscles(true, leftThumbCurl, leftIndexCurl, leftMiddleCurl, leftRingCurl,
|
|
leftPinkyCurl, leftSpreadFingers, ref humanPose);
|
|
|
|
// 오른손 제어
|
|
SetHandMuscles(false, rightThumbCurl, rightIndexCurl, rightMiddleCurl, rightRingCurl,
|
|
rightPinkyCurl, rightSpreadFingers, ref humanPose);
|
|
|
|
// 3. 머슬 포즈 적용 (손가락 포함 전체 본에 영향)
|
|
humanPoseHandler.SetHumanPose(ref humanPose);
|
|
|
|
// 4. 손가락을 제외한 모든 본의 로컬 회전 복원 (본 길이 변형 방지)
|
|
foreach (var kvp in savedBoneLocalRotations)
|
|
{
|
|
Transform bone = animator.GetBoneTransform(kvp.Key);
|
|
if (bone != null)
|
|
{
|
|
bone.localRotation = kvp.Value;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void SetHandMuscles(bool isLeft, float thumb, float index, float middle, float ring,
|
|
float pinky, float spread, ref HumanPose humanPose)
|
|
{
|
|
// 해당 손이 비활성화 상태면 건너뛰기
|
|
if (isLeft && !leftHandEnabled) return;
|
|
if (!isLeft && !rightHandEnabled) return;
|
|
|
|
int baseOffset = isLeft ? 55 : 75; // 왼손은 55부터, 오른손은 75부터 시작
|
|
int muscleCount = humanPose.muscles.Length;
|
|
|
|
// 엄지손가락
|
|
if (baseOffset < muscleCount) humanPose.muscles[baseOffset] = thumb; // Thumb 1
|
|
if (baseOffset + 1 < muscleCount) humanPose.muscles[baseOffset + 1] = thumb; // Thumb Spread
|
|
if (baseOffset + 2 < muscleCount) humanPose.muscles[baseOffset + 2] = thumb; // Thumb 2
|
|
if (baseOffset + 3 < muscleCount) humanPose.muscles[baseOffset + 3] = thumb; // Thumb 3
|
|
|
|
// 검지
|
|
if (baseOffset + 4 < muscleCount) humanPose.muscles[baseOffset + 4] = index; // Index 1
|
|
if (baseOffset + 5 < muscleCount) humanPose.muscles[baseOffset + 5] = spread; // Index Spread
|
|
if (baseOffset + 6 < muscleCount) humanPose.muscles[baseOffset + 6] = index; // Index 2
|
|
if (baseOffset + 7 < muscleCount) humanPose.muscles[baseOffset + 7] = index; // Index 3
|
|
|
|
// 중지
|
|
if (baseOffset + 8 < muscleCount) humanPose.muscles[baseOffset + 8] = middle; // Middle 1
|
|
if (baseOffset + 9 < muscleCount) humanPose.muscles[baseOffset + 9] = spread; // Middle Spread
|
|
if (baseOffset + 10 < muscleCount) humanPose.muscles[baseOffset + 10] = middle; // Middle 2
|
|
if (baseOffset + 11 < muscleCount) humanPose.muscles[baseOffset + 11] = middle; // Middle 3
|
|
|
|
// 약지
|
|
if (baseOffset + 12 < muscleCount) humanPose.muscles[baseOffset + 12] = ring; // Ring 1
|
|
if (baseOffset + 13 < muscleCount) humanPose.muscles[baseOffset + 13] = spread; // Ring Spread
|
|
if (baseOffset + 14 < muscleCount) humanPose.muscles[baseOffset + 14] = ring; // Ring 2
|
|
if (baseOffset + 15 < muscleCount) humanPose.muscles[baseOffset + 15] = ring; // Ring 3
|
|
|
|
// 새끼손가락
|
|
if (baseOffset + 16 < muscleCount) humanPose.muscles[baseOffset + 16] = pinky; // Little 1
|
|
if (baseOffset + 17 < muscleCount) humanPose.muscles[baseOffset + 17] = spread; // Little Spread
|
|
if (baseOffset + 18 < muscleCount) humanPose.muscles[baseOffset + 18] = pinky; // Little 2
|
|
if (baseOffset + 19 < muscleCount) humanPose.muscles[baseOffset + 19] = pinky; // Little 3
|
|
}
|
|
}
|