264 lines
7.9 KiB
C#
264 lines
7.9 KiB
C#
using UnityEngine;
|
|
using UnityEditor;
|
|
[CustomEditor(typeof(StreamingleFacialReceiver))]
|
|
public class StreamingleFacialReceiverEditor : Editor
|
|
{
|
|
private SerializedProperty mirrorMode;
|
|
private SerializedProperty faceMeshRenderers;
|
|
private SerializedProperty availablePorts;
|
|
|
|
private SerializedProperty enableFiltering;
|
|
private SerializedProperty smoothingFactor;
|
|
private SerializedProperty maxBlendShapeDelta;
|
|
private SerializedProperty maxRotationDelta;
|
|
private SerializedProperty fastBlendShapeMultiplier;
|
|
private SerializedProperty spikeToleranceFrames;
|
|
private SerializedProperty globalIntensity;
|
|
private SerializedProperty blendShapeIntensityOverrides;
|
|
|
|
private bool showConnection = false;
|
|
private bool showFiltering = false;
|
|
private bool showIntensity = false;
|
|
|
|
private static readonly Color HeaderColor = new Color(0.18f, 0.18f, 0.18f, 1f);
|
|
private static readonly Color ActivePortColor = new Color(0.2f, 0.8f, 0.4f, 1f);
|
|
private static readonly Color InactivePortColor = new Color(0.35f, 0.35f, 0.35f, 1f);
|
|
private static readonly Color AccentColor = new Color(0.4f, 0.7f, 1f, 1f);
|
|
|
|
private GUIStyle _headerStyle;
|
|
private GUIStyle _sectionBoxStyle;
|
|
private GUIStyle _portButtonStyle;
|
|
private GUIStyle _portButtonActiveStyle;
|
|
private GUIStyle _statusLabelStyle;
|
|
|
|
void OnEnable()
|
|
{
|
|
mirrorMode = serializedObject.FindProperty("mirrorMode");
|
|
faceMeshRenderers = serializedObject.FindProperty("faceMeshRenderers");
|
|
availablePorts = serializedObject.FindProperty("availablePorts");
|
|
enableFiltering = serializedObject.FindProperty("enableFiltering");
|
|
smoothingFactor = serializedObject.FindProperty("smoothingFactor");
|
|
maxBlendShapeDelta = serializedObject.FindProperty("maxBlendShapeDelta");
|
|
maxRotationDelta = serializedObject.FindProperty("maxRotationDelta");
|
|
fastBlendShapeMultiplier = serializedObject.FindProperty("fastBlendShapeMultiplier");
|
|
spikeToleranceFrames = serializedObject.FindProperty("spikeToleranceFrames");
|
|
globalIntensity = serializedObject.FindProperty("globalIntensity");
|
|
blendShapeIntensityOverrides = serializedObject.FindProperty("blendShapeIntensityOverrides");
|
|
}
|
|
|
|
void InitStyles()
|
|
{
|
|
if (_headerStyle != null) return;
|
|
|
|
_headerStyle = new GUIStyle(EditorStyles.boldLabel)
|
|
{
|
|
fontSize = 13,
|
|
alignment = TextAnchor.MiddleLeft,
|
|
padding = new RectOffset(8, 0, 4, 4),
|
|
};
|
|
_headerStyle.normal.textColor = AccentColor;
|
|
|
|
_sectionBoxStyle = new GUIStyle("HelpBox")
|
|
{
|
|
padding = new RectOffset(10, 10, 8, 8),
|
|
margin = new RectOffset(0, 0, 4, 8),
|
|
};
|
|
|
|
_portButtonStyle = new GUIStyle(GUI.skin.button)
|
|
{
|
|
fontSize = 12,
|
|
fontStyle = FontStyle.Bold,
|
|
fixedHeight = 36,
|
|
alignment = TextAnchor.MiddleCenter,
|
|
};
|
|
|
|
_portButtonActiveStyle = new GUIStyle(_portButtonStyle);
|
|
_portButtonActiveStyle.normal.textColor = Color.white;
|
|
|
|
_statusLabelStyle = new GUIStyle(EditorStyles.miniLabel)
|
|
{
|
|
alignment = TextAnchor.MiddleCenter,
|
|
fontSize = 10,
|
|
};
|
|
}
|
|
|
|
public override void OnInspectorGUI()
|
|
{
|
|
serializedObject.Update();
|
|
InitStyles();
|
|
|
|
var mocap = (StreamingleFacialReceiver)target;
|
|
|
|
// 타이틀
|
|
EditorGUILayout.Space(4);
|
|
DrawTitle();
|
|
EditorGUILayout.Space(4);
|
|
|
|
// 기본 설정
|
|
DrawBasicSettings();
|
|
|
|
// 포트 핫스왑
|
|
DrawPortSection(mocap);
|
|
|
|
// 필터링
|
|
DrawFilteringSection();
|
|
|
|
// 페이셜 강도
|
|
DrawIntensitySection();
|
|
|
|
serializedObject.ApplyModifiedProperties();
|
|
}
|
|
|
|
void DrawTitle()
|
|
{
|
|
var rect = EditorGUILayout.GetControlRect(false, 32);
|
|
EditorGUI.DrawRect(rect, HeaderColor);
|
|
|
|
var titleStyle = new GUIStyle(EditorStyles.boldLabel)
|
|
{
|
|
fontSize = 15,
|
|
alignment = TextAnchor.MiddleLeft,
|
|
};
|
|
titleStyle.normal.textColor = Color.white;
|
|
|
|
EditorGUI.LabelField(rect, " Streamingle Facial Receiver", titleStyle);
|
|
|
|
// 상태 표시
|
|
if (Application.isPlaying)
|
|
{
|
|
var statusRect = new Rect(rect.xMax - 80, rect.y, 75, rect.height);
|
|
var dotRect = new Rect(statusRect.x - 12, rect.y + rect.height / 2 - 4, 8, 8);
|
|
EditorGUI.DrawRect(dotRect, ActivePortColor);
|
|
EditorGUI.LabelField(statusRect, "LIVE", _statusLabelStyle);
|
|
}
|
|
}
|
|
|
|
void DrawBasicSettings()
|
|
{
|
|
EditorGUILayout.BeginVertical(_sectionBoxStyle);
|
|
|
|
EditorGUILayout.PropertyField(faceMeshRenderers, new GUIContent("Face Mesh Renderers"));
|
|
EditorGUILayout.Space(2);
|
|
EditorGUILayout.PropertyField(mirrorMode, new GUIContent("Mirror Mode (L/R Flip)"));
|
|
|
|
EditorGUILayout.EndVertical();
|
|
}
|
|
|
|
void DrawPortSection(StreamingleFacialReceiver mocap)
|
|
{
|
|
showConnection = DrawSectionHeader("Port Hot-Swap", showConnection);
|
|
if (!showConnection) return;
|
|
|
|
EditorGUILayout.BeginVertical(_sectionBoxStyle);
|
|
|
|
// 현재 포트 표시
|
|
EditorGUILayout.BeginHorizontal();
|
|
EditorGUILayout.LabelField("Active Port", EditorStyles.miniLabel, GUILayout.Width(70));
|
|
var portLabel = new GUIStyle(EditorStyles.boldLabel);
|
|
portLabel.normal.textColor = ActivePortColor;
|
|
EditorGUILayout.LabelField(mocap.LOCAL_PORT.ToString(), portLabel);
|
|
EditorGUILayout.EndHorizontal();
|
|
|
|
EditorGUILayout.Space(4);
|
|
|
|
// 포트 버튼 그리드
|
|
if (mocap.availablePorts != null && mocap.availablePorts.Length > 0)
|
|
{
|
|
EditorGUILayout.BeginHorizontal();
|
|
for (int i = 0; i < mocap.availablePorts.Length; i++)
|
|
{
|
|
bool isActive = i == mocap.activePortIndex;
|
|
|
|
var prevBg = GUI.backgroundColor;
|
|
GUI.backgroundColor = isActive ? ActivePortColor : InactivePortColor;
|
|
|
|
var style = isActive ? _portButtonActiveStyle : _portButtonStyle;
|
|
string label = mocap.availablePorts[i].ToString();
|
|
|
|
if (GUILayout.Button(label, style))
|
|
{
|
|
if (Application.isPlaying)
|
|
{
|
|
mocap.SwitchToPort(i);
|
|
}
|
|
else
|
|
{
|
|
Undo.RecordObject(mocap, "Switch Port");
|
|
mocap.activePortIndex = i;
|
|
EditorUtility.SetDirty(mocap);
|
|
}
|
|
}
|
|
|
|
GUI.backgroundColor = prevBg;
|
|
}
|
|
EditorGUILayout.EndHorizontal();
|
|
}
|
|
|
|
EditorGUILayout.Space(2);
|
|
EditorGUILayout.PropertyField(availablePorts, new GUIContent("Port List"), true);
|
|
|
|
EditorGUILayout.EndVertical();
|
|
}
|
|
|
|
void DrawFilteringSection()
|
|
{
|
|
showFiltering = DrawSectionHeader("Data Filtering", showFiltering);
|
|
if (!showFiltering) return;
|
|
|
|
EditorGUILayout.BeginVertical(_sectionBoxStyle);
|
|
|
|
EditorGUILayout.PropertyField(enableFiltering, new GUIContent("Enable"));
|
|
|
|
if (enableFiltering.boolValue)
|
|
{
|
|
EditorGUI.indentLevel++;
|
|
EditorGUILayout.Space(2);
|
|
EditorGUILayout.PropertyField(smoothingFactor, new GUIContent("Smoothing"));
|
|
EditorGUILayout.PropertyField(maxBlendShapeDelta, new GUIContent("Max BlendShape Delta"));
|
|
EditorGUILayout.PropertyField(maxRotationDelta, new GUIContent("Max Rotation Delta"));
|
|
EditorGUILayout.PropertyField(fastBlendShapeMultiplier, new GUIContent("Fast BS Multiplier"));
|
|
EditorGUILayout.PropertyField(spikeToleranceFrames, new GUIContent("Spike Tolerance"));
|
|
EditorGUI.indentLevel--;
|
|
}
|
|
|
|
EditorGUILayout.EndVertical();
|
|
}
|
|
|
|
void DrawIntensitySection()
|
|
{
|
|
showIntensity = DrawSectionHeader("Facial Intensity", showIntensity);
|
|
if (!showIntensity) return;
|
|
|
|
EditorGUILayout.BeginVertical(_sectionBoxStyle);
|
|
|
|
// Global intensity - 크게 표시
|
|
EditorGUILayout.LabelField("Global", EditorStyles.miniLabel);
|
|
EditorGUILayout.PropertyField(globalIntensity, GUIContent.none);
|
|
|
|
EditorGUILayout.Space(6);
|
|
|
|
// 구분선
|
|
var lineRect = EditorGUILayout.GetControlRect(false, 1);
|
|
EditorGUI.DrawRect(lineRect, new Color(0.4f, 0.4f, 0.4f, 0.5f));
|
|
|
|
EditorGUILayout.Space(4);
|
|
EditorGUILayout.LabelField("Per-BlendShape Overrides", EditorStyles.miniLabel);
|
|
EditorGUILayout.PropertyField(blendShapeIntensityOverrides, GUIContent.none, true);
|
|
|
|
EditorGUILayout.EndVertical();
|
|
}
|
|
|
|
bool DrawSectionHeader(string title, bool expanded)
|
|
{
|
|
EditorGUILayout.Space(2);
|
|
var rect = EditorGUILayout.GetControlRect(false, 24);
|
|
EditorGUI.DrawRect(rect, HeaderColor);
|
|
|
|
// 폴드 화살표 + 타이틀
|
|
var foldRect = new Rect(rect.x + 4, rect.y, rect.width - 4, rect.height);
|
|
bool result = EditorGUI.Foldout(foldRect, expanded, " " + title, true, _headerStyle);
|
|
|
|
return result;
|
|
}
|
|
}
|