247 lines
8.1 KiB
C#
247 lines
8.1 KiB
C#
using UnityEngine;
|
|
using UnityEditor;
|
|
using System.IO;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
|
|
public class StreamingleAvatarExporter : EditorWindow
|
|
{
|
|
private GameObject targetAvatar;
|
|
private Vector2 scrollPosition;
|
|
private Dictionary<SkinnedMeshRenderer, string> meshTags = new Dictionary<SkinnedMeshRenderer, string>();
|
|
|
|
private string[] tagOptions = new string[] { "None", "Clothes", "Hair", "Face", "Body", "Other" };
|
|
private Color[] tagColors = new Color[] {
|
|
Color.gray, // None
|
|
Color.blue, // Clothes
|
|
Color.yellow, // Hair
|
|
Color.green, // Face
|
|
Color.red, // Body
|
|
Color.magenta // Other
|
|
};
|
|
|
|
[MenuItem("Tools/Streamingle/Avatar Exporter")]
|
|
public static void ShowWindow()
|
|
{
|
|
GetWindow<StreamingleAvatarExporter>("Streamingle Exporter");
|
|
}
|
|
|
|
private void OnGUI()
|
|
{
|
|
GUILayout.Label("Streamingle Avatar Exporter", EditorStyles.boldLabel);
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
GameObject newTarget = (GameObject)EditorGUILayout.ObjectField("Avatar Object", targetAvatar, typeof(GameObject), true);
|
|
|
|
if (newTarget != targetAvatar)
|
|
{
|
|
targetAvatar = newTarget;
|
|
if (targetAvatar != null)
|
|
{
|
|
InitializeMeshList();
|
|
}
|
|
else
|
|
{
|
|
meshTags.Clear();
|
|
}
|
|
}
|
|
|
|
if (targetAvatar != null)
|
|
{
|
|
GUILayout.Space(10);
|
|
EditorGUILayout.LabelField("메쉬 태그 설정", EditorStyles.boldLabel);
|
|
|
|
scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
|
|
|
|
foreach (var pair in meshTags.ToList())
|
|
{
|
|
SkinnedMeshRenderer renderer = pair.Key;
|
|
if (renderer == null) continue;
|
|
|
|
EditorGUILayout.BeginVertical("box");
|
|
|
|
EditorGUILayout.BeginHorizontal();
|
|
EditorGUILayout.LabelField($"메쉬: {renderer.name}", EditorStyles.boldLabel);
|
|
EditorGUILayout.EndHorizontal();
|
|
|
|
EditorGUILayout.BeginHorizontal();
|
|
EditorGUILayout.LabelField($"버텍스: {renderer.sharedMesh.vertexCount}", GUILayout.Width(120));
|
|
EditorGUILayout.LabelField($"블렌드쉐입: {renderer.sharedMesh.blendShapeCount}", GUILayout.Width(120));
|
|
EditorGUILayout.EndHorizontal();
|
|
|
|
int currentIndex = System.Array.IndexOf(tagOptions, pair.Value);
|
|
int newIndex = EditorGUILayout.Popup("태그", currentIndex, tagOptions);
|
|
|
|
if (newIndex != currentIndex)
|
|
{
|
|
meshTags[renderer] = tagOptions[newIndex];
|
|
}
|
|
|
|
EditorGUI.DrawRect(EditorGUILayout.GetControlRect(false, 3), tagColors[newIndex]);
|
|
|
|
EditorGUILayout.EndVertical();
|
|
GUILayout.Space(5);
|
|
}
|
|
|
|
EditorGUILayout.EndScrollView();
|
|
|
|
if (GUILayout.Button("Export Avatar"))
|
|
{
|
|
ExportAvatar();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void InitializeMeshList()
|
|
{
|
|
meshTags.Clear();
|
|
var renderers = targetAvatar.GetComponentsInChildren<SkinnedMeshRenderer>(true);
|
|
foreach (var renderer in renderers)
|
|
{
|
|
meshTags[renderer] = "None";
|
|
}
|
|
}
|
|
|
|
private void ExportAvatar()
|
|
{
|
|
if (targetAvatar == null)
|
|
{
|
|
EditorUtility.DisplayDialog("Error", "Please select an avatar first!", "OK");
|
|
return;
|
|
}
|
|
|
|
string fullpath = EditorUtility.SaveFilePanel(
|
|
"Export Streamingle Avatar",
|
|
".",
|
|
targetAvatar.name,
|
|
"streamingle"
|
|
);
|
|
|
|
if (string.IsNullOrEmpty(fullpath))
|
|
return;
|
|
|
|
string filename = Path.GetFileName(fullpath);
|
|
string prefabPath = "Assets/StreamingleAvatarTemp.prefab";
|
|
|
|
try
|
|
{
|
|
// 컴파일 에러 체크
|
|
if (!string.IsNullOrEmpty(AssetDatabase.GetAssetPath(targetAvatar)))
|
|
{
|
|
AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(targetAvatar), ImportAssetOptions.ForceUpdate);
|
|
}
|
|
|
|
// 프리팹 생성 전 임시 폴더 정리
|
|
string tempPath = Path.Combine(Application.dataPath, "../Temp/AssetBundles");
|
|
if (Directory.Exists(tempPath))
|
|
{
|
|
Directory.Delete(tempPath, true);
|
|
}
|
|
Directory.CreateDirectory(tempPath);
|
|
|
|
// 프리팹 생성
|
|
bool succeededPack = false;
|
|
GameObject prefabAsset = PrefabUtility.SaveAsPrefabAsset(targetAvatar, prefabPath, out succeededPack);
|
|
|
|
if (!succeededPack || prefabAsset == null)
|
|
{
|
|
throw new System.Exception("프리팹 생성 실패");
|
|
}
|
|
|
|
// AssetDatabase 새로고침 및 대기
|
|
AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
|
|
System.Threading.Thread.Sleep(1000); // 새로고침 대기
|
|
|
|
// AssetBundle 설정
|
|
AssetBundleBuild bundleBuild = new AssetBundleBuild
|
|
{
|
|
assetBundleName = filename,
|
|
assetNames = new string[] { prefabPath }
|
|
};
|
|
|
|
// 빌드 옵션 설정
|
|
BuildAssetBundleOptions options = BuildAssetBundleOptions.None;
|
|
|
|
// AssetBundle 빌드
|
|
BuildPipeline.BuildAssetBundles(
|
|
tempPath,
|
|
new AssetBundleBuild[] { bundleBuild },
|
|
options,
|
|
EditorUserBuildSettings.activeBuildTarget
|
|
);
|
|
|
|
// 결과 파일 이동
|
|
string bundlePath = Path.Combine(tempPath, filename);
|
|
if (File.Exists(bundlePath))
|
|
{
|
|
if (File.Exists(fullpath))
|
|
File.Delete(fullpath);
|
|
|
|
File.Copy(bundlePath, fullpath, true);
|
|
}
|
|
else
|
|
{
|
|
throw new System.Exception($"AssetBundle 파일을 찾을 수 없습니다. 경로: {bundlePath}");
|
|
}
|
|
|
|
EditorUtility.DisplayDialog("Export", "아바타 출력 완료!", "OK");
|
|
}
|
|
catch (System.Exception e)
|
|
{
|
|
Debug.LogError($"Export failed: {e.Message}");
|
|
EditorUtility.DisplayDialog("Error", "아바타 출력 실패! 콘솔을 확인해주세요.", "OK");
|
|
}
|
|
finally
|
|
{
|
|
AssetDatabase.DeleteAsset(prefabPath);
|
|
if (File.Exists(prefabPath))
|
|
File.Delete(prefabPath);
|
|
}
|
|
}
|
|
}
|
|
|
|
// 태그 설정을 위한 별도의 윈도우
|
|
public class TagSetupWindow : EditorWindow
|
|
{
|
|
private GameObject targetAvatar;
|
|
private Vector2 scrollPosition;
|
|
private string[] availableTags = new string[] { "Clothes", "Hair", "Face", "Body", "Other" };
|
|
|
|
public void Initialize(GameObject avatar)
|
|
{
|
|
targetAvatar = avatar;
|
|
titleContent = new GUIContent("태그 설정");
|
|
}
|
|
|
|
private void OnGUI()
|
|
{
|
|
if (targetAvatar == null) return;
|
|
|
|
GUILayout.Label("아바타 파츠 태그 설정", EditorStyles.boldLabel);
|
|
|
|
scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
|
|
|
|
Transform[] children = targetAvatar.GetComponentsInChildren<Transform>(true);
|
|
foreach (Transform child in children)
|
|
{
|
|
if (child == targetAvatar.transform) continue;
|
|
|
|
EditorGUILayout.BeginHorizontal();
|
|
EditorGUILayout.LabelField(child.name);
|
|
|
|
string currentTag = child.tag;
|
|
int tagIndex = System.Array.IndexOf(availableTags, currentTag);
|
|
int newTagIndex = EditorGUILayout.Popup(tagIndex, availableTags);
|
|
|
|
if (newTagIndex != tagIndex)
|
|
{
|
|
child.tag = availableTags[newTagIndex];
|
|
EditorUtility.SetDirty(child.gameObject);
|
|
}
|
|
|
|
EditorGUILayout.EndHorizontal();
|
|
}
|
|
|
|
EditorGUILayout.EndScrollView();
|
|
}
|
|
} |