Fix : 머리 회전 기능 업데이트
This commit is contained in:
parent
580b64894c
commit
98676d49db
@ -108,6 +108,11 @@ namespace KindRetargeting
|
|||||||
[Header("발목 높이 설정")]
|
[Header("발목 높이 설정")]
|
||||||
[SerializeField] public float minimumAnkleHeight = 0.2f; // 수동 설정용 최소 발목 높이
|
[SerializeField] public float minimumAnkleHeight = 0.2f; // 수동 설정용 최소 발목 높이
|
||||||
|
|
||||||
|
[Header("머리 회전 오프셋")]
|
||||||
|
[SerializeField, Range(-180f, 180f)] public float headRotationOffsetX = 0f; // 머리 좌우 기울기 (Roll)
|
||||||
|
[SerializeField, Range(-180f, 180f)] public float headRotationOffsetY = 0f; // 머리 좌우 회전 (Yaw)
|
||||||
|
[SerializeField, Range(-180f, 180f)] public float headRotationOffsetZ = 0f; // 머리 상하 회전 (Pitch)
|
||||||
|
|
||||||
[Header("설정 저장/로드")]
|
[Header("설정 저장/로드")]
|
||||||
[SerializeField] private string settingsFolderName = "RetargetingSettings";
|
[SerializeField] private string settingsFolderName = "RetargetingSettings";
|
||||||
|
|
||||||
@ -171,6 +176,10 @@ namespace KindRetargeting
|
|||||||
public List<MuscleCalibrationData> sourceMuscleCalibrationCache;
|
public List<MuscleCalibrationData> sourceMuscleCalibrationCache;
|
||||||
// 의자 앉기 높이 오프셋 (LimbWeightController)
|
// 의자 앉기 높이 오프셋 (LimbWeightController)
|
||||||
public float chairSeatHeightOffset;
|
public float chairSeatHeightOffset;
|
||||||
|
// 머리 회전 오프셋
|
||||||
|
public float headRotationOffsetX;
|
||||||
|
public float headRotationOffsetY;
|
||||||
|
public float headRotationOffsetZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
[System.Serializable]
|
[System.Serializable]
|
||||||
@ -685,6 +694,9 @@ namespace KindRetargeting
|
|||||||
fingerCloseRotationsCache = fingerCloseCache,
|
fingerCloseRotationsCache = fingerCloseCache,
|
||||||
sourceMuscleCalibrationCache = muscleCalibrationCache,
|
sourceMuscleCalibrationCache = muscleCalibrationCache,
|
||||||
chairSeatHeightOffset = chairOffset,
|
chairSeatHeightOffset = chairOffset,
|
||||||
|
headRotationOffsetX = headRotationOffsetX,
|
||||||
|
headRotationOffsetY = headRotationOffsetY,
|
||||||
|
headRotationOffsetZ = headRotationOffsetZ,
|
||||||
};
|
};
|
||||||
|
|
||||||
string json = JsonUtility.ToJson(settings, true);
|
string json = JsonUtility.ToJson(settings, true);
|
||||||
@ -785,6 +797,11 @@ namespace KindRetargeting
|
|||||||
limbController.chairSeatHeightOffset = settings.chairSeatHeightOffset;
|
limbController.chairSeatHeightOffset = settings.chairSeatHeightOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 머리 회전 오프셋 로드
|
||||||
|
headRotationOffsetX = settings.headRotationOffsetX;
|
||||||
|
headRotationOffsetY = settings.headRotationOffsetY;
|
||||||
|
headRotationOffsetZ = settings.headRotationOffsetZ;
|
||||||
|
|
||||||
//너무 자주 출력되어서 주석처리
|
//너무 자주 출력되어서 주석처리
|
||||||
//Debug.Log($"설정을 로드했습니다: {filePath}");
|
//Debug.Log($"설정을 로드했습니다: {filePath}");
|
||||||
}
|
}
|
||||||
@ -1356,6 +1373,36 @@ namespace KindRetargeting
|
|||||||
previousScale = avatarScale;
|
previousScale = avatarScale;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// LateUpdate에서 머리 회전 오프셋을 적용합니다 (IK 이후 실행).
|
||||||
|
/// </summary>
|
||||||
|
void LateUpdate()
|
||||||
|
{
|
||||||
|
ApplyHeadRotationOffset();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 머리 본에 회전 오프셋을 적용합니다.
|
||||||
|
/// </summary>
|
||||||
|
private void ApplyHeadRotationOffset()
|
||||||
|
{
|
||||||
|
if (targetAnimator == null) return;
|
||||||
|
|
||||||
|
// 머리 본 가져오기
|
||||||
|
Transform headBone = targetAnimator.GetBoneTransform(HumanBodyBones.Head);
|
||||||
|
if (headBone == null) return;
|
||||||
|
|
||||||
|
// 오프셋이 모두 0이면 스킵
|
||||||
|
if (Mathf.Approximately(headRotationOffsetX, 0f) &&
|
||||||
|
Mathf.Approximately(headRotationOffsetY, 0f) &&
|
||||||
|
Mathf.Approximately(headRotationOffsetZ, 0f))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// 오프셋 적용 (로컬 회전에 오일러 각도 추가)
|
||||||
|
Quaternion offsetRotation = Quaternion.Euler(headRotationOffsetX, headRotationOffsetY, headRotationOffsetZ);
|
||||||
|
headBone.localRotation *= offsetRotation;
|
||||||
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 머슬 데이터를 사용하여 손가락 포즈를 복제합니다.
|
/// 머슬 데이터를 사용하여 손가락 포즈를 복제합니다.
|
||||||
/// SetHumanPose가 모든 본에 영향을 미치므로, 손가락을 제외한 모든 본의 Transform을 저장하고 복원합니다.
|
/// SetHumanPose가 모든 본에 영향을 미치므로, 손가락을 제외한 모든 본의 Transform을 저장하고 복원합니다.
|
||||||
|
|||||||
@ -27,6 +27,7 @@ public class RetargetingControlWindow : EditorWindow
|
|||||||
private Dictionary<int, bool> rightHandFoldouts = new Dictionary<int, bool>();
|
private Dictionary<int, bool> rightHandFoldouts = new Dictionary<int, bool>();
|
||||||
private Dictionary<int, bool> headFoldouts = new Dictionary<int, bool>();
|
private Dictionary<int, bool> headFoldouts = new Dictionary<int, bool>();
|
||||||
private Dictionary<int, bool> propControlFoldouts = new Dictionary<int, bool>();
|
private Dictionary<int, bool> propControlFoldouts = new Dictionary<int, bool>();
|
||||||
|
private Dictionary<int, bool> headRotationFoldouts = new Dictionary<int, bool>();
|
||||||
|
|
||||||
private bool isDirty = false;
|
private bool isDirty = false;
|
||||||
private double lastUpdateTime;
|
private double lastUpdateTime;
|
||||||
@ -233,6 +234,7 @@ public class RetargetingControlWindow : EditorWindow
|
|||||||
if (!rightHandFoldouts.ContainsKey(instanceID)) rightHandFoldouts[instanceID] = false;
|
if (!rightHandFoldouts.ContainsKey(instanceID)) rightHandFoldouts[instanceID] = false;
|
||||||
if (!headFoldouts.ContainsKey(instanceID)) headFoldouts[instanceID] = false;
|
if (!headFoldouts.ContainsKey(instanceID)) headFoldouts[instanceID] = false;
|
||||||
if (!propControlFoldouts.ContainsKey(instanceID)) propControlFoldouts[instanceID] = false;
|
if (!propControlFoldouts.ContainsKey(instanceID)) propControlFoldouts[instanceID] = false;
|
||||||
|
if (!headRotationFoldouts.ContainsKey(instanceID)) headRotationFoldouts[instanceID] = false;
|
||||||
|
|
||||||
SerializedObject serializedObject = new SerializedObject(script);
|
SerializedObject serializedObject = new SerializedObject(script);
|
||||||
|
|
||||||
@ -387,6 +389,15 @@ public class RetargetingControlWindow : EditorWindow
|
|||||||
EditorGUI.indentLevel--;
|
EditorGUI.indentLevel--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 머리 회전 오프셋 설정 섹션
|
||||||
|
headRotationFoldouts[instanceID] = EditorGUILayout.Foldout(headRotationFoldouts[instanceID], "머리 회전 오프셋", true);
|
||||||
|
if (headRotationFoldouts[instanceID])
|
||||||
|
{
|
||||||
|
EditorGUI.indentLevel++;
|
||||||
|
DrawHeadRotationSettings(serializedObject);
|
||||||
|
EditorGUI.indentLevel--;
|
||||||
|
}
|
||||||
|
|
||||||
// 프랍 컨트롤 설정
|
// 프랍 컨트롤 설정
|
||||||
propControlFoldouts[instanceID] = EditorGUILayout.Foldout(propControlFoldouts[instanceID], "프랍 설정", true);
|
propControlFoldouts[instanceID] = EditorGUILayout.Foldout(propControlFoldouts[instanceID], "프랍 설정", true);
|
||||||
if (propControlFoldouts[instanceID])
|
if (propControlFoldouts[instanceID])
|
||||||
@ -1114,6 +1125,39 @@ public class RetargetingControlWindow : EditorWindow
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 머리 회전 오프셋 UI 그리기 함수
|
||||||
|
private void DrawHeadRotationSettings(SerializedObject serializedObject)
|
||||||
|
{
|
||||||
|
EditorGUI.BeginChangeCheck();
|
||||||
|
|
||||||
|
var headRotationXProp = serializedObject.FindProperty("headRotationOffsetX");
|
||||||
|
var headRotationYProp = serializedObject.FindProperty("headRotationOffsetY");
|
||||||
|
var headRotationZProp = serializedObject.FindProperty("headRotationOffsetZ");
|
||||||
|
|
||||||
|
EditorGUILayout.Slider(headRotationXProp, -180f, 180f,
|
||||||
|
new GUIContent("X (Roll) - 좌우 기울기", "머리를 좌우로 기울입니다"));
|
||||||
|
EditorGUILayout.Slider(headRotationYProp, -180f, 180f,
|
||||||
|
new GUIContent("Y (Yaw) - 좌우 회전", "머리를 좌우로 회전합니다"));
|
||||||
|
EditorGUILayout.Slider(headRotationZProp, -180f, 180f,
|
||||||
|
new GUIContent("Z (Pitch) - 상하 회전", "머리를 상하로 회전합니다"));
|
||||||
|
|
||||||
|
// 초기화 버튼
|
||||||
|
EditorGUILayout.Space(5);
|
||||||
|
if (GUILayout.Button("회전 초기화", GUILayout.Height(25)))
|
||||||
|
{
|
||||||
|
headRotationXProp.floatValue = 0f;
|
||||||
|
headRotationYProp.floatValue = 0f;
|
||||||
|
headRotationZProp.floatValue = 0f;
|
||||||
|
serializedObject.ApplyModifiedProperties();
|
||||||
|
EditorUtility.SetDirty(serializedObject.targetObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EditorGUI.EndChangeCheck())
|
||||||
|
{
|
||||||
|
serializedObject.ApplyModifiedProperties();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 창이 포커스를 얻거나 잃을 때 리페인트
|
// 창이 포커스를 얻거나 잃을 때 리페인트
|
||||||
private void OnFocus()
|
private void OnFocus()
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user