diff --git a/Assets/External/OptiTrack Unity Plugin/OptiTrack/Scripts/OptitrackSkeletonAnimator_Mingle.cs b/Assets/External/OptiTrack Unity Plugin/OptiTrack/Scripts/OptitrackSkeletonAnimator_Mingle.cs
index 92a59acb8..9cab1d013 100644
--- a/Assets/External/OptiTrack Unity Plugin/OptiTrack/Scripts/OptitrackSkeletonAnimator_Mingle.cs
+++ b/Assets/External/OptiTrack Unity Plugin/OptiTrack/Scripts/OptitrackSkeletonAnimator_Mingle.cs
@@ -39,6 +39,11 @@ public class OptitrackSkeletonAnimator_Mingle : MonoBehaviour
[HideInInspector]
public FilterStrength filterStrength = FilterStrength.Medium;
+ [Header("어깨 증폭")]
+ [Tooltip("어깨 회전을 증폭합니다. 1 = 원본, 2 = 2배. 하위 체인(상완)은 자동 역보정되어 손 위치가 유지됩니다.")]
+ [Range(0f, 10f)]
+ public float shoulderAmplify = 2f;
+
[HideInInspector] public float filterMinCutoff = 3.0f;
[HideInInspector] public float filterBeta = 1.5f;
[HideInInspector] public float filterMaxCutoff = 15.0f;
@@ -423,6 +428,39 @@ public class OptitrackSkeletonAnimator_Mingle : MonoBehaviour
}
}
+ // ── 어깨 증폭 + 상완 역보정 (1.0이면 스킵) ──
+ if (Mathf.Abs(shoulderAmplify - 1f) > 0.001f)
+ {
+ AmplifyShoulderWithCompensation("LShoulder", "LUArm");
+ AmplifyShoulderWithCompensation("RShoulder", "RUArm");
+ }
+
+ }
+
+ ///
+ /// 어깨 회전을 rest pose 대비 증폭하고, 상완에서 추가 회전분을 상쇄하여 손 위치를 보존합니다.
+ ///
+ private void AmplifyShoulderWithCompensation(string shoulderName, string upperArmName)
+ {
+ Transform shoulder = GetMappedTransform(shoulderName);
+ Transform upperArm = GetMappedTransform(upperArmName);
+ if (shoulder == null || upperArm == null) return;
+
+ // rest pose 대비 델타 추출 → 증폭
+ Quaternion restRot = GetRestLocalRotation(shoulderName);
+ Quaternion currentRot = shoulder.localRotation;
+ Quaternion delta = Quaternion.Inverse(restRot) * currentRot;
+ Quaternion amplifiedDelta = Quaternion.SlerpUnclamped(Quaternion.identity, delta, shoulderAmplify);
+ Quaternion amplifiedRot = restRot * amplifiedDelta;
+
+ // 추가된 회전량
+ Quaternion extraRotation = Quaternion.Inverse(currentRot) * amplifiedRot;
+
+ // 어깨에 증폭 적용
+ shoulder.localRotation = amplifiedRot;
+
+ // 상완에서 추가분 상쇄 (손 위치 보존)
+ upperArm.localRotation = Quaternion.Inverse(extraRotation) * upperArm.localRotation;
}
///
diff --git a/Assets/Resources/StreamingleDashboard/dashboard_script.txt b/Assets/Resources/StreamingleDashboard/dashboard_script.txt
index 67007f197..237d666e1 100644
--- a/Assets/Resources/StreamingleDashboard/dashboard_script.txt
+++ b/Assets/Resources/StreamingleDashboard/dashboard_script.txt
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:b8b7459084087b43af049ed7eebac07606d982a72a7aada50036e80d515e0ebf
-size 72569
+oid sha256:0013b010a51681ed769b4fbfb6b9792f2b0926627cbe42adb43d6e4851194144
+size 70967
diff --git a/Assets/Scripts/KindRetargeting/CustomRetargetingScript.cs b/Assets/Scripts/KindRetargeting/CustomRetargetingScript.cs
index 52d8f3bd8..bccfa7c7c 100644
--- a/Assets/Scripts/KindRetargeting/CustomRetargetingScript.cs
+++ b/Assets/Scripts/KindRetargeting/CustomRetargetingScript.cs
@@ -106,9 +106,6 @@ namespace KindRetargeting
[HideInInspector] public Vector3 tPoseHeadForward = Vector3.forward;
[HideInInspector] public Vector3 tPoseHeadUp = Vector3.up;
- [Header("어깨 보정")]
- [SerializeField] public ShoulderCorrectionFunction shoulderCorrection = new ShoulderCorrectionFunction();
-
[Header("프랍 부착")]
[SerializeField] public PropLocationController propLocation = new PropLocationController();
@@ -263,10 +260,6 @@ namespace KindRetargeting
// OptiTrack 스파인 분배 초기화
InitializeOptiTrackSpineDistribution();
- // 어깨 보정 모듈 초기화
- if (targetAnimator != null)
- shoulderCorrection.Initialize(targetAnimator);
-
// 프랍 부착 모듈 초기화
if (targetAnimator != null)
propLocation.Initialize(targetAnimator);
@@ -738,7 +731,6 @@ namespace KindRetargeting
// 손가락은 SyncBoneRotations에서 함께 처리됨 (lastBoneIndex=55)
fingerShaped.OnUpdate();
- shoulderCorrection.OnUpdate();
limbWeight.OnUpdate();
ikSolver.OnUpdate();
diff --git a/Assets/Scripts/KindRetargeting/Editor/CustomRetargetingScriptEditor.cs b/Assets/Scripts/KindRetargeting/Editor/CustomRetargetingScriptEditor.cs
index 0a1f503ff..249550aa4 100644
--- a/Assets/Scripts/KindRetargeting/Editor/CustomRetargetingScriptEditor.cs
+++ b/Assets/Scripts/KindRetargeting/Editor/CustomRetargetingScriptEditor.cs
@@ -62,9 +62,6 @@ namespace KindRetargeting
// ── 머리 회전 오프셋 ──
root.Add(BuildHeadRotationSection());
- // ── 어깨 보정 (ShoulderCorrection) ──
- root.Add(BuildShoulderSection());
-
// ── 사지 가중치 (LimbWeight) ──
root.Add(BuildLimbWeightSection());
@@ -185,33 +182,6 @@ namespace KindRetargeting
return foldout;
}
- // ========== 어깨 보정 ==========
-
- private VisualElement BuildShoulderSection()
- {
- var foldout = new Foldout { text = "어깨 보정 (ShoulderCorrection)", value = false };
-
- var strength = new Slider("블렌드 강도", 0f, 5f) { showInputField = true };
- strength.BindProperty(serializedObject.FindProperty("shoulderCorrection.blendStrength"));
- foldout.Add(strength);
-
- var maxBlend = new Slider("최대 블렌드", 0f, 1f) { showInputField = true };
- maxBlend.BindProperty(serializedObject.FindProperty("shoulderCorrection.maxShoulderBlend"));
- foldout.Add(maxBlend);
-
- foldout.Add(new PropertyField(serializedObject.FindProperty("shoulderCorrection.reverseLeftRotation"), "왼쪽 회전 반전"));
- foldout.Add(new PropertyField(serializedObject.FindProperty("shoulderCorrection.reverseRightRotation"), "오른쪽 회전 반전"));
-
- foldout.Add(BuildMinMaxRange("높이 차이 범위",
- serializedObject.FindProperty("shoulderCorrection.minHeightDifference"),
- serializedObject.FindProperty("shoulderCorrection.maxHeightDifference"),
- -0.5f, 2f));
-
- foldout.Add(new PropertyField(serializedObject.FindProperty("shoulderCorrection.shoulderCorrectionCurve"), "보정 커브"));
-
- return foldout;
- }
-
// ========== 사지 가중치 ==========
private VisualElement BuildLimbWeightSection()
diff --git a/Assets/Scripts/KindRetargeting/Editor/RetargetingControlWindow.cs b/Assets/Scripts/KindRetargeting/Editor/RetargetingControlWindow.cs
index 0f1edd5a7..a141fa345 100644
--- a/Assets/Scripts/KindRetargeting/Editor/RetargetingControlWindow.cs
+++ b/Assets/Scripts/KindRetargeting/Editor/RetargetingControlWindow.cs
@@ -224,9 +224,6 @@ public class RetargetingControlWindow : EditorWindow
footContainer.Bind(so);
panel.Add(footFoldout);
- // 어깨 보정
- panel.Add(BuildShoulderSection(script, so));
-
// 접지 설정
// 손가락 제어 설정
@@ -729,37 +726,6 @@ public class RetargetingControlWindow : EditorWindow
return box;
}
- // ========== Shoulder Correction ==========
-
- private VisualElement BuildShoulderSection(CustomRetargetingScript script, SerializedObject so)
- {
- var foldout = new Foldout { text = "어깨 보정", value = false };
- var container = new VisualElement();
-
- var strength = new Slider("블렌드 강도", 0f, 5f) { showInputField = true };
- strength.BindProperty(so.FindProperty("shoulderCorrection.blendStrength"));
- container.Add(strength);
-
- var maxBlend = new Slider("최대 블렌드", 0f, 1f) { showInputField = true };
- maxBlend.BindProperty(so.FindProperty("shoulderCorrection.maxShoulderBlend"));
- container.Add(maxBlend);
-
- container.Add(new PropertyField(so.FindProperty("shoulderCorrection.reverseLeftRotation"), "왼쪽 회전 반전"));
- container.Add(new PropertyField(so.FindProperty("shoulderCorrection.reverseRightRotation"), "오른쪽 회전 반전"));
-
- container.Add(BuildMinMaxRange("높이 차이 범위",
- so.FindProperty("shoulderCorrection.minHeightDifference"),
- so.FindProperty("shoulderCorrection.maxHeightDifference"),
- -0.5f, 2f, so));
-
- container.Add(new PropertyField(so.FindProperty("shoulderCorrection.shoulderCorrectionCurve"), "보정 커브"));
-
- container.Bind(so);
- foldout.Add(container);
- return foldout;
- }
-
-
// ========== Helpers ==========
private VisualElement BuildMinMaxRange(string label, SerializedProperty minProp, SerializedProperty maxProp, float limitMin, float limitMax, SerializedObject so)
diff --git a/Assets/Scripts/KindRetargeting/Remote/RetargetingRemoteController.cs b/Assets/Scripts/KindRetargeting/Remote/RetargetingRemoteController.cs
index b42dc0bed..fef4d3414 100644
--- a/Assets/Scripts/KindRetargeting/Remote/RetargetingRemoteController.cs
+++ b/Assets/Scripts/KindRetargeting/Remote/RetargetingRemoteController.cs
@@ -280,14 +280,6 @@ namespace KindRetargeting.Remote
{ "enableLeftArmIK", script.limbWeight.enableLeftArmIK },
{ "enableRightArmIK", script.limbWeight.enableRightArmIK },
- // ShoulderCorrection 데이터
- { "shoulderBlendStrength", script.shoulderCorrection.blendStrength },
- { "shoulderMaxBlend", script.shoulderCorrection.maxShoulderBlend },
- { "shoulderMaxHeightDiff", script.shoulderCorrection.maxHeightDifference },
- { "shoulderMinHeightDiff", script.shoulderCorrection.minHeightDifference },
- { "shoulderReverseLeft", script.shoulderCorrection.reverseLeftRotation },
- { "shoulderReverseRight", script.shoulderCorrection.reverseRightRotation },
-
// FingerShapedController 데이터
{ "handPoseEnabled", script.fingerShaped.enabled },
{ "leftHandEnabled", script.fingerShaped.leftHandEnabled },
@@ -420,26 +412,6 @@ namespace KindRetargeting.Remote
script.limbWeight.enableRightArmIK = value > 0.5f;
break;
- // ShoulderCorrection 속성
- case "shoulderBlendStrength":
- script.shoulderCorrection.blendStrength = value;
- break;
- case "shoulderMaxBlend":
- script.shoulderCorrection.maxShoulderBlend = value;
- break;
- case "shoulderMaxHeightDiff":
- script.shoulderCorrection.maxHeightDifference = value;
- break;
- case "shoulderMinHeightDiff":
- script.shoulderCorrection.minHeightDifference = value;
- break;
- case "shoulderReverseLeft":
- script.shoulderCorrection.reverseLeftRotation = value > 0.5f;
- break;
- case "shoulderReverseRight":
- script.shoulderCorrection.reverseRightRotation = value > 0.5f;
- break;
-
// FingerShapedController 속성
case "handPoseEnabled":
script.fingerShaped.enabled = value > 0.5f;
diff --git a/Assets/Scripts/KindRetargeting/ShoulderCorrectionFunction.cs b/Assets/Scripts/KindRetargeting/ShoulderCorrectionFunction.cs
deleted file mode 100644
index 434a0f70a..000000000
--- a/Assets/Scripts/KindRetargeting/ShoulderCorrectionFunction.cs
+++ /dev/null
@@ -1,93 +0,0 @@
-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;
- }
- }
- }
-}
diff --git a/Assets/Scripts/KindRetargeting/ShoulderCorrectionFunction.cs.meta b/Assets/Scripts/KindRetargeting/ShoulderCorrectionFunction.cs.meta
deleted file mode 100644
index 75696218d..000000000
--- a/Assets/Scripts/KindRetargeting/ShoulderCorrectionFunction.cs.meta
+++ /dev/null
@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: d017e8fb3cc30d5448512160bfea29f5
-MonoImporter:
- externalObjects: {}
- serializedVersion: 2
- defaultReferences: []
- executionOrder: 0
- icon: {instanceID: 0}
- userData:
- assetBundleName:
- assetBundleVariant: