Streamingle_URP/Assets/Scripts/KindRetargeting/ShoulderCorrectionFunction.cs
user 52d6960710 Refactor : ShoulderCorrectionFunction을 Serializable 모듈로 전환
- RequireComponent 6개 제거 (모듈화 준비)
- ShoulderCorrectionFunction: MonoBehaviour → [Serializable] 클래스
- Start() → Initialize(Animator), Update() → OnUpdate()
- CustomRetargetingScript에서 shoulderCorrection 필드로 소유 및 호출

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 23:00:35 +09:00

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;
}
}
}
}