166 lines
6.2 KiB
C#

using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using System.Linq;
using System.IO;
namespace VRCDeveloperTool
{
public class ShapeKeyDeleter : EditorWindow
{
private SkinnedMeshRenderer renderer;
private List<string> shapeKeyNames;
private bool[] selectedShapeKeys;
private bool isOpenedBlendShape = true;
private Vector2 shapeKeyScrollPos = Vector2.zero;
private int lastSelectedIndex = -1; // 마지막 선택된 인덱스 저장
[MenuItem("VRCDeveloperTool/Mesh/ShapeKey Deleter")]
private static void Open()
{
GetWindow<ShapeKeyDeleter>("ShapeKey Deleter");
}
private void OnEnable()
{
renderer = null;
shapeKeyNames = null;
selectedShapeKeys = null;
isOpenedBlendShape = true;
shapeKeyScrollPos = Vector2.zero;
}
private void OnGUI()
{
using (var check = new EditorGUI.ChangeCheckScope())
{
renderer = EditorGUILayout.ObjectField(
"SkinnedMeshRenderer",
renderer,
typeof(SkinnedMeshRenderer),
true
) as SkinnedMeshRenderer;
if (check.changed)
{
if (renderer != null)
{
shapeKeyNames = GetBlendShapeListFromRenderer(renderer);
selectedShapeKeys = new bool[shapeKeyNames.Count()];
}
}
}
if (shapeKeyNames != null)
{
isOpenedBlendShape = EditorGUILayout.Foldout(isOpenedBlendShape, "Shape Keys");
if (isOpenedBlendShape)
{
using (new EditorGUI.IndentLevelScope())
using (var scroll = new EditorGUILayout.ScrollViewScope(shapeKeyScrollPos, GUI.skin.box))
{
shapeKeyScrollPos = scroll.scrollPosition;
Event e = Event.current;
for (int i = 0; i < shapeKeyNames.Count(); i++)
{
bool originalValue = selectedShapeKeys[i];
bool newValue = EditorGUILayout.ToggleLeft(shapeKeyNames[i], selectedShapeKeys[i]);
// Shift 클릭 처리
if (e.shift && lastSelectedIndex != -1 && newValue != originalValue)
{
int startIndex = Mathf.Min(lastSelectedIndex, i);
int endIndex = Mathf.Max(lastSelectedIndex, i);
for (int j = startIndex; j <= endIndex; j++)
{
selectedShapeKeys[j] = true;
}
}
// 마지막 선택된 인덱스 갱신
if (newValue != originalValue)
{
lastSelectedIndex = i;
}
selectedShapeKeys[i] = newValue;
}
}
}
}
using (new EditorGUI.DisabledScope(renderer == null || (selectedShapeKeys != null && selectedShapeKeys.All(x => !x))))
{
if (GUILayout.Button("Delete ShapeKeys"))
{
var selectedBlendShapeIndexs = selectedShapeKeys
.Select((isSelect, index) => new { Index = index, Value = isSelect })
.Where(x => x.Value)
.Select(x => x.Index)
.ToArray();
DeleteShapeKey(renderer, selectedBlendShapeIndexs);
shapeKeyNames = GetBlendShapeListFromRenderer(renderer);
selectedShapeKeys = new bool[shapeKeyNames.Count()];
}
}
}
private bool DeleteShapeKey(SkinnedMeshRenderer renderer, int[] selectedShapeKeyIndexs)
{
var mesh = renderer.sharedMesh;
if (mesh == null) return false;
var mesh_custom = Instantiate(mesh);
mesh_custom.ClearBlendShapes();
int frameIndex = 0;
string shapeKeyName;
float weight;
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);
weight = mesh.GetBlendShapeFrameWeight(blendShapeIndex, frameIndex);
if (!selectedShapeKeyIndexs.Contains(blendShapeIndex))
{
shapeKeyName = mesh.GetBlendShapeName(blendShapeIndex);
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 + "_shapekeydeleted.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;
}
}
}