Streamingle_URP/Assets/External/StreamingleFacial/Editor/BlendShapeIntensityOverrideDrawer.cs

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