- BackgroundSceneLoaderWindow: OnGUI → CreateGUI (Toolbar + ToolbarSearchField) - PropBrowserWindow: OnGUI → CreateGUI (Toolbar + ToolbarSearchField) - StreamingleCommon.uss: 브라우저 공통 스타일 추가 (그리드/리스트/뷰토글/액션바/상태바) - excludeFromWeb 상태 새로고침 시 보존 수정 - 삭제된 배경 리소스 정리 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
116 lines
4.2 KiB
C#
116 lines
4.2 KiB
C#
using UnityEngine;
|
|
using UnityEditor;
|
|
using UnityEngine.UIElements;
|
|
using UnityEditor.UIElements;
|
|
using System.IO;
|
|
using UniHumanoid;
|
|
|
|
public class HumanPoseClipCreator : EditorWindow
|
|
{
|
|
private const string CommonUssPath = "Assets/Scripts/Streamingle/StreamingleControl/Editor/UXML/StreamingleCommon.uss";
|
|
|
|
private ObjectField animatorField;
|
|
private TextField nameField;
|
|
private TextField pathField;
|
|
|
|
[MenuItem("Tools/Animation Tools/포즈 클립 생성기")]
|
|
public static void ShowWindow()
|
|
{
|
|
GetWindow<HumanPoseClipCreator>("포즈 클립 생성기");
|
|
}
|
|
|
|
public void CreateGUI()
|
|
{
|
|
var root = rootVisualElement;
|
|
root.AddToClassList("tool-root");
|
|
|
|
var commonUss = AssetDatabase.LoadAssetAtPath<StyleSheet>(CommonUssPath);
|
|
if (commonUss != null) root.styleSheets.Add(commonUss);
|
|
|
|
root.Add(new Label("휴먼 포즈 클립 생성") { name = "title" });
|
|
root.Q<Label>("title").AddToClassList("tool-title");
|
|
|
|
animatorField = new ObjectField("타겟 Animator") { objectType = typeof(Animator), allowSceneObjects = true };
|
|
root.Add(animatorField);
|
|
|
|
nameField = new TextField("에셋 이름") { value = "NewPoseClip" };
|
|
root.Add(nameField);
|
|
|
|
pathField = new TextField("저장 경로") { value = "Assets/Resources" };
|
|
root.Add(pathField);
|
|
|
|
var browseBtn = new Button(() =>
|
|
{
|
|
string path = EditorUtility.SaveFolderPanel("저장 폴더 선택", "Assets", "");
|
|
if (!string.IsNullOrEmpty(path))
|
|
{
|
|
if (path.StartsWith(Application.dataPath))
|
|
pathField.value = "Assets" + path.Substring(Application.dataPath.Length);
|
|
else
|
|
EditorUtility.DisplayDialog("오류", "Assets 폴더 내부를 선택해주세요.", "확인");
|
|
}
|
|
}) { text = "폴더 선택" };
|
|
root.Add(browseBtn);
|
|
|
|
var createBtn = new Button(CreatePoseClip) { text = "포즈 클립 생성" };
|
|
createBtn.style.height = 30;
|
|
createBtn.style.marginTop = 12;
|
|
createBtn.AddToClassList("btn-primary");
|
|
root.Add(createBtn);
|
|
|
|
root.schedule.Execute(() => createBtn.SetEnabled(animatorField.value != null)).Every(200);
|
|
}
|
|
|
|
private void CreatePoseClip()
|
|
{
|
|
var selectedAnimator = animatorField.value as Animator;
|
|
if (selectedAnimator == null)
|
|
{
|
|
EditorUtility.DisplayDialog("오류", "Animator를 선택해주세요.", "확인");
|
|
return;
|
|
}
|
|
|
|
string savePath = pathField.value;
|
|
if (!savePath.StartsWith("Assets/"))
|
|
{
|
|
EditorUtility.DisplayDialog("오류", "저장 경로는 'Assets/'로 시작해야 합니다.", "확인");
|
|
return;
|
|
}
|
|
|
|
var avatar = selectedAnimator.avatar;
|
|
if (avatar == null || !avatar.isHuman)
|
|
{
|
|
EditorUtility.DisplayDialog("오류", "Humanoid Avatar가 필요합니다.", "확인");
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
var handler = new HumanPoseHandler(avatar, selectedAnimator.transform);
|
|
HumanPose pose = new HumanPose();
|
|
handler.GetHumanPose(ref pose);
|
|
|
|
HumanPoseClip poseClip = ScriptableObject.CreateInstance<HumanPoseClip>();
|
|
poseClip.ApplyPose(ref pose);
|
|
|
|
string assetName = nameField.value;
|
|
string fullPath = Path.Combine(savePath, $"{assetName}.pose.asset");
|
|
string directory = Path.GetDirectoryName(fullPath);
|
|
if (!Directory.Exists(directory))
|
|
Directory.CreateDirectory(directory);
|
|
|
|
AssetDatabase.CreateAsset(poseClip, fullPath);
|
|
AssetDatabase.SaveAssets();
|
|
AssetDatabase.Refresh();
|
|
|
|
Debug.Log($"포즈 클립이 생성되었습니다: {fullPath}");
|
|
EditorUtility.DisplayDialog("성공", $"포즈 클립이 생성되었습니다:\n{fullPath}", "확인");
|
|
}
|
|
catch (System.Exception e)
|
|
{
|
|
Debug.LogError($"포즈 클립 생성 오류: {e.Message}");
|
|
EditorUtility.DisplayDialog("오류", $"포즈 클립 생성 실패: {e.Message}", "확인");
|
|
}
|
|
}
|
|
}
|