- RequireComponent 6개 제거 (모듈화 준비) - ShoulderCorrectionFunction: MonoBehaviour → [Serializable] 클래스 - Start() → Initialize(Animator), Update() → OnUpdate() - CustomRetargetingScript에서 shoulderCorrection 필드로 소유 및 호출 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
94 lines
4.1 KiB
C#
94 lines
4.1 KiB
C#
using UnityEngine;
|
|
|
|
namespace KindRetargeting
|
|
{
|
|
[System.Serializable]
|
|
public class ShoulderCorrectionFunction
|
|
{
|
|
[Header("설정")]
|
|
[Range(0f, 5f)]
|
|
public float blendStrength = 2f;
|
|
[Range(0f, 1f)]
|
|
public float maxShoulderBlend = 0.7f;
|
|
public bool reverseLeftRotation = false;
|
|
public bool reverseRightRotation = false;
|
|
|
|
[Header("높이 제한 설정")]
|
|
public float maxHeightDifference = 0.8f;
|
|
public float minHeightDifference = -0.1f;
|
|
|
|
[Header("보정 커브 설정")]
|
|
public AnimationCurve shoulderCorrectionCurve = AnimationCurve.Linear(0f, 0f, 1f, 1f);
|
|
|
|
private float leftBlendWeight = 0f;
|
|
private float rightBlendWeight = 0f;
|
|
|
|
private Transform leftShoulder;
|
|
private Transform rightShoulder;
|
|
private Transform leftUpperArm;
|
|
private Transform rightUpperArm;
|
|
private Transform leftLowerArm;
|
|
private Transform rightLowerArm;
|
|
|
|
public void Initialize(Animator targetAnimator)
|
|
{
|
|
leftShoulder = targetAnimator.GetBoneTransform(HumanBodyBones.LeftShoulder);
|
|
rightShoulder = targetAnimator.GetBoneTransform(HumanBodyBones.RightShoulder);
|
|
leftUpperArm = targetAnimator.GetBoneTransform(HumanBodyBones.LeftUpperArm);
|
|
rightUpperArm = targetAnimator.GetBoneTransform(HumanBodyBones.RightUpperArm);
|
|
leftLowerArm = targetAnimator.GetBoneTransform(HumanBodyBones.LeftLowerArm);
|
|
rightLowerArm = targetAnimator.GetBoneTransform(HumanBodyBones.RightLowerArm);
|
|
}
|
|
|
|
public void OnUpdate()
|
|
{
|
|
if (leftShoulder == null || rightShoulder == null) return;
|
|
|
|
// 왼쪽 어깨 보정
|
|
Vector3 leftElbowPos = leftLowerArm.position;
|
|
float leftHeightDiff = leftElbowPos.y - leftShoulder.position.y;
|
|
float leftRawBlend = Mathf.Clamp01(
|
|
Mathf.InverseLerp(minHeightDifference, maxHeightDifference, leftHeightDiff) * blendStrength
|
|
);
|
|
leftBlendWeight = shoulderCorrectionCurve.Evaluate(leftRawBlend) * maxShoulderBlend;
|
|
|
|
// 오른쪽 어깨 보정
|
|
Vector3 rightElbowPos = rightLowerArm.position;
|
|
float rightHeightDiff = rightElbowPos.y - rightShoulder.position.y;
|
|
float rightRawBlend = Mathf.Clamp01(
|
|
Mathf.InverseLerp(minHeightDifference, maxHeightDifference, rightHeightDiff) * blendStrength
|
|
);
|
|
rightBlendWeight = shoulderCorrectionCurve.Evaluate(rightRawBlend) * maxShoulderBlend;
|
|
|
|
// 어깨와 윗팔 회전 보정 적용
|
|
if (leftBlendWeight > 0.01f)
|
|
{
|
|
Quaternion currentWorldShoulderRot = leftShoulder.rotation;
|
|
Quaternion currentWorldArmRot = leftUpperArm.rotation;
|
|
|
|
Vector3 shoulderToArm = (leftUpperArm.position - leftShoulder.position).normalized;
|
|
Quaternion targetRotation = Quaternion.FromToRotation(leftShoulder.forward,
|
|
reverseLeftRotation ? shoulderToArm : -shoulderToArm);
|
|
Quaternion targetWorldShoulderRot = targetRotation * currentWorldShoulderRot;
|
|
|
|
leftShoulder.rotation = Quaternion.Lerp(currentWorldShoulderRot, targetWorldShoulderRot, leftBlendWeight);
|
|
leftUpperArm.rotation = currentWorldArmRot;
|
|
}
|
|
|
|
if (rightBlendWeight > 0.01f)
|
|
{
|
|
Quaternion currentWorldShoulderRot = rightShoulder.rotation;
|
|
Quaternion currentWorldArmRot = rightUpperArm.rotation;
|
|
|
|
Vector3 shoulderToArm = (rightUpperArm.position - rightShoulder.position).normalized;
|
|
Quaternion targetRotation = Quaternion.FromToRotation(rightShoulder.forward,
|
|
reverseRightRotation ? -shoulderToArm : shoulderToArm);
|
|
Quaternion targetWorldShoulderRot = targetRotation * currentWorldShoulderRot;
|
|
|
|
rightShoulder.rotation = Quaternion.Lerp(currentWorldShoulderRot, targetWorldShoulderRot, rightBlendWeight);
|
|
rightUpperArm.rotation = currentWorldArmRot;
|
|
}
|
|
}
|
|
}
|
|
}
|