137 lines
4.6 KiB
C#
137 lines
4.6 KiB
C#
using UnityEngine;
|
|
using UnityEditor;
|
|
using System.Collections.Generic;
|
|
|
|
[CustomPropertyDrawer(typeof(StreamingleFacialReceiver.BlendShapeIntensityOverride))]
|
|
public class BlendShapeIntensityOverrideDrawer : PropertyDrawer
|
|
{
|
|
// 카테고리별로 구분된 ARKit BlendShape 이름 (Popup에 구분선 역할)
|
|
private static readonly string[] ARKitBlendShapeNames = new string[]
|
|
{
|
|
// Eye (0-13)
|
|
"EyeBlinkLeft", "EyeBlinkRight",
|
|
"EyeLookDownLeft", "EyeLookDownRight",
|
|
"EyeLookInLeft", "EyeLookInRight",
|
|
"EyeLookOutLeft", "EyeLookOutRight",
|
|
"EyeLookUpLeft", "EyeLookUpRight",
|
|
"EyeSquintLeft", "EyeSquintRight",
|
|
"EyeWideLeft", "EyeWideRight",
|
|
// Jaw (14-17)
|
|
"JawForward", "JawLeft", "JawRight", "JawOpen",
|
|
// Mouth (18-37)
|
|
"MouthClose", "MouthFunnel", "MouthPucker",
|
|
"MouthLeft", "MouthRight",
|
|
"MouthSmileLeft", "MouthSmileRight",
|
|
"MouthFrownLeft", "MouthFrownRight",
|
|
"MouthDimpleLeft", "MouthDimpleRight",
|
|
"MouthStretchLeft", "MouthStretchRight",
|
|
"MouthRollLower", "MouthRollUpper",
|
|
"MouthShrugLower", "MouthShrugUpper",
|
|
"MouthPressLeft", "MouthPressRight",
|
|
"MouthLowerDownLeft", "MouthLowerDownRight",
|
|
"MouthUpperUpLeft", "MouthUpperUpRight",
|
|
// Brow (38-42)
|
|
"BrowDownLeft", "BrowDownRight",
|
|
"BrowInnerUp",
|
|
"BrowOuterUpLeft", "BrowOuterUpRight",
|
|
// Cheek/Nose (43-47)
|
|
"CheekPuff", "CheekSquintLeft", "CheekSquintRight",
|
|
"NoseSneerLeft", "NoseSneerRight",
|
|
// Tongue (48)
|
|
"TongueOut",
|
|
};
|
|
|
|
// 카테고리 구분 표시용
|
|
private static readonly string[] DisplayNames;
|
|
private static readonly Dictionary<string, int> nameToIndex;
|
|
|
|
static BlendShapeIntensityOverrideDrawer()
|
|
{
|
|
nameToIndex = new Dictionary<string, int>(System.StringComparer.OrdinalIgnoreCase);
|
|
|
|
// 카테고리 프리픽스 부여
|
|
DisplayNames = new string[ARKitBlendShapeNames.Length];
|
|
for (int i = 0; i < ARKitBlendShapeNames.Length; i++)
|
|
{
|
|
string name = ARKitBlendShapeNames[i];
|
|
string category;
|
|
|
|
if (name.StartsWith("Eye")) category = "Eye";
|
|
else if (name.StartsWith("Jaw")) category = "Jaw";
|
|
else if (name.StartsWith("Mouth")) category = "Mouth";
|
|
else if (name.StartsWith("Brow")) category = "Brow";
|
|
else if (name.StartsWith("Cheek") || name.StartsWith("Nose")) category = "Cheek-Nose";
|
|
else if (name.StartsWith("Tongue")) category = "Tongue";
|
|
else category = "";
|
|
|
|
DisplayNames[i] = category + "/" + name;
|
|
nameToIndex[name] = i;
|
|
}
|
|
}
|
|
|
|
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
|
|
{
|
|
return EditorGUIUtility.singleLineHeight + 2f;
|
|
}
|
|
|
|
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
|
{
|
|
EditorGUI.BeginProperty(position, label, property);
|
|
|
|
position.y += 1f;
|
|
position.height -= 2f;
|
|
|
|
var nameProp = property.FindPropertyRelative("blendShapeName");
|
|
var intensityProp = property.FindPropertyRelative("intensity");
|
|
|
|
// 새로 추가된 항목의 기본값 보정
|
|
if (intensityProp.floatValue == 0f && string.IsNullOrEmpty(nameProp.stringValue))
|
|
{
|
|
intensityProp.floatValue = 1.0f;
|
|
}
|
|
|
|
// 레이아웃: [드롭다운 55%] [슬라이더 35%] [값 라벨 10%]
|
|
float dropW = position.width * 0.55f;
|
|
float sliderW = position.width * 0.35f;
|
|
float valW = position.width * 0.10f - 6f;
|
|
|
|
Rect dropRect = new Rect(position.x, position.y, dropW - 2f, position.height);
|
|
Rect sliderRect = new Rect(position.x + dropW + 2f, position.y, sliderW - 2f, position.height);
|
|
Rect valRect = new Rect(position.x + dropW + sliderW + 4f, position.y, valW, position.height);
|
|
|
|
// 현재 인덱스
|
|
int currentIndex = 0;
|
|
if (!string.IsNullOrEmpty(nameProp.stringValue) && nameToIndex.TryGetValue(nameProp.stringValue, out int idx))
|
|
{
|
|
currentIndex = idx;
|
|
}
|
|
|
|
// 드롭다운 (카테고리 구분)
|
|
int newIndex = EditorGUI.Popup(dropRect, currentIndex, DisplayNames);
|
|
if (newIndex != currentIndex || string.IsNullOrEmpty(nameProp.stringValue))
|
|
{
|
|
nameProp.stringValue = ARKitBlendShapeNames[newIndex];
|
|
}
|
|
|
|
// 슬라이더
|
|
intensityProp.floatValue = GUI.HorizontalSlider(sliderRect, intensityProp.floatValue, 0f, 3f);
|
|
|
|
// 값 표시 (색상으로 강약 표현)
|
|
float val = intensityProp.floatValue;
|
|
Color valColor;
|
|
if (val < 0.5f) valColor = new Color(1f, 0.4f, 0.4f); // 약함 = 빨강
|
|
else if (val > 1.5f) valColor = new Color(0.4f, 0.8f, 1f); // 강함 = 파랑
|
|
else valColor = new Color(0.7f, 0.7f, 0.7f); // 보통 = 회색
|
|
|
|
var valStyle = new GUIStyle(EditorStyles.miniLabel)
|
|
{
|
|
alignment = TextAnchor.MiddleRight,
|
|
fontStyle = FontStyle.Bold,
|
|
};
|
|
valStyle.normal.textColor = valColor;
|
|
EditorGUI.LabelField(valRect, $"x{val:F1}", valStyle);
|
|
|
|
EditorGUI.EndProperty();
|
|
}
|
|
}
|