Unity) EditorWindow(DotProduct)
이번에는 Unity에서 EditorWindow를 이용해보려 한다.
기존에 마야에서 PySide2를 이용해 기본적인 툴을 만들었듯이, 유니티에도 기본적인 툴을 제작할 수 있는 환경이 있었다.
이 툴을 통해 에디터에서 직접 벡터의 내적을 계산하고, 핸들을 사용해 위치를 조정해 보자.

주요기능
- p0, p1, c 세 점을 조작가능
- 벡터간 내적을 실시간으로 계산한다.
Handles.FreeMoveHandle()을 사용해 에디터에서 점 이동가능Handles.Label()을 활용해 내적 값을 에디터에 출력
ShowWindow
[MenuItem("Tools/Dot Product")]
public static void ShowWindow()
{
DotProductEditor window = (DotProductEditor)GetWindow
(typeof(DotProductEditor), true, "Dot Product");
window.Show();
}
- Unity 에디터의 메뉴바에 버튼을 추가해,
DotProductEditor창을 연다. GetWindow를 통해 윈도우를 생성하고,Show로 호출한다.

OneEnable
private void OnEnable()
{
if (pt0 == Vector3.zero && pt1 == Vector3.zero)
{
pt0 = new Vector3(0f, 1f, 0f);
pt1 = new Vector3(.5f, .5f, 0f);
ptC = Vector3.zero;
}
obj = new SerializedObject(this);
propP0 = obj.FindProperty("pt0");
propP1 = obj.FindProperty("pt1");
propC = obj.FindProperty("ptC");
guiStyle.fontSize = 25;
guiStyle.fontStyle = FontStyle.Bold;
guiStyle.normal.textColor = Color.white;
SceneView.duringSceneGui += SceneGUI;
}
- 에디터 창이 활성화될 때 초기화
- 기본 벡터 좌표 설정
SerializedObject를 통해 Unity Inspector에서 프로퍼티 조작 가능SceneView.duringSceneGui += SceneGUI;를 통해 SceneView에서 GUI를 그릴 수 있도록 이벤트를 등록
OnDisable
private void OnDisable()
{
SceneView.duringSceneGui -= SceneGUI;
}
- 에디터 창이 닫힐 때 이벤트 해제
- SceneView에서
SceneGUI이벤트를 제거
OnGUI
private void OnGUI()
{
obj.Update();
DrawBlockGUI("p0", propP0);
DrawBlockGUI("p1", propP1);
DrawBlockGUI("c", propC);
if (obj.ApplyModifiedProperties())
{
SceneView.RepaintAll();
}
}
- 사용자 UI 그리기
- p0, p1, p2의 값을 에디터에서 수정 할 수 있도록 UI 생성
SceneView.RepaintAll()로 변경사항이 즉시 반영되도록 지정
DrawBlockGUI
void DrawBlockGUI(string lab, SerializedProperty prop)
{
EditorGUILayout.BeginHorizontal("box");
EditorGUILayout.LabelField(lab, GUILayout.Width(50));
EditorGUILayout.PropertyField(prop, GUIContent.none);
EditorGUILayout.EndHorizontal();
}
- 입력 필드를 생성한다.
- p0, p1, p2에 대한 GUI 블록을 생성
EditorGUILayout.LabelField()를 사용하여 필드 라벨을 추가
SceneGUI
private void SceneGUI(SceneView view)
{
Handles.color = Color.red;
Vector3 p0 = SetMovePoint(pt0);
Handles.color = Color.green;
Vector3 p1 = SetMovePoint(pt1);
Handles.color = Color.white;
Vector3 c = SetMovePoint(ptC);
if (pt0 != p0 || pt1 != p1 || ptC != c)
{
pt0 = p0;
pt1 = p1;
ptC = c;
Repaint();
}
DrawLabel(p0, p1, c);
}
- SceneView에서 점을 이동하며 내적 계산
SetMovePoint()를 사용하여 SceneView에서 점을 이동 가능하도록 설정- 사용자가 이동한 경우
Repaint()를 호출하여 즉시 업데이트
SetMovePoint
Vector3 SetMovePoint(Vector3 pos)
{
float size = HandleUtility.GetHandleSize(Vector3.zero) * 0.15f;
return Handles.FreeMoveHandle(pos, size, Vector3.zero, Handles.SphereHandleCap);
}
- SceneView에서 점을 이동가능하도록 설정
Handles.FreeMoveHandle()을 사용하여 마우스로 이동 가능한 점을 SceneView에 표시
DotProduct
float DotProduct(Vector3 p0, Vector3 p1, Vector3 c)
{
Vector3 a = (p0 - c).normalized;
Vector3 b = (p1 - c).normalized;
return (a.x * b.x) + (a.y * b.y) + (a.z * b.z);
}
- 두 벡터를 정규화(normalize)한 후 내적 연산 수행
- 결과 값은 두 벡터 사이의 코사인 값을 나타낸다. (1: 0도, 0: 90도, -1: 180도)
DrawLabel
void DrawLabel(Vector3 p0, Vector3 p1, Vector3 c)
{
Handles.Label(c, DotProduct(p0, p1, c).ToString("F2"), guiStyle);
Handles.color = Color.black;
Handles.DrawAAPolyLine(3f, p0, c);
Handles.DrawAAPolyLine(3f, p1, c);
}
- 내적 결과를 SceneView에 표시
Handles.Label을 사용하여 내적 결과를 SceneView에 텍스트로 출력-
Handles.DrawAAPolyLine을 사용하여 점과 점을 선으로 연결 "F2"이 숫자를 통해 보여질 소수점 자리를 지정 가능
마무리
Unity의 EditorWindow를 활용하면 Maya에서 PySide2로 툴을 제작했던 것처럼, 내가 원하는 기능을 직접 추가하여 커스텀 유니티 툴을 제작할 수 있었다.
이번에서는 벡터 내적(Dot Product) 계산을 시각적으로 조작할 수 있는 툴을 만들어봤다.
이 툴을 통해 SceneView에서 핸들을 조작하여 벡터를 실시간으로 이동시키고, 내적 값을 즉시 확인하는 인터랙티브한 편집 환경까지 되었다.
앞으로도 에디터를 확장하며 제작 환경을 커스터마이징해 보다 직관적이게 구축하고, 반복적인 작업을 자동화하거나, 더 편리하게 데이터를 조작할 수 있도록 지원할 수 있도록 만져봐야겠다.
댓글남기기