diff --git a/Assets/ResourcesData/Etc/Fake Shadow/Fake Shadow_Pos.prefab b/Assets/ResourcesData/Etc/Fake Shadow/Fake Shadow_Pos.prefab index 1e9064c2..105199b9 100644 --- a/Assets/ResourcesData/Etc/Fake Shadow/Fake Shadow_Pos.prefab +++ b/Assets/ResourcesData/Etc/Fake Shadow/Fake Shadow_Pos.prefab @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:015c1962357ca99f6877aa0f0448651e7a0446edd56dcea218e76b90021bf795 -size 7809 +oid sha256:1b7a654df06639ea10470537d037f7c161620ae7c098b2bf55ff3e15079d71d1 +size 7861 diff --git a/Assets/Scripts/KindRetargeting/CustomRetargetingScript.cs b/Assets/Scripts/KindRetargeting/CustomRetargetingScript.cs index 0cef7e4b..502720b8 100644 --- a/Assets/Scripts/KindRetargeting/CustomRetargetingScript.cs +++ b/Assets/Scripts/KindRetargeting/CustomRetargetingScript.cs @@ -38,6 +38,7 @@ namespace KindRetargeting private float hipsOffsetZ = 0f; // 캐릭터 기준 앞뒤 (항상 Forward 방향) [HideInInspector] public float HipsWeightOffset = 1f; + [HideInInspector] public float ChairSeatHeightOffset = 0f; // 의자 좌석 높이 오프셋 (월드 Y 기준) // 축 매핑: 월드 방향(Right/Up/Forward)을 담당하는 로컬 축을 저장 // 예: localAxisForWorldRight = (0, 0, 1) 이면 로컬 Z축이 월드 Right 방향을 담당 @@ -164,6 +165,8 @@ namespace KindRetargeting public List fingerCloseRotationsCache; // 소스 머슬 캘리브레이션 데이터 public List sourceMuscleCalibrationCache; + // 의자 앉기 높이 오프셋 (LimbWeightController) + public float chairSeatHeightOffset; } [System.Serializable] @@ -624,6 +627,10 @@ namespace KindRetargeting muscleCalibrationCache.Add(new MuscleCalibrationData(kvp.Key, kvp.Value.open, kvp.Value.close)); } + // LimbWeightController에서 의자 높이 오프셋 가져오기 + var limbController = GetComponent(); + float chairOffset = limbController != null ? limbController.chairSeatHeightOffset : 0.05f; + var settings = new RetargetingSettings { hipsOffsetX = hipsOffsetX, @@ -647,6 +654,7 @@ namespace KindRetargeting fingerOpenRotationsCache = fingerOpenCache, fingerCloseRotationsCache = fingerCloseCache, sourceMuscleCalibrationCache = muscleCalibrationCache, + chairSeatHeightOffset = chairOffset, }; string json = JsonUtility.ToJson(settings, true); @@ -740,6 +748,13 @@ namespace KindRetargeting // Mingle 캘리브레이션 완료 여부 확인 isMingleCalibrated = fingerOpenRotations.Count > 0 && fingerCloseRotations.Count > 0; + // LimbWeightController에 의자 높이 오프셋 적용 + var limbController = GetComponent(); + if (limbController != null) + { + limbController.chairSeatHeightOffset = settings.chairSeatHeightOffset; + } + //너무 자주 출력되어서 주석처리 //Debug.Log($"설정을 로드했습니다: {filePath}"); } @@ -1601,6 +1616,9 @@ namespace KindRetargeting // 4. 바닥 높이 추가 (월드 Y축 - 바닥은 항상 월드 기준) adjustedPosition.y += floorHeight; + // 5. 의자 좌석 높이 오프셋 추가 (월드 Y축 - 로컬 보정과 별개) + adjustedPosition.y += ChairSeatHeightOffset; + targetHips.position = adjustedPosition; // 6. IK 타겟에도 동기화 diff --git a/Assets/Scripts/KindRetargeting/Editor/LimbWeightControllerEditor.cs b/Assets/Scripts/KindRetargeting/Editor/LimbWeightControllerEditor.cs index 8229cfc4..33754d23 100644 --- a/Assets/Scripts/KindRetargeting/Editor/LimbWeightControllerEditor.cs +++ b/Assets/Scripts/KindRetargeting/Editor/LimbWeightControllerEditor.cs @@ -20,6 +20,7 @@ namespace KindRetargeting SerializedProperty footHeightMaxThreshold; SerializedProperty enableLeftArmIK; SerializedProperty enableRightArmIK; + SerializedProperty chairSeatHeightOffset; private bool showDistanceSettings = true; private bool showWeightSettings = true; @@ -28,6 +29,7 @@ namespace KindRetargeting private bool showGroundHipsSettings = true; private bool showFootHeightSettings = true; private bool showIKActivationSettings = true; + private bool showChairSeatSettings = true; protected override void OnEnable() { @@ -50,6 +52,7 @@ namespace KindRetargeting footHeightMaxThreshold = serializedObject.FindProperty("footHeightMaxThreshold"); enableLeftArmIK = serializedObject.FindProperty("enableLeftArmIK"); enableRightArmIK = serializedObject.FindProperty("enableRightArmIK"); + chairSeatHeightOffset = serializedObject.FindProperty("chairSeatHeightOffset"); } } @@ -170,6 +173,15 @@ namespace KindRetargeting EditorGUI.indentLevel--; } + EditorGUILayout.Space(5); + showChairSeatSettings = EditorGUILayout.Foldout(showChairSeatSettings, "의자 앉기 높이 설정", true); + if (showChairSeatSettings) + { + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(chairSeatHeightOffset, new GUIContent("좌석 높이 오프셋", "의자에 앉을 때 엉덩이가 좌석면에서 떠있는 높이 (월드 Y 기준)")); + EditorGUI.indentLevel--; + } + EditorGUILayout.Space(5); showReferences = EditorGUILayout.Foldout(showReferences, "참조 설정", true); if (showReferences) diff --git a/Assets/Scripts/KindRetargeting/Editor/RetargetingControlWindow.cs b/Assets/Scripts/KindRetargeting/Editor/RetargetingControlWindow.cs index 7c26c949..8dde2a25 100644 --- a/Assets/Scripts/KindRetargeting/Editor/RetargetingControlWindow.cs +++ b/Assets/Scripts/KindRetargeting/Editor/RetargetingControlWindow.cs @@ -295,6 +295,24 @@ public class RetargetingControlWindow : EditorWindow EditorGUILayout.Slider(hipsOffsetZProp, -1f, 1f, new GUIContent("← 앞뒤 →", "캐릭터 기준 뒤(-) / 앞(+)")); + // 의자 앉기 높이 설정 (월드 Y 기준) + EditorGUILayout.Space(5); + var limb = script.GetComponent(); + if (limb != null) + { + var serializedLimb = new SerializedObject(limb); + serializedLimb.Update(); + var chairSeatHeightOffset = serializedLimb.FindProperty("chairSeatHeightOffset"); + EditorGUI.BeginChangeCheck(); + EditorGUILayout.Slider(chairSeatHeightOffset, -1f, 1f, + new GUIContent("의자 앉기 높이", "의자에 앉을 때 엉덩이 높이 조정 (월드 Y 기준)")); + if (EditorGUI.EndChangeCheck()) + { + serializedLimb.ApplyModifiedProperties(); + EditorUtility.SetDirty(limb); + } + } + EditorGUI.indentLevel--; } diff --git a/Assets/Scripts/KindRetargeting/LimbWeightController.cs b/Assets/Scripts/KindRetargeting/LimbWeightController.cs index 6ea13eb4..25ff9174 100644 --- a/Assets/Scripts/KindRetargeting/LimbWeightController.cs +++ b/Assets/Scripts/KindRetargeting/LimbWeightController.cs @@ -32,6 +32,11 @@ namespace KindRetargeting [SerializeField] public bool enableLeftArmIK = true; // 왼팔 IK 활성화 여부 [SerializeField] public bool enableRightArmIK = true; // 오른팔 IK 활성화 여부 + [Header("의자 앉기 높이 설정")] + [Tooltip("의자에 앉을 때 엉덩이 높이 조정 (월드 Y 기준, +: 위로, -: 아래로)")] + [SerializeField, Range(-1f, 1f)] + public float chairSeatHeightOffset = 0.05f; + private FullBodyInverseKinematics_RND fbik; private CustomRetargetingScript crs; @@ -60,6 +65,10 @@ namespace KindRetargeting List hipsWeights = new List(); private float MasterHipsWeight = 1f; + // 의자 좌석 높이 오프셋 (월드 Y 기준) + private float currentChairSeatOffset = 0f; + private float targetChairSeatOffset = 0f; + void Update() { //손의 거리를 기반으로한 가중치 적용 @@ -297,18 +306,35 @@ namespace KindRetargeting if (hipsTransform != null && props != null) { float minDistance = float.MaxValue; + bool foundChair = false; + foreach (Transform prop in props) { PropTypeController ptc = prop.GetComponent(); if (ptc != null && ptc.propType == EnumsList.PropType.Chair) { float distance = Vector3.Distance(hipsTransform.position, prop.childCount > 0 ? prop.GetChild(0).position : prop.position); - minDistance = Mathf.Min(minDistance, distance); + if (distance < minDistance) + { + minDistance = distance; + foundChair = true; + } } } float t = Mathf.Clamp01((minDistance - hipsMinDistance) / (hipsMaxDistance - hipsMinDistance)); hipsWeights[0] = t; // 직접 HipsWeightOffset 수정 대신 배열에 저장 + + // 의자 좌석 높이 오프셋 계산 (가까울수록 더 적용) - 캐릭터별 설정 사용 + if (foundChair) + { + // t가 0에 가까울수록 의자에 가까움 → 좌석 오프셋 더 적용 + targetChairSeatOffset = chairSeatHeightOffset * (1f - t); + } + else + { + targetChairSeatOffset = 0f; + } } } @@ -362,10 +388,18 @@ namespace KindRetargeting weightSmoothSpeed * deltaTime ); + // 의자 좌석 높이 오프셋 스무딩 (월드 Y 기준) + currentChairSeatOffset = Mathf.Lerp( + currentChairSeatOffset, + targetChairSeatOffset, + weightSmoothSpeed * deltaTime + ); + // CustomRetargetingScript에 최종 가중치 전달 if (crs != null) { crs.HipsWeightOffset = MasterHipsWeight; + crs.ChairSeatHeightOffset = currentChairSeatOffset; } }