Created
May 15, 2019 16:52
-
-
Save XakazukinX/b0028b8facd4e066c567cbc10b9beb7d to your computer and use it in GitHub Desktop.
VRMBlendShapeProxyからAnimationClipをはくやつ
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using UnityEditor; | |
using UnityEngine; | |
using VRM; | |
public class BlendShapeAnimationExpoter : EditorWindow | |
{ | |
//対象のVRMBlendShapeProxy | |
public VRMBlendShapeProxy proxy; | |
public string savePath; | |
//Animatorとかがアタッチされているオブジェクト | |
private GameObject targetRoot; | |
//チェックボックスの状態を管理する用 | |
[Serializable] | |
public class TargetBlendShapeClip | |
{ | |
public string blendShapeClipName; | |
public bool isExport; | |
} | |
private List<TargetBlendShapeClip> targetBlendShapeClips = new List<TargetBlendShapeClip>(); | |
private Dictionary<string ,bool> targetDictionary; | |
/* | |
[ContextMenu("test")] | |
public void test() | |
{ | |
exportBlendShapeProxyForAnimationClip(); | |
} | |
*/ | |
private void exportBlendShapeProxyForAnimationClip() | |
{ | |
targetRoot = proxy.gameObject; | |
//BlendShapeProxyの個数 | |
int clipCount = proxy.BlendShapeAvatar.Clips.Count; | |
for (int i = 0; i < clipCount; i++) | |
{ | |
//i番目のBlendShapeClipを取得 | |
var blendShapeClip = proxy.BlendShapeAvatar.Clips[i]; | |
//チェックボックスがFalseだったときは飛ばす | |
if (!targetDictionary[blendShapeClip.BlendShapeName]) | |
{ | |
continue; | |
} | |
//空のAnimationClipを作成 | |
AnimationClip animclip = new AnimationClip(); | |
EditorCurveBinding curveBinding = new EditorCurveBinding(); | |
//BlendShapeClipで使われているBlendShapeをそれぞれ参照して、weightをAnimationClipに書き込む | |
for (int j = 0; j < blendShapeClip.Values.Length; j++) | |
{ | |
//i番目のBlendShapeClipで使われているj番目のSkinnedMeshRendererのある相対パスを取得(ややこい) | |
var relativePath = blendShapeClip.Values[j].RelativePath; | |
//パスからSkinnedMeshRendererとSharedMeshを取得 | |
var skinnedMeshRenderer = targetRoot.transform.Find(relativePath).GetComponent<SkinnedMeshRenderer>(); | |
var sharedMesh = skinnedMeshRenderer.sharedMesh; | |
//SharedMeshからBlendShapeの名前とを引っ張ってくる | |
var blendShapeName = sharedMesh.GetBlendShapeName(blendShapeClip.Values[j].Index); | |
var blendShapeWeight = blendShapeClip.Values[j].Weight; | |
//一旦BlendShapeにBlendShapeClipで指定されている値をいれてAnimationClipを生成しやすくする | |
skinnedMeshRenderer.SetBlendShapeWeight(blendShapeClip.Values[j].Index, blendShapeWeight); | |
//案メーション作成 | |
createAnimation(animclip, curveBinding, relativePath, | |
"blendShape." + blendShapeName, blendShapeWeight); | |
//BlendShapeの値を0に戻す | |
skinnedMeshRenderer.SetBlendShapeWeight(blendShapeClip.Values[j].Index, 0); | |
} | |
if (blendShapeClip.Values.Length != 0) | |
{ | |
//AnimationClipとして書き出す | |
AssetDatabase.CreateAsset( | |
animclip, | |
AssetDatabase.GenerateUniqueAssetPath("Assets/"+savePath+"/"+blendShapeClip.BlendShapeName+".anim") | |
); | |
AssetDatabase.SaveAssets(); | |
Debug.Log("Generate "+blendShapeClip.BlendShapeName+".anim !"); | |
AssetDatabase.Refresh(); | |
} | |
} | |
} | |
private void initDictionary() | |
{ | |
targetDictionary = new Dictionary<string, bool>(); | |
for (int i = 0; i < proxy.BlendShapeAvatar.Clips.Count; i++) | |
{ | |
targetDictionary.Add(targetBlendShapeClips[i].blendShapeClipName, targetBlendShapeClips[i].isExport); | |
} | |
} | |
//AnimationClipに書き込んでいく関数 | |
private void createAnimation(AnimationClip targetAnimClip, EditorCurveBinding curveBinding, string curvePath, | |
string curvePropertyName, float keyWeight) | |
{ | |
curveBinding.path = curvePath; | |
curveBinding.type = typeof(SkinnedMeshRenderer); | |
curveBinding.propertyName = curvePropertyName; | |
AnimationCurve curve = new AnimationCurve(); | |
curve.AddKey(0f, keyWeight); | |
AnimationUtility.SetEditorCurve(targetAnimClip, curveBinding, curve); | |
} | |
[MenuItem("VRM/VRMBlendShapeProxyAnimationExporter")] | |
static void Open () | |
{ | |
var exampleWindow = CreateInstance<BlendShapeAnimationExpoter> (); | |
exampleWindow.Show (); | |
} | |
private void OnGUI() | |
{ | |
EditorGUIUtility.labelWidth = 200; | |
EditorGUILayout.BeginVertical(); | |
proxy = (VRMBlendShapeProxy) EditorGUILayout.ObjectField("TragetVRMBlendShapeProxy",proxy, typeof(VRMBlendShapeProxy), true); | |
EditorGUILayout.BeginHorizontal(); | |
EditorGUILayout.PrefixLabel ("SavePath:Assets/"); | |
savePath = EditorGUILayout.TextField(savePath); | |
EditorGUILayout.PrefixLabel ("/"); | |
EditorGUILayout.EndHorizontal(); | |
EditorGUILayout.EndVertical(); | |
if (proxy == null) | |
{ | |
return; | |
} | |
for (int i = 0; i < proxy.BlendShapeAvatar.Clips.Count; i++) | |
{ | |
targetBlendShapeClips.Add(new TargetBlendShapeClip()); | |
EditorGUILayout.BeginHorizontal(); | |
targetBlendShapeClips[i].blendShapeClipName = proxy.BlendShapeAvatar.Clips[i].BlendShapeName; | |
targetBlendShapeClips[i].isExport = EditorGUILayout.Toggle(targetBlendShapeClips[i].blendShapeClipName, targetBlendShapeClips[i].isExport); | |
EditorGUILayout.EndHorizontal(); | |
} | |
if( GUILayout.Button( "Generate AnimationClip !" ) ) | |
{ | |
if (proxy == null) | |
{ | |
Debug.LogError("VRMBlendShapeProxyがセットされていません!"); | |
return; | |
} | |
initDictionary(); | |
exportBlendShapeProxyForAnimationClip(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment