270 lines
9.8 KiB
C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;
using System.Linq;
using System;
namespace VRCDeveloperTool
{
public class ShapeKeyNameChanger : EditorWindow
{
private List<string> shapeKeyNames;
private SkinnedMeshRenderer renderer;
private string[] posNames;
private bool useDuplication = false;
private Vector2 scrollPos = Vector2.zero;
enum SelectType
{
Input,
Select
}
private SelectType selectTab = SelectType.Input;
public static GUIContent[] tabToggles
{
get
{
return System.Enum.GetNames(typeof(SelectType)).Select(x => new GUIContent(x)).ToArray();
}
}
[Serializable]
public class JsonData
{
public string[] ShapeKeyNames;
}
private string[] selectableNames;
private int[] selectedIndices;
private void OnEnable()
{
shapeKeyNames = null;
renderer = null;
posNames = null;
selectableNames = LoadJsonDataFromResourceFolder("ShapeKeyNameChanger/shapekeynames");
}
[MenuItem("VRCDeveloperTool/Mesh/ShapeKeyName Changer")]
private static void Create()
{
GetWindow<ShapeKeyNameChanger>("ShapeKeyName Changer");
}
private void OnGUI()
{
using (var check = new EditorGUI.ChangeCheckScope())
{
renderer = EditorGUILayout.ObjectField(
"Renderer",
renderer,
typeof(SkinnedMeshRenderer),
true
) as SkinnedMeshRenderer;
if (check.changed)
{
if (renderer == null)
{
shapeKeyNames = null;
posNames = null;
selectedIndices = null;
}
else
{
shapeKeyNames = GetBlendShapeListFromRenderer(renderer);
posNames = shapeKeyNames.ToArray();
selectedIndices = new int[shapeKeyNames.Count];
for (int i = 0; i < selectedIndices.Length; i++)
{
selectedIndices[i] = -1;
}
}
}
}
selectTab = (SelectType)GUILayout.Toolbar((int)selectTab, tabToggles, "LargeButton", GUI.ToolbarButtonSize.Fixed);
if (shapeKeyNames != null)
{
using (var pos = new GUILayout.ScrollViewScope(scrollPos))
{
scrollPos = pos.scrollPosition;
if (selectTab == SelectType.Input)
{
for (int i = 0; i < shapeKeyNames.Count; i++)
{
using (new EditorGUILayout.HorizontalScope())
{
using (var toggle = new EditorGUI.ChangeCheckScope())
{
EditorGUILayout.Toggle(shapeKeyNames[i] != posNames[i], GUILayout.Width(30));
if (toggle.changed && shapeKeyNames[i] != posNames[i])
{
posNames[i] = shapeKeyNames[i];
selectedIndices[i] = -1;
}
}
posNames[i] = EditorGUILayout.TextField(shapeKeyNames[i], posNames[i]);
}
}
}
else
{
for (int i = 0; i < shapeKeyNames.Count; i++)
{
using (new EditorGUILayout.HorizontalScope())
{
using (var toggle = new EditorGUI.ChangeCheckScope())
{
EditorGUILayout.Toggle(shapeKeyNames[i] != posNames[i], GUILayout.Width(30));
if (toggle.changed && shapeKeyNames[i] != posNames[i])
{
posNames[i] = shapeKeyNames[i];
selectedIndices[i] = -1;
}
}
using (var check = new EditorGUI.ChangeCheckScope())
{
selectedIndices[i] = EditorGUILayout.Popup(shapeKeyNames[i], selectedIndices[i], selectableNames);
if (check.changed && selectedIndices[i] != -1)
posNames[i] = selectableNames[selectedIndices[i]];
}
}
}
}
}
}
using (new EditorGUI.DisabledScope(renderer == null))
{
useDuplication = EditorGUILayout.Toggle("Duplication ShapeKeys", useDuplication);
// 대문자 -> 소문자 변환 버튼
if (GUILayout.Button("Convert First Letter to Lowercase"))
{
ConvertFirstLetterToLowercase();
}
// 소문자 -> 대문자 변환 버튼
if (GUILayout.Button("Convert First Letter to Uppercase"))
{
ConvertFirstLetterToUppercase();
}
if (GUILayout.Button("Change ShapeKeyName"))
{
CreateNewShapeKeyNameMesh(renderer, posNames, useDuplication, shapeKeyNames);
shapeKeyNames = GetBlendShapeListFromRenderer(renderer);
posNames = shapeKeyNames.ToArray();
selectedIndices = new int[shapeKeyNames.Count];
for (int i = 0; i < selectedIndices.Length; i++)
{
selectedIndices[i] = -1;
}
}
}
}
// 첫 글자를 소문자로 변환하는 함수
private void ConvertFirstLetterToLowercase()
{
for (int i = 0; i < posNames.Length; i++)
{
if (!char.IsLower(posNames[i][0]))
{
posNames[i] = char.ToLower(posNames[i][0]) + posNames[i].Substring(1);
}
}
}
// 첫 글자를 대문자로 변환하는 함수
private void ConvertFirstLetterToUppercase()
{
for (int i = 0; i < posNames.Length; i++)
{
if (!char.IsUpper(posNames[i][0]))
{
posNames[i] = char.ToUpper(posNames[i][0]) + posNames[i].Substring(1);
}
}
}
private bool CreateNewShapeKeyNameMesh(SkinnedMeshRenderer renderer, string[] posShapeKeyNames, bool useDuplication, List<string> preShapeKeyNames)
{
var mesh = renderer.sharedMesh;
if (mesh == null) return false;
if (posShapeKeyNames.Length != mesh.blendShapeCount) return false;
var mesh_custom = UnityEngine.Object.Instantiate<Mesh>(mesh);
mesh_custom.ClearBlendShapes();
var frameIndex = 0;
var shapeKeyName = string.Empty;
Vector3[] deltaVertices, deltaNormals, deltaTangents;
for (int blendShapeIndex = 0; blendShapeIndex < mesh.blendShapeCount; blendShapeIndex++)
{
deltaVertices = new Vector3[mesh.vertexCount];
deltaNormals = new Vector3[mesh.vertexCount];
deltaTangents = new Vector3[mesh.vertexCount];
mesh.GetBlendShapeFrameVertices(blendShapeIndex, frameIndex, deltaVertices, deltaNormals, deltaTangents);
var weight = mesh.GetBlendShapeFrameWeight(blendShapeIndex, frameIndex);
shapeKeyName = posNames[blendShapeIndex];
if (useDuplication && !preShapeKeyNames[blendShapeIndex].Equals(shapeKeyName))
{
mesh_custom.AddBlendShapeFrame(preShapeKeyNames[blendShapeIndex], weight, deltaVertices, deltaNormals, deltaTangents);
}
mesh_custom.AddBlendShapeFrame(shapeKeyName, weight, deltaVertices, deltaNormals, deltaTangents);
}
Undo.RecordObject(renderer, "Renderer " + renderer.name);
renderer.sharedMesh = mesh_custom;
var path = Path.GetDirectoryName(AssetDatabase.GetAssetPath(mesh)) + "/" + mesh.name + "_custom.asset";
AssetDatabase.CreateAsset(mesh_custom, AssetDatabase.GenerateUniqueAssetPath(path));
AssetDatabase.SaveAssets();
return true;
}
private List<string> GetBlendShapeListFromRenderer(SkinnedMeshRenderer renderer)
{
List<string> shapeKeyNames = new List<string>();
var mesh = renderer.sharedMesh;
if (mesh != null)
for (int i = 0; i < mesh.blendShapeCount; i++)
shapeKeyNames.Add(mesh.GetBlendShapeName(i));
return shapeKeyNames;
}
private string[] LoadJsonDataFromResourceFolder(string path)
{
var textAsset = Resources.Load<TextAsset>(path);
var jsonData = JsonUtility.FromJson<JsonData>(textAsset.ToString());
return jsonData.ShapeKeyNames;
}
}
}