ADD: VRCDeveloperTool 스크립트 업로드
This commit is contained in:
parent
139756d662
commit
df848b2c8b
9
Assets/External/VRCDeveloperTool/Editor.meta
vendored
Normal file
9
Assets/External/VRCDeveloperTool/Editor.meta
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c0567de9323ae234dbc4465a542d0be3
|
||||
folderAsset: yes
|
||||
timeCreated: 1536028717
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/External/VRCDeveloperTool/Editor/AnimationPropertyConverter.meta
vendored
Normal file
8
Assets/External/VRCDeveloperTool/Editor/AnimationPropertyConverter.meta
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9adcb8c102e5f7948b0f7e44f6c4bf0e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
361
Assets/External/VRCDeveloperTool/Editor/AnimationPropertyConverter/AnimationPropertyConverter.cs
vendored
Normal file
361
Assets/External/VRCDeveloperTool/Editor/AnimationPropertyConverter/AnimationPropertyConverter.cs
vendored
Normal file
@ -0,0 +1,361 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
// ver 1.0
|
||||
// © 2019 gatosyocora
|
||||
|
||||
namespace VRCDeveloperTool
|
||||
{
|
||||
|
||||
public class AnimationPropertyConverter : EditorWindow
|
||||
{
|
||||
|
||||
private SkinnedMeshRenderer avatarMesh;
|
||||
|
||||
private List<AnimationClip> preAnimationClips;
|
||||
private List<AnimationProperty> animPropertyList;
|
||||
private string[] blendShapeNameList;
|
||||
|
||||
private string saveFolder = "Assets/";
|
||||
|
||||
private bool convertBlendShapeName = false;
|
||||
private bool isOpeningPreAnimationClips = true;
|
||||
private bool isOpeningAnimationPropertyList = true;
|
||||
private Vector2 propertyScrollPos = Vector2.zero;
|
||||
private bool isConvertAll = false;
|
||||
|
||||
public class AnimationProperty
|
||||
{
|
||||
public string propertyType;
|
||||
public string preName;
|
||||
public string posName;
|
||||
public bool isConvert;
|
||||
public int selectedBlendShapeIndex;
|
||||
public List<int> animIndexHavingThisProperty;
|
||||
|
||||
public AnimationProperty(string type, string name, int animIndex)
|
||||
{
|
||||
propertyType = type;
|
||||
preName = name;
|
||||
posName = preName;
|
||||
isConvert = false;
|
||||
selectedBlendShapeIndex = 0;
|
||||
|
||||
animIndexHavingThisProperty = new List<int>() { animIndex };
|
||||
}
|
||||
|
||||
public void AddAnimIndexHavingThisProperty(int animIndex)
|
||||
{
|
||||
animIndexHavingThisProperty.Add(animIndex);
|
||||
}
|
||||
|
||||
public bool RemoveAnimIndexHavingThisProperty(int animIndex)
|
||||
{
|
||||
return animIndexHavingThisProperty.Remove(animIndex);
|
||||
}
|
||||
|
||||
public bool existAnimHavingThisProperty()
|
||||
{
|
||||
return animIndexHavingThisProperty.Count > 0;
|
||||
}
|
||||
}
|
||||
|
||||
[MenuItem("VRCDeveloperTool/AnimationPropertyConverter")]
|
||||
private static void Create()
|
||||
{
|
||||
GetWindow<AnimationPropertyConverter>("AnimationProperty Converter");
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
avatarMesh = null;
|
||||
|
||||
preAnimationClips = new List<AnimationClip>();
|
||||
preAnimationClips.Add(null);
|
||||
|
||||
animPropertyList = new List<AnimationProperty>();
|
||||
|
||||
blendShapeNameList = null;
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
convertBlendShapeName = EditorGUILayout.ToggleLeft("Convert BlendShapeName", convertBlendShapeName);
|
||||
|
||||
if (convertBlendShapeName)
|
||||
{
|
||||
using (var check = new EditorGUI.ChangeCheckScope())
|
||||
{
|
||||
avatarMesh = EditorGUILayout.ObjectField(
|
||||
"Avatar's SkinnedMeshRenderer",
|
||||
avatarMesh,
|
||||
typeof(SkinnedMeshRenderer),
|
||||
true
|
||||
) as SkinnedMeshRenderer;
|
||||
|
||||
if (check.changed && avatarMesh != null)
|
||||
blendShapeNameList = GetBlendShapeNameList(avatarMesh);
|
||||
}
|
||||
}
|
||||
|
||||
isOpeningPreAnimationClips = EditorGUILayout.Foldout(isOpeningPreAnimationClips, "Pre AnimationClips");
|
||||
if (isOpeningPreAnimationClips)
|
||||
{
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
GUILayout.FlexibleSpace();
|
||||
if (GUILayout.Button("+"))
|
||||
{
|
||||
preAnimationClips.Add(null);
|
||||
}
|
||||
if (GUILayout.Button("-") && preAnimationClips.Count > 1)
|
||||
{
|
||||
var animIndex = preAnimationClips.Count - 1;
|
||||
|
||||
CheckAndRemoveAnimProperties(ref animPropertyList, animIndex);
|
||||
|
||||
preAnimationClips.RemoveAt(animIndex);
|
||||
}
|
||||
}
|
||||
using (new EditorGUI.IndentLevelScope())
|
||||
{
|
||||
for (int animIndex = 0; animIndex < preAnimationClips.Count; animIndex++)
|
||||
{
|
||||
using (var check = new EditorGUI.ChangeCheckScope())
|
||||
{
|
||||
preAnimationClips[animIndex] = EditorGUILayout.ObjectField(
|
||||
"AnimationClip " + (animIndex + 1),
|
||||
preAnimationClips[animIndex],
|
||||
typeof(AnimationClip),
|
||||
true
|
||||
) as AnimationClip;
|
||||
|
||||
if (check.changed)
|
||||
{
|
||||
CheckAndRemoveAnimProperties(ref animPropertyList, animIndex);
|
||||
|
||||
if (preAnimationClips[animIndex] != null)
|
||||
UpdateAnimationPropertyNameList(preAnimationClips[animIndex], ref animPropertyList, animIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
EditorGUILayout.Space();
|
||||
|
||||
isOpeningAnimationPropertyList = EditorGUILayout.Foldout(isOpeningAnimationPropertyList, "AnimationPropertyList");
|
||||
if (isOpeningAnimationPropertyList)
|
||||
{
|
||||
using (new EditorGUI.IndentLevelScope())
|
||||
{
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
using (var check = new EditorGUI.ChangeCheckScope())
|
||||
{
|
||||
isConvertAll = EditorGUILayout.Toggle(isConvertAll, GUILayout.Width(30f));
|
||||
|
||||
if (check.changed)
|
||||
ChangeAllIsConvertParams(isConvertAll, ref animPropertyList);
|
||||
}
|
||||
|
||||
EditorGUILayout.LabelField("prePropertyName", EditorStyles.boldLabel);
|
||||
EditorGUILayout.LabelField("posPropertyName", EditorStyles.boldLabel);
|
||||
}
|
||||
|
||||
using (var scrollPos = new GUILayout.ScrollViewScope(propertyScrollPos))
|
||||
{
|
||||
propertyScrollPos = scrollPos.scrollPosition;
|
||||
foreach (var animProperty in animPropertyList)
|
||||
{
|
||||
if (!convertBlendShapeName || animProperty.propertyType == "blendShape")
|
||||
{
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
animProperty.isConvert = EditorGUILayout.Toggle(animProperty.isConvert, GUILayout.Width(30f));
|
||||
|
||||
if (convertBlendShapeName && avatarMesh != null)
|
||||
{
|
||||
EditorGUILayout.LabelField(animProperty.preName);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.LabelField(animProperty.propertyType + "." + animProperty.preName);
|
||||
}
|
||||
|
||||
using (var check = new EditorGUI.ChangeCheckScope())
|
||||
{
|
||||
|
||||
if (convertBlendShapeName && avatarMesh != null)
|
||||
{
|
||||
animProperty.selectedBlendShapeIndex = EditorGUILayout.Popup(animProperty.selectedBlendShapeIndex, blendShapeNameList);
|
||||
}
|
||||
else
|
||||
{
|
||||
animProperty.posName = EditorGUILayout.TextField(animProperty.posName);
|
||||
}
|
||||
|
||||
if (check.changed)
|
||||
{
|
||||
if (convertBlendShapeName && avatarMesh != null)
|
||||
animProperty.posName = blendShapeNameList[animProperty.selectedBlendShapeIndex];
|
||||
|
||||
animProperty.isConvert = true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
EditorGUILayout.LabelField("AnimClipSaveFolder", saveFolder);
|
||||
|
||||
if (GUILayout.Button("Select Folder", GUILayout.Width(100)))
|
||||
{
|
||||
saveFolder = EditorUtility.OpenFolderPanel("Select saved folder", saveFolder, "");
|
||||
var match = Regex.Match(saveFolder, @"Assets/.*");
|
||||
saveFolder = match.Value + "/";
|
||||
if (saveFolder == "/") saveFolder = "Assets/";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Convert Property & Save as New File"))
|
||||
{
|
||||
ConvertAndCreateAnimationClips(preAnimationClips, animPropertyList, saveFolder, convertBlendShapeName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// アニメーションファイルのプロパティの名前を変更して新しいファイルとして書き出す
|
||||
/// </summary>
|
||||
/// <param name="baseAnimClips"></param>
|
||||
/// <param name="animPropertyList"></param>
|
||||
/// <param name="saveFolder"></param>
|
||||
/// <param name="convertBlendShapeName"></param>
|
||||
private void ConvertAndCreateAnimationClips(List<AnimationClip> baseAnimClips, List<AnimationProperty> animPropertyList, string saveFolder, bool convertBlendShapeName)
|
||||
{
|
||||
// 変換するプロパティ(isConvert == true)のものだけのリストをつくる
|
||||
var shoundConvertedPropertyList = animPropertyList.Where(x => x.isConvert).ToList<AnimationProperty>();
|
||||
|
||||
foreach (var baseAnimClip in baseAnimClips)
|
||||
{
|
||||
if (baseAnimClip == null) continue;
|
||||
|
||||
var convertedAnimClip = Object.Instantiate<AnimationClip>(baseAnimClip);
|
||||
|
||||
var bindings = AnimationUtility.GetCurveBindings(convertedAnimClip);
|
||||
|
||||
for (int i = 0; i < bindings.Length; i++)
|
||||
{
|
||||
// binding.propertyName == blendShape.vrc.v_silみたいになっている
|
||||
var propertyType = bindings[i].propertyName.Split('.')[0];
|
||||
var blendShapeName = bindings[i].propertyName.Replace(propertyType + ".", "");
|
||||
|
||||
// blendShapeだけ変更するモードだったらそれ以外の場合は処理しない
|
||||
if (convertBlendShapeName && propertyType != "blendShape") continue;
|
||||
|
||||
// 変換するプロパティのリストに含まれるプロパティだけ変換する
|
||||
var targetAnimProperty = shoundConvertedPropertyList.Find(x => x.propertyType == propertyType && x.preName == blendShapeName);
|
||||
if (targetAnimProperty != null)
|
||||
{
|
||||
var curve = AnimationUtility.GetEditorCurve(convertedAnimClip, bindings[i]);
|
||||
AnimationUtility.SetEditorCurve(convertedAnimClip, bindings[i], null);
|
||||
|
||||
bindings[i].propertyName = targetAnimProperty.propertyType + "." + targetAnimProperty.posName;
|
||||
|
||||
AnimationUtility.SetEditorCurve(convertedAnimClip, bindings[i], curve);
|
||||
}
|
||||
}
|
||||
|
||||
AssetDatabase.CreateAsset(convertedAnimClip, AssetDatabase.GenerateUniqueAssetPath(saveFolder + baseAnimClip.name + ".anim"));
|
||||
|
||||
}
|
||||
AssetDatabase.SaveAssets();
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// アニメーションプロパティリストを更新する
|
||||
/// </summary>
|
||||
/// <param name="animClips"></param>
|
||||
/// <param name="animPropertyList"></param>
|
||||
private void UpdateAnimationPropertyNameList(AnimationClip animClips, ref List<AnimationProperty> animPropertyList, int animIndex)
|
||||
{
|
||||
var bindings = AnimationUtility.GetCurveBindings(animClips);
|
||||
|
||||
foreach (var binding in bindings)
|
||||
{
|
||||
// binding.propertyName == blendShape.vrc.v_silみたいになっている
|
||||
var propertyType = binding.propertyName.Split('.')[0];
|
||||
var blendShapeName = binding.propertyName.Replace(propertyType + ".", "");
|
||||
|
||||
// animPropertyListに含まれていないプロパティだけ追加する
|
||||
// すでに含まれている場合AnimIndexHavingThisPropertyに追加する
|
||||
var animProperty = animPropertyList.Find(x => x.propertyType == propertyType && x.preName == blendShapeName);
|
||||
if (animProperty == null)
|
||||
animPropertyList.Add(new AnimationProperty(propertyType, blendShapeName, animIndex));
|
||||
else
|
||||
animProperty.AddAnimIndexHavingThisProperty(animIndex);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ブレンドシェイプの名前一覧を取得する
|
||||
/// </summary>
|
||||
/// <param name="meshRenderer"></param>
|
||||
/// <returns></returns>
|
||||
private string[] GetBlendShapeNameList(SkinnedMeshRenderer meshRenderer)
|
||||
{
|
||||
var mesh = meshRenderer.sharedMesh;
|
||||
if (mesh == null) return null;
|
||||
|
||||
var blendShapeNameList = new string[mesh.blendShapeCount];
|
||||
|
||||
for (int i = 0; i < mesh.blendShapeCount; i++)
|
||||
blendShapeNameList[i] = mesh.GetBlendShapeName(i);
|
||||
|
||||
return blendShapeNameList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// すべてのプロパティリストのisConvertを変更する
|
||||
/// </summary>
|
||||
/// <param name="isConvertAll"></param>
|
||||
/// <param name="animPropertyList"></param>
|
||||
private void ChangeAllIsConvertParams(bool isConvertAll, ref List<AnimationProperty> animPropertyList)
|
||||
{
|
||||
foreach (var animProperty in animPropertyList)
|
||||
{
|
||||
animProperty.isConvert = isConvertAll;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// プロパティリストに含まれるすべてのプロパティのAnimIndexHavingThisPropertyからanimIndexを削除して
|
||||
/// リストに不要なプロパティか調べ、削除する
|
||||
/// </summary>
|
||||
/// <param name="animPropertyList"></param>
|
||||
/// <param name="animIndex"></param>
|
||||
private void CheckAndRemoveAnimProperties(ref List<AnimationProperty> animPropertyList, int animIndex)
|
||||
{
|
||||
foreach (var animProperty in animPropertyList.ToArray())
|
||||
{
|
||||
animProperty.RemoveAnimIndexHavingThisProperty(animIndex);
|
||||
if (!animProperty.existAnimHavingThisProperty())
|
||||
animPropertyList.Remove(animProperty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9826d703d0a307c478e8e2a69f9ec980
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/External/VRCDeveloperTool/Editor/AnimatorControllerDuplicator.meta
vendored
Normal file
8
Assets/External/VRCDeveloperTool/Editor/AnimatorControllerDuplicator.meta
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8b7d1dbc790667b4d96b794d9102bb06
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
262
Assets/External/VRCDeveloperTool/Editor/AnimatorControllerDuplicator/AnimatorControllerDuplicator.cs
vendored
Normal file
262
Assets/External/VRCDeveloperTool/Editor/AnimatorControllerDuplicator/AnimatorControllerDuplicator.cs
vendored
Normal file
@ -0,0 +1,262 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Animations;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
using VRCDeveloperTool;
|
||||
|
||||
// ver 1.0.1
|
||||
// Copyright (c) 2020 gatosyocora
|
||||
|
||||
namespace VRCDeveloperTool
|
||||
{
|
||||
public class AnimatorControllerDuplicator : EditorWindow
|
||||
{
|
||||
private RuntimeAnimatorController runtimeAnimatorController;
|
||||
private static RuntimeAnimatorController tempController;
|
||||
private List<ControllerAnimationClip> animationClips;
|
||||
|
||||
private string saveFolder;
|
||||
private string endKeyword;
|
||||
|
||||
private bool isOverrideController = true;
|
||||
|
||||
private Vector2 scrollPos = Vector2.zero;
|
||||
|
||||
public class ControllerAnimationClip
|
||||
{
|
||||
public AnimationClip clip;
|
||||
public List<int> controllerIndices;
|
||||
public bool isDuplicate;
|
||||
|
||||
public ControllerAnimationClip(AnimationClip clip, int index, bool isDuplicate = true)
|
||||
{
|
||||
this.clip = clip;
|
||||
controllerIndices = new List<int>();
|
||||
AddIndex(index);
|
||||
this.isDuplicate = isDuplicate;
|
||||
}
|
||||
|
||||
public void AddIndex(int index)
|
||||
{
|
||||
controllerIndices.Add(index);
|
||||
}
|
||||
}
|
||||
|
||||
[MenuItem("CONTEXT/RuntimeAnimatorController/Duplicate Controller And Clips")]
|
||||
private static void GetSelectController(MenuCommand menuCommand)
|
||||
{
|
||||
tempController = menuCommand.context as RuntimeAnimatorController;
|
||||
Open();
|
||||
}
|
||||
|
||||
[MenuItem("VRCDeveloperTool/AnimatorControllerDuplicator")]
|
||||
public static void Open()
|
||||
{
|
||||
GetWindow<AnimatorControllerDuplicator>("AnimatorControllerDuplicator");
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
if (tempController != null)
|
||||
{
|
||||
runtimeAnimatorController = tempController;
|
||||
tempController = null;
|
||||
LoadRuntimeControllerInfo(runtimeAnimatorController);
|
||||
}
|
||||
|
||||
using (var check = new EditorGUI.ChangeCheckScope())
|
||||
{
|
||||
runtimeAnimatorController = EditorGUILayout.ObjectField(
|
||||
"AnimatorController",
|
||||
runtimeAnimatorController,
|
||||
typeof(RuntimeAnimatorController),
|
||||
true) as RuntimeAnimatorController;
|
||||
|
||||
EditorGUILayout.HelpBox("複製したいAnimatorOverrideControllerを設定してください", MessageType.Info);
|
||||
|
||||
if (!isOverrideController)
|
||||
EditorGUILayout.HelpBox("まだAnimatorControllerは未対応です", MessageType.Error);
|
||||
|
||||
if (check.changed && runtimeAnimatorController != null)
|
||||
{
|
||||
LoadRuntimeControllerInfo(runtimeAnimatorController);
|
||||
}
|
||||
}
|
||||
|
||||
if (animationClips != null)
|
||||
{
|
||||
EditorGUILayout.LabelField("AnimaionClips", EditorStyles.boldLabel);
|
||||
|
||||
using (new EditorGUI.IndentLevelScope())
|
||||
{
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
EditorGUILayout.LabelField("複製", EditorStyles.boldLabel, GUILayout.Width(50f));
|
||||
EditorGUILayout.LabelField("AnimationClipの名前", EditorStyles.boldLabel);
|
||||
}
|
||||
|
||||
using (var scroll = new EditorGUILayout.ScrollViewScope(scrollPos))
|
||||
{
|
||||
scrollPos = scroll.scrollPosition;
|
||||
|
||||
foreach (var animationClip in animationClips)
|
||||
{
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
animationClip.isDuplicate = EditorGUILayout.ToggleLeft(string.Empty, animationClip.isDuplicate, GUILayout.Width(50f));
|
||||
EditorGUILayout.LabelField(animationClip.clip.name);
|
||||
if (GUILayout.Button("Select"))
|
||||
{
|
||||
Selection.activeObject = animationClip.clip;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
saveFolder = EditorGUILayout.TextField("保存先フォルダ", saveFolder);
|
||||
|
||||
endKeyword = EditorGUILayout.TextField("複製後Assetのキーワード", endKeyword);
|
||||
|
||||
EditorGUILayout.HelpBox("AnimatorControllerおよび選択したAnimationClipを複製します\n複製されると複製後のものがそれぞれ設定されます\n複製後Assetのキーワードに設定した文字がそれぞれの名前の末尾につきます", MessageType.Info);
|
||||
|
||||
using (new EditorGUI.DisabledGroupScope(runtimeAnimatorController == null || !isOverrideController))
|
||||
{
|
||||
if (GUILayout.Button("Duplicate AnimatorController & AnimationClips"))
|
||||
{
|
||||
DuplicateAnimatorControllerAndAnimationClips();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DuplicateAnimatorControllerAndAnimationClips()
|
||||
{
|
||||
var controllerPath = AssetDatabase.GetAssetPath(runtimeAnimatorController);
|
||||
var newControllerPath = AssetDatabase.GenerateUniqueAssetPath(
|
||||
saveFolder + "\\"
|
||||
+ GatoEditorUtility.AddKeywordToEnd(Path.GetFileNameWithoutExtension(controllerPath), endKeyword)
|
||||
+ Path.GetExtension(controllerPath));
|
||||
|
||||
var success = AssetDatabase.CopyAsset(controllerPath, newControllerPath);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
Debug.LogError("AnimatorControllerの複製に失敗しました");
|
||||
return;
|
||||
}
|
||||
|
||||
AssetDatabase.SaveAssets();
|
||||
AssetDatabase.Refresh();
|
||||
|
||||
runtimeAnimatorController = AssetDatabase.LoadAssetAtPath(newControllerPath, typeof(RuntimeAnimatorController)) as RuntimeAnimatorController;
|
||||
|
||||
foreach (var animationClip in animationClips)
|
||||
{
|
||||
if (!animationClip.isDuplicate) continue;
|
||||
|
||||
var animClipPath = AssetDatabase.GetAssetPath(animationClip.clip);
|
||||
var newAnimClipPath = AssetDatabase.GenerateUniqueAssetPath(
|
||||
saveFolder + "\\"
|
||||
+ GatoEditorUtility.AddKeywordToEnd(Path.GetFileNameWithoutExtension(animClipPath), endKeyword)
|
||||
+ Path.GetExtension(animClipPath));
|
||||
|
||||
var successAnimClip = AssetDatabase.CopyAsset(animClipPath, newAnimClipPath);
|
||||
|
||||
if (!successAnimClip)
|
||||
{
|
||||
Debug.LogErrorFormat("AnimationClip:{0}の複製に失敗しました", animationClip.clip.name);
|
||||
return;
|
||||
}
|
||||
|
||||
AssetDatabase.SaveAssets();
|
||||
AssetDatabase.Refresh();
|
||||
|
||||
animationClip.clip = AssetDatabase.LoadAssetAtPath(newAnimClipPath, typeof(AnimationClip)) as AnimationClip;
|
||||
|
||||
foreach (var index in animationClip.controllerIndices)
|
||||
{
|
||||
runtimeAnimatorController.animationClips[index] = animationClip.clip;
|
||||
}
|
||||
}
|
||||
|
||||
if (isOverrideController)
|
||||
{
|
||||
var overrideController = runtimeAnimatorController as AnimatorOverrideController;
|
||||
var baseAnimClips = overrideController.runtimeAnimatorController.animationClips;
|
||||
|
||||
foreach (var animationClip in animationClips)
|
||||
{
|
||||
foreach (var index in animationClip.controllerIndices)
|
||||
{
|
||||
var baseAnimClipName = baseAnimClips[index].name;
|
||||
overrideController[baseAnimClipName] = animationClip.clip;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
AssetDatabase.SaveAssets();
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
|
||||
private List<ControllerAnimationClip> DistinctControllerAnimationClips(List<ControllerAnimationClip> animClips)
|
||||
{
|
||||
var distinctedAnimClips = new List<ControllerAnimationClip>();
|
||||
var animClipDictionary = new Dictionary<string, ControllerAnimationClip>();
|
||||
|
||||
for (int i = 0; i < animClips.Count; i++)
|
||||
{
|
||||
var animName = animClips[i].clip.name;
|
||||
if (!animClipDictionary.ContainsKey(animName))
|
||||
{
|
||||
animClipDictionary.Add(animName, animClips[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
var animClipData = animClipDictionary[animName];
|
||||
animClipData.AddIndex(animClips[i].controllerIndices.First());
|
||||
}
|
||||
}
|
||||
|
||||
distinctedAnimClips = animClipDictionary.Select(x => x.Value).ToList();
|
||||
return distinctedAnimClips;
|
||||
}
|
||||
|
||||
private void LoadRuntimeControllerInfo(RuntimeAnimatorController runtimeAnimatorController)
|
||||
{
|
||||
AnimatorController controller = runtimeAnimatorController as AnimatorController;
|
||||
AnimatorOverrideController overrideController = runtimeAnimatorController as AnimatorOverrideController;
|
||||
|
||||
if (controller != null)
|
||||
{
|
||||
isOverrideController = false;
|
||||
// AnimatorControllerからAnimationClipの取得
|
||||
}
|
||||
else if (overrideController != null)
|
||||
{
|
||||
isOverrideController = true;
|
||||
// AnimatorOverrideControllerからAnimationClipの取得
|
||||
// OverrideされたAnimationClipのみ取得
|
||||
var baseAnimationController = overrideController.runtimeAnimatorController as AnimatorController;
|
||||
animationClips = overrideController.animationClips
|
||||
.Select((x, index) => new { Value = x, Index = index })
|
||||
.Where(x => baseAnimationController.animationClips[x.Index].name != x.Value.name)
|
||||
.Select(x => new ControllerAnimationClip(x.Value, x.Index))
|
||||
.ToList();
|
||||
|
||||
animationClips = DistinctControllerAnimationClips(animationClips);
|
||||
|
||||
}
|
||||
|
||||
saveFolder = Path.GetDirectoryName(AssetDatabase.GetAssetPath(runtimeAnimatorController));
|
||||
endKeyword = string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b31bd1421b78b1e46b35ab56873af04e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
9
Assets/External/VRCDeveloperTool/Editor/ComponentAdder.meta
vendored
Normal file
9
Assets/External/VRCDeveloperTool/Editor/ComponentAdder.meta
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0ecf1e763fda23f48a947d07940662a5
|
||||
folderAsset: yes
|
||||
timeCreated: 1537791342
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
268
Assets/External/VRCDeveloperTool/Editor/ComponentAdder/ComponentAdder.cs
vendored
Normal file
268
Assets/External/VRCDeveloperTool/Editor/ComponentAdder/ComponentAdder.cs
vendored
Normal file
@ -0,0 +1,268 @@
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
#if VRC_SDK_VRCSDK2
|
||||
using VRCSDK2;
|
||||
#endif
|
||||
using System.Collections.Generic;
|
||||
|
||||
// ver 1.2.2
|
||||
// © 2018 gatosyocora
|
||||
|
||||
namespace VRCDeveloperTool
|
||||
{
|
||||
public class ComponentAdder : EditorWindow
|
||||
{
|
||||
|
||||
GameObject targetObject = null;
|
||||
|
||||
private enum AddType
|
||||
{
|
||||
Current_Children_Only,
|
||||
All_Childrens,
|
||||
};
|
||||
|
||||
AddType addType;
|
||||
|
||||
private bool isRigidbody = false;
|
||||
private bool useGravityFlag = true;
|
||||
private bool isKinematicFlag = false;
|
||||
private bool freezePosFlag = false;
|
||||
private bool freezeRotFlag = false;
|
||||
|
||||
private bool isObjectSync = false;
|
||||
|
||||
private bool isPickup = false;
|
||||
|
||||
private bool isBoxCollider = false;
|
||||
private bool isTriggerFlag = false;
|
||||
|
||||
[MenuItem("VRCDeveloperTool/Component Adder")]
|
||||
private static void Create()
|
||||
{
|
||||
GetWindow<ComponentAdder>("Component Adder");
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
targetObject = EditorGUILayout.ObjectField(
|
||||
"ParentObject",
|
||||
targetObject,
|
||||
typeof(GameObject),
|
||||
true
|
||||
) as GameObject;
|
||||
|
||||
addType = (AddType)EditorGUILayout.EnumPopup("Add Type", addType);
|
||||
|
||||
guiRigidbody();
|
||||
|
||||
guiObjectSync();
|
||||
|
||||
guiPickup();
|
||||
|
||||
guiBoxCollider();
|
||||
|
||||
guiAction();
|
||||
|
||||
}
|
||||
|
||||
// 指定オブジェクトの直接的な子オブジェクトをすべて取得する
|
||||
private List<GameObject> getCurrentChildrens(GameObject parentObj)
|
||||
{
|
||||
List<GameObject> objs = new List<GameObject>(parentObj.transform.childCount);
|
||||
|
||||
foreach (Transform child in parentObj.transform)
|
||||
{
|
||||
objs.Add(child.gameObject);
|
||||
|
||||
}
|
||||
return objs;
|
||||
}
|
||||
|
||||
// 指定オブジェクトの子オブジェクト以降をすべて取得する
|
||||
private List<GameObject> getAllChildrens(GameObject parentObj)
|
||||
{
|
||||
List<GameObject> objs = new List<GameObject>();
|
||||
|
||||
var childTransform = parentObj.GetComponentsInChildren<Transform>();
|
||||
|
||||
foreach (Transform child in childTransform)
|
||||
{
|
||||
objs.Add(child.gameObject);
|
||||
}
|
||||
|
||||
return objs;
|
||||
}
|
||||
|
||||
// 特定のオブジェクトにコンポーネントを追加する
|
||||
private void AddComponentObject(GameObject obj)
|
||||
{
|
||||
if (isRigidbody)
|
||||
{
|
||||
var rigid = obj.GetComponent<Rigidbody>();
|
||||
if (rigid == null)
|
||||
rigid = obj.AddComponent<Rigidbody>();
|
||||
rigid.isKinematic = isKinematicFlag;
|
||||
rigid.useGravity = useGravityFlag;
|
||||
rigid.constraints = 0;
|
||||
if (freezePosFlag) rigid.constraints |= RigidbodyConstraints.FreezePosition;
|
||||
if (freezeRotFlag) rigid.constraints |= RigidbodyConstraints.FreezeRotation;
|
||||
}
|
||||
if (isObjectSync)
|
||||
{
|
||||
#if VRC_SDK_VRCSDK2
|
||||
if (obj.GetComponent<VRC_ObjectSync>() == null)
|
||||
{
|
||||
var com = obj.AddComponent<VRC_ObjectSync>();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (isPickup)
|
||||
{
|
||||
#if VRC_SDK_VRCSDK2
|
||||
if (obj.GetComponent<VRC_Pickup>() == null)
|
||||
{
|
||||
var com = obj.AddComponent<VRC_Pickup>();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (isBoxCollider)
|
||||
{
|
||||
if (obj.GetComponent<Collider>() == null || obj.GetComponent<BoxCollider>() != null)
|
||||
{
|
||||
var com = obj.GetComponent<BoxCollider>();
|
||||
if (com == null)
|
||||
com = obj.AddComponent<BoxCollider>();
|
||||
com.isTrigger = isTriggerFlag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 特定のオブジェクトのコンポーネントを削除する
|
||||
private void DeleteComponentObject(GameObject obj)
|
||||
{
|
||||
if (isPickup)
|
||||
{
|
||||
#if VRC_SDK_VRCSDK2
|
||||
var com = obj.GetComponent<VRC_Pickup>();
|
||||
if (com != null) DestroyImmediate(com);
|
||||
#endif
|
||||
}
|
||||
if (isRigidbody)
|
||||
{
|
||||
var com = obj.GetComponent<Rigidbody>();
|
||||
if (com != null) DestroyImmediate(com);
|
||||
}
|
||||
if (isObjectSync)
|
||||
{
|
||||
#if VRC_SDK_VRCSDK2
|
||||
var com = obj.GetComponent<VRC_ObjectSync>();
|
||||
if (com != null) DestroyImmediate(com);
|
||||
#endif
|
||||
}
|
||||
if (isBoxCollider)
|
||||
{
|
||||
var com = obj.GetComponent<BoxCollider>();
|
||||
if (com != null) DestroyImmediate(com);
|
||||
}
|
||||
}
|
||||
|
||||
private void guiRigidbody()
|
||||
{
|
||||
isRigidbody = EditorGUILayout.BeginToggleGroup("Rigidbody", isRigidbody);
|
||||
if (isRigidbody)
|
||||
{
|
||||
useGravityFlag = EditorGUILayout.Toggle("useGravity", useGravityFlag);
|
||||
isKinematicFlag = EditorGUILayout.Toggle("isKinematic", isKinematicFlag);
|
||||
freezePosFlag = EditorGUILayout.Toggle("Freeze Positions", freezePosFlag);
|
||||
freezeRotFlag = EditorGUILayout.Toggle("Freeze Rotations", freezeRotFlag);
|
||||
}
|
||||
EditorGUILayout.EndToggleGroup();
|
||||
}
|
||||
|
||||
private void guiObjectSync()
|
||||
{
|
||||
isObjectSync = EditorGUILayout.BeginToggleGroup("VRC_ObjectSync", isObjectSync);
|
||||
//syncPhysicsFlag = EditorGUILayout.Toggle("Synchronize Physics", syncPhysicsFlag);
|
||||
//collisionTransferFlag = EditorGUILayout.Toggle("Collision Transfer", collisionTransferFlag);
|
||||
#if VRC_SDK_VRCSDK2
|
||||
#else
|
||||
if (isObjectSync)
|
||||
{
|
||||
EditorGUILayout.HelpBox("VRCSDK2をインポートしてください", MessageType.Error);
|
||||
}
|
||||
#endif
|
||||
EditorGUILayout.EndToggleGroup();
|
||||
}
|
||||
|
||||
private void guiPickup()
|
||||
{
|
||||
isPickup = EditorGUILayout.BeginToggleGroup("VRC_Pickup", isPickup);
|
||||
#if VRC_SDK_VRCSDK2
|
||||
#else
|
||||
if (isPickup)
|
||||
{
|
||||
EditorGUILayout.HelpBox("VRCSDK2をインポートしてください", MessageType.Error);
|
||||
}
|
||||
#endif
|
||||
EditorGUILayout.EndToggleGroup();
|
||||
}
|
||||
|
||||
private void guiBoxCollider()
|
||||
{
|
||||
isBoxCollider = EditorGUILayout.BeginToggleGroup("BoxCollider", isBoxCollider);
|
||||
if (isBoxCollider)
|
||||
{
|
||||
isTriggerFlag = EditorGUILayout.Toggle("isTrigger", isTriggerFlag);
|
||||
}
|
||||
EditorGUILayout.EndToggleGroup();
|
||||
}
|
||||
|
||||
private void guiAction()
|
||||
{
|
||||
|
||||
EditorGUI.BeginDisabledGroup(targetObject == null);
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
if (GUILayout.Button("Add/Change Components"))
|
||||
{
|
||||
List<GameObject> objs;
|
||||
|
||||
if (addType == AddType.Current_Children_Only)
|
||||
{
|
||||
objs = getCurrentChildrens(targetObject);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
objs = getAllChildrens(targetObject);
|
||||
}
|
||||
|
||||
foreach (GameObject obj in objs)
|
||||
{
|
||||
AddComponentObject(obj);
|
||||
}
|
||||
}
|
||||
if (GUILayout.Button("Delete Components"))
|
||||
{
|
||||
List<GameObject> objs;
|
||||
|
||||
if (addType == AddType.Current_Children_Only)
|
||||
{
|
||||
objs = getCurrentChildrens(targetObject);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
objs = getAllChildrens(targetObject);
|
||||
}
|
||||
|
||||
foreach (GameObject obj in objs)
|
||||
{
|
||||
DeleteComponentObject(obj);
|
||||
}
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
EditorGUI.EndDisabledGroup();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
12
Assets/External/VRCDeveloperTool/Editor/ComponentAdder/ComponentAdder.cs.meta
vendored
Normal file
12
Assets/External/VRCDeveloperTool/Editor/ComponentAdder/ComponentAdder.cs.meta
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e5f0ce7345f2dcb4b9c8d9a0f1a9de10
|
||||
timeCreated: 1537079080
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
9
Assets/External/VRCDeveloperTool/Editor/HandPoseAdder.meta
vendored
Normal file
9
Assets/External/VRCDeveloperTool/Editor/HandPoseAdder.meta
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 38b7d06e6faf6454ba07c362e80890d1
|
||||
folderAsset: yes
|
||||
timeCreated: 1537791366
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
9
Assets/External/VRCDeveloperTool/Editor/HandPoseAdder/Animations.meta
vendored
Normal file
9
Assets/External/VRCDeveloperTool/Editor/HandPoseAdder/Animations.meta
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d4451bc762558274ea722d45840a70a0
|
||||
folderAsset: yes
|
||||
timeCreated: 1537791379
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
2093
Assets/External/VRCDeveloperTool/Editor/HandPoseAdder/Animations/FingerPoint.anim
vendored
Normal file
2093
Assets/External/VRCDeveloperTool/Editor/HandPoseAdder/Animations/FingerPoint.anim
vendored
Normal file
File diff suppressed because it is too large
Load Diff
9
Assets/External/VRCDeveloperTool/Editor/HandPoseAdder/Animations/FingerPoint.anim.meta
vendored
Normal file
9
Assets/External/VRCDeveloperTool/Editor/HandPoseAdder/Animations/FingerPoint.anim.meta
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3d6aa19a0d34987449b69a30397c0171
|
||||
timeCreated: 1537791431
|
||||
licenseType: Free
|
||||
NativeFormatImporter:
|
||||
mainObjectFileID: 7400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
2093
Assets/External/VRCDeveloperTool/Editor/HandPoseAdder/Animations/Fist.anim
vendored
Normal file
2093
Assets/External/VRCDeveloperTool/Editor/HandPoseAdder/Animations/Fist.anim
vendored
Normal file
File diff suppressed because it is too large
Load Diff
9
Assets/External/VRCDeveloperTool/Editor/HandPoseAdder/Animations/Fist.anim.meta
vendored
Normal file
9
Assets/External/VRCDeveloperTool/Editor/HandPoseAdder/Animations/Fist.anim.meta
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bf1036ae4731baf41b35d98e03686f41
|
||||
timeCreated: 1537791411
|
||||
licenseType: Free
|
||||
NativeFormatImporter:
|
||||
mainObjectFileID: 7400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
2093
Assets/External/VRCDeveloperTool/Editor/HandPoseAdder/Animations/HandGun.anim
vendored
Normal file
2093
Assets/External/VRCDeveloperTool/Editor/HandPoseAdder/Animations/HandGun.anim
vendored
Normal file
File diff suppressed because it is too large
Load Diff
9
Assets/External/VRCDeveloperTool/Editor/HandPoseAdder/Animations/HandGun.anim.meta
vendored
Normal file
9
Assets/External/VRCDeveloperTool/Editor/HandPoseAdder/Animations/HandGun.anim.meta
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ea99b4a464dafa541b7d326a128bb5af
|
||||
timeCreated: 1537791431
|
||||
licenseType: Free
|
||||
NativeFormatImporter:
|
||||
mainObjectFileID: 7400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
2093
Assets/External/VRCDeveloperTool/Editor/HandPoseAdder/Animations/HandOpen.anim
vendored
Normal file
2093
Assets/External/VRCDeveloperTool/Editor/HandPoseAdder/Animations/HandOpen.anim
vendored
Normal file
File diff suppressed because it is too large
Load Diff
9
Assets/External/VRCDeveloperTool/Editor/HandPoseAdder/Animations/HandOpen.anim.meta
vendored
Normal file
9
Assets/External/VRCDeveloperTool/Editor/HandPoseAdder/Animations/HandOpen.anim.meta
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 188c432963af8ea4fab44ea681a8df5d
|
||||
timeCreated: 1537791431
|
||||
licenseType: Free
|
||||
NativeFormatImporter:
|
||||
mainObjectFileID: 7400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
2093
Assets/External/VRCDeveloperTool/Editor/HandPoseAdder/Animations/RocknRoll.anim
vendored
Normal file
2093
Assets/External/VRCDeveloperTool/Editor/HandPoseAdder/Animations/RocknRoll.anim
vendored
Normal file
File diff suppressed because it is too large
Load Diff
9
Assets/External/VRCDeveloperTool/Editor/HandPoseAdder/Animations/RocknRoll.anim.meta
vendored
Normal file
9
Assets/External/VRCDeveloperTool/Editor/HandPoseAdder/Animations/RocknRoll.anim.meta
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d13ab5ba79c432547ab955ad1343f36d
|
||||
timeCreated: 1537791431
|
||||
licenseType: Free
|
||||
NativeFormatImporter:
|
||||
mainObjectFileID: 7400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
2093
Assets/External/VRCDeveloperTool/Editor/HandPoseAdder/Animations/ThumbsUp.anim
vendored
Normal file
2093
Assets/External/VRCDeveloperTool/Editor/HandPoseAdder/Animations/ThumbsUp.anim
vendored
Normal file
File diff suppressed because it is too large
Load Diff
9
Assets/External/VRCDeveloperTool/Editor/HandPoseAdder/Animations/ThumbsUp.anim.meta
vendored
Normal file
9
Assets/External/VRCDeveloperTool/Editor/HandPoseAdder/Animations/ThumbsUp.anim.meta
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fc63fb35bd0032944a05af79bb27fa14
|
||||
timeCreated: 1537791431
|
||||
licenseType: Free
|
||||
NativeFormatImporter:
|
||||
mainObjectFileID: 7400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
2093
Assets/External/VRCDeveloperTool/Editor/HandPoseAdder/Animations/Victory.anim
vendored
Normal file
2093
Assets/External/VRCDeveloperTool/Editor/HandPoseAdder/Animations/Victory.anim
vendored
Normal file
File diff suppressed because it is too large
Load Diff
9
Assets/External/VRCDeveloperTool/Editor/HandPoseAdder/Animations/Victory.anim.meta
vendored
Normal file
9
Assets/External/VRCDeveloperTool/Editor/HandPoseAdder/Animations/Victory.anim.meta
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 445b91c568bfc6e438d551e42d995dca
|
||||
timeCreated: 1537791431
|
||||
licenseType: Free
|
||||
NativeFormatImporter:
|
||||
mainObjectFileID: 7400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
128
Assets/External/VRCDeveloperTool/Editor/HandPoseAdder/HandPoseAdder.cs
vendored
Normal file
128
Assets/External/VRCDeveloperTool/Editor/HandPoseAdder/HandPoseAdder.cs
vendored
Normal file
@ -0,0 +1,128 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
|
||||
// ver 1.2
|
||||
// © 2018-9-24 gatosyocora
|
||||
|
||||
namespace VRCDeveloperTool
|
||||
{
|
||||
|
||||
public class HandPoseAdder : Editor
|
||||
{
|
||||
|
||||
private static string ORIGIN_ANIM_PATH = "Assets/VRCDeveloperTool/Editor/HandPoseAdder/Animations/"; // コピー元となるAnimationファイルが置いてあるディレクトリのパス
|
||||
|
||||
private static readonly string[] HANDNAMES ={"LeftHand.Index", "LeftHand.Little", "LeftHand.Middle", "LeftHand.Ring", "LeftHand.Thumb",
|
||||
"RightHand.Index", "RightHand.Little", "RightHand.Middle", "RightHand.Ring", "RightHand.Thumb"};
|
||||
|
||||
private static readonly string[] HANDPOSTYPES = { "1 Stretched", "2 Stretched", "3 Stretched", "Spread" };
|
||||
|
||||
// None
|
||||
[MenuItem("CONTEXT/Motion/Clear Hand pose", false, 0)]
|
||||
private static void ClearHandAnimationKeys(MenuCommand command)
|
||||
{
|
||||
ClearHandPoseAnimationKeys(command);
|
||||
}
|
||||
|
||||
// FINGER POINT
|
||||
[MenuItem("CONTEXT/Motion/Add Hand pose 'FINGER POINT'", false, 1)]
|
||||
private static void AddFPAnimationKeys(MenuCommand command)
|
||||
{
|
||||
AddHandPoseAnimationKeys(command, ORIGIN_ANIM_PATH + "FingerPoint.anim");
|
||||
}
|
||||
|
||||
// FIST
|
||||
[MenuItem("CONTEXT/Motion/Add Hand pose 'FIST'", false, 2)]
|
||||
private static void AddFISTAnimationKeys(MenuCommand command)
|
||||
{
|
||||
AddHandPoseAnimationKeys(command, ORIGIN_ANIM_PATH + "Fist.anim");
|
||||
}
|
||||
|
||||
// HAND GUN
|
||||
[MenuItem("CONTEXT/Motion/Add Hand pose 'HAND GUN'", false, 3)]
|
||||
private static void AddHGAnimationKeys(MenuCommand command)
|
||||
{
|
||||
AddHandPoseAnimationKeys(command, ORIGIN_ANIM_PATH + "HandGun.anim");
|
||||
}
|
||||
|
||||
// HAND OPEN
|
||||
[MenuItem("CONTEXT/Motion/Add Hand pose 'HAND OPEN'", false, 4)]
|
||||
private static void AddHOAnimationKeys(MenuCommand command)
|
||||
{
|
||||
AddHandPoseAnimationKeys(command, ORIGIN_ANIM_PATH + "HandOpen.anim");
|
||||
}
|
||||
|
||||
// ROCKN ROLL
|
||||
[MenuItem("CONTEXT/Motion/Add Hand pose 'ROCK N ROLL'", false, 5)]
|
||||
private static void AddRRAnimationKeys(MenuCommand command)
|
||||
{
|
||||
AddHandPoseAnimationKeys(command, ORIGIN_ANIM_PATH + "RocknRoll.anim");
|
||||
}
|
||||
|
||||
// THUMBS UP
|
||||
[MenuItem("CONTEXT/Motion/Add Hand pose 'THUMBS UP'", false, 6)]
|
||||
private static void AddTUAnimationKeys(MenuCommand command)
|
||||
{
|
||||
AddHandPoseAnimationKeys(command, ORIGIN_ANIM_PATH + "ThumbsUp.anim");
|
||||
}
|
||||
|
||||
|
||||
// VICTORY
|
||||
[MenuItem("CONTEXT/Motion/Add Hand pose 'VICTORY'", false, 7)]
|
||||
private static void AddVICTORYAnimationKeys(MenuCommand command)
|
||||
{
|
||||
AddHandPoseAnimationKeys(command, ORIGIN_ANIM_PATH + "Victory.anim");
|
||||
}
|
||||
|
||||
// 特定のAnimationファイルのAnimationキー全てをコピーする
|
||||
public static void AddHandPoseAnimationKeys(MenuCommand command, string originPath)
|
||||
{
|
||||
AnimationClip targetClip = command.context as AnimationClip;
|
||||
|
||||
AnimationClip originClip = (AnimationClip)AssetDatabase.LoadAssetAtPath(originPath, typeof(AnimationClip)); // originPathよりAnimationClipの読み込み
|
||||
|
||||
CopyAnimationKeys(originClip, targetClip);
|
||||
}
|
||||
|
||||
// originClipに設定されたAnimationKeyをすべてtargetclipにコピーする
|
||||
public static void CopyAnimationKeys(AnimationClip originClip, AnimationClip targetClip)
|
||||
{
|
||||
foreach (var binding in AnimationUtility.GetCurveBindings(originClip).ToArray())
|
||||
{
|
||||
// AnimationClipよりAnimationCurveを取得
|
||||
AnimationCurve curve = AnimationUtility.GetEditorCurve(originClip, binding);
|
||||
// AnimationClipにキーリダクションを行ったAnimationCurveを設定
|
||||
AnimationUtility.SetEditorCurve(targetClip, binding, curve);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 手の形に関するAnimationキーを全て削除する
|
||||
/// </summary>
|
||||
/// <param name="command"></param>
|
||||
public static void ClearHandPoseAnimationKeys(MenuCommand command)
|
||||
{
|
||||
var targetClip = command.context as AnimationClip;
|
||||
|
||||
foreach (var handname in HANDNAMES)
|
||||
{
|
||||
foreach (var handpostype in HANDPOSTYPES)
|
||||
{
|
||||
var binding = new EditorCurveBinding();
|
||||
binding.path = "";
|
||||
binding.type = typeof(Animator);
|
||||
binding.propertyName = handname + "." + handpostype;
|
||||
|
||||
// キーを削除する
|
||||
AnimationUtility.SetEditorCurve(targetClip, binding, null);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
12
Assets/External/VRCDeveloperTool/Editor/HandPoseAdder/HandPoseAdder.cs.meta
vendored
Normal file
12
Assets/External/VRCDeveloperTool/Editor/HandPoseAdder/HandPoseAdder.cs.meta
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1f784a4681f082c418e5751c74cc50ec
|
||||
timeCreated: 1537770890
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
121
Assets/External/VRCDeveloperTool/Editor/HandPoseAdder/HandPoseSetting.cs
vendored
Normal file
121
Assets/External/VRCDeveloperTool/Editor/HandPoseAdder/HandPoseSetting.cs
vendored
Normal file
@ -0,0 +1,121 @@
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
// ver 1.1
|
||||
// © 2018-9-25 gatosyocora
|
||||
|
||||
namespace VRCDeveloperTool
|
||||
{
|
||||
|
||||
public class HandPoseSetting : EditorWindow
|
||||
{
|
||||
|
||||
private static string EditorPath = "Assets/VRCDeveloperTool/Editor/HandPoseAdder/";
|
||||
|
||||
private static string handPoseName = "";
|
||||
private static AnimationClip handPoseAnimClip = null;
|
||||
|
||||
[MenuItem("VRCDeveloperTool/HandPose Adder Setting")]
|
||||
private static void Create()
|
||||
{
|
||||
loadSettingData();
|
||||
GetWindow<HandPoseSetting>("HandPose Adder Setting");
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
|
||||
EditorGUILayout.PrefixLabel("Custom Hand Pose");
|
||||
|
||||
handPoseName = EditorGUILayout.TextField("Hand Pose Name", handPoseName);
|
||||
|
||||
handPoseAnimClip = EditorGUILayout.ObjectField(
|
||||
"Hand Pose AnimationClip",
|
||||
handPoseAnimClip,
|
||||
typeof(AnimationClip),
|
||||
true
|
||||
) as AnimationClip;
|
||||
|
||||
EditorGUI.BeginDisabledGroup(handPoseName == "" || handPoseAnimClip == null);
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
if (GUILayout.Button("Apply Setting"))
|
||||
{
|
||||
createSettingData(handPoseName, handPoseAnimClip);
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
EditorGUI.EndDisabledGroup();
|
||||
|
||||
EditorGUI.BeginDisabledGroup(!File.Exists(EditorPath + "SettingData.asset") || !File.Exists(EditorPath + "CustomHandPoseAdder.cs"));
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
if (GUILayout.Button("Load Setting"))
|
||||
{
|
||||
loadSettingData();
|
||||
}
|
||||
if (GUILayout.Button("Clear Setting"))
|
||||
{
|
||||
handPoseName = "";
|
||||
handPoseAnimClip = null;
|
||||
ClearSettingData();
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
EditorGUI.EndDisabledGroup();
|
||||
|
||||
}
|
||||
|
||||
// 設定データを保存
|
||||
private static void createSettingData(string name, AnimationClip animClip)
|
||||
{
|
||||
HandPoseSettingData.CreateSettingData(name, animClip);
|
||||
CreateCustomHandPoseAdderScript();
|
||||
}
|
||||
|
||||
// 設定データを読み込み
|
||||
private static void loadSettingData()
|
||||
{
|
||||
HandPoseSettingData settingData = HandPoseSettingData.LoadSettingData();
|
||||
|
||||
if (settingData == null) return;
|
||||
|
||||
handPoseName = settingData.handPoseName;
|
||||
handPoseAnimClip = settingData.handPoseAnimClip;
|
||||
}
|
||||
|
||||
// 追加した手の形のAnimationファイルをコピーするためのスクリプトを作成
|
||||
public static void CreateCustomHandPoseAdderScript()
|
||||
{
|
||||
string scriptAssetPath = EditorPath + "CustomHandPoseAdder.cs";
|
||||
StreamWriter sw = new StreamWriter(scriptAssetPath, false);
|
||||
|
||||
sw.WriteLine("using UnityEngine;");
|
||||
sw.WriteLine("using UnityEditor;");
|
||||
sw.WriteLine("using VRCDeveloperTool;");
|
||||
sw.WriteLine("");
|
||||
sw.WriteLine("// Generated by HandPoseSetting.cs ver 1.1");
|
||||
sw.WriteLine("// © 2018-9-25 gatosyocora");
|
||||
sw.WriteLine("");
|
||||
sw.WriteLine("public class CustomHandPoseAdder : EditorWindow {");
|
||||
|
||||
sw.WriteLine(" [MenuItem(\"CONTEXT/Motion/Add Hand pose '" + handPoseName + "'\", false, 8)]");
|
||||
sw.WriteLine(" private static void AddFPAnimationKeys(MenuCommand command) {");
|
||||
sw.WriteLine(" string animClipPath = \"" + AssetDatabase.GetAssetPath(handPoseAnimClip) + "\";");
|
||||
sw.WriteLine(" HandPoseAdder.AddHandPoseAnimationKeys(command, animClipPath);");
|
||||
sw.WriteLine(" }");
|
||||
|
||||
sw.WriteLine("}");
|
||||
sw.Flush();
|
||||
sw.Close();
|
||||
|
||||
AssetDatabase.ImportAsset(scriptAssetPath);
|
||||
}
|
||||
|
||||
// 設定データを管理するファイルとCustomスクリプトを削除
|
||||
private static void ClearSettingData()
|
||||
{
|
||||
if (File.Exists(EditorPath + "SettingData.asset")) AssetDatabase.DeleteAsset(EditorPath + "SettingData.asset");
|
||||
if (File.Exists(EditorPath + "CustomHandPoseAdder.cs")) AssetDatabase.DeleteAsset(EditorPath + "CustomHandPoseAdder.cs");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
12
Assets/External/VRCDeveloperTool/Editor/HandPoseAdder/HandPoseSetting.cs.meta
vendored
Normal file
12
Assets/External/VRCDeveloperTool/Editor/HandPoseAdder/HandPoseSetting.cs.meta
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 51c6f466a893c0f45b1aa5bc320b341a
|
||||
timeCreated: 1537829968
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
50
Assets/External/VRCDeveloperTool/Editor/HandPoseAdder/HandPoseSettingData.cs
vendored
Normal file
50
Assets/External/VRCDeveloperTool/Editor/HandPoseAdder/HandPoseSettingData.cs
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
// ver 1.1
|
||||
// © 2018-9-25 gatosyocora
|
||||
|
||||
namespace VRCDeveloperTool
|
||||
{
|
||||
|
||||
public class HandPoseSettingData : ScriptableObject
|
||||
{
|
||||
private static string EditorPath = "Assets/VRCDeveloperTool/Editor/HandPoseAdder/";
|
||||
|
||||
/*
|
||||
int handPoseNum = 0;
|
||||
|
||||
struct handPoseData
|
||||
{
|
||||
public string handPoseName;
|
||||
public AnimationClip handPoseAnimClip;
|
||||
}
|
||||
|
||||
List<handPoseData> handPoses;
|
||||
*/
|
||||
|
||||
public string handPoseName; // 手の形の名前
|
||||
|
||||
public AnimationClip handPoseAnimClip; // 手の形のAnimationキーを持つAnimationClip
|
||||
|
||||
// 設定データを保存するファイルを作成
|
||||
public static void CreateSettingData(string name, AnimationClip animClip)
|
||||
{
|
||||
var settingData = CreateInstance<HandPoseSettingData>();
|
||||
settingData.handPoseName = name;
|
||||
settingData.handPoseAnimClip = animClip;
|
||||
|
||||
AssetDatabase.CreateAsset(settingData, EditorPath + "SettingData.asset");
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
|
||||
// 設定データを保存したファイルからデータを読み込み
|
||||
public static HandPoseSettingData LoadSettingData()
|
||||
{
|
||||
var settingData = AssetDatabase.LoadAssetAtPath<HandPoseSettingData>(EditorPath + "SettingData.asset");
|
||||
return settingData;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
12
Assets/External/VRCDeveloperTool/Editor/HandPoseAdder/HandPoseSettingData.cs.meta
vendored
Normal file
12
Assets/External/VRCDeveloperTool/Editor/HandPoseAdder/HandPoseSettingData.cs.meta
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4cc22f6d24d159048837aed82bd0c02b
|
||||
timeCreated: 1537828928
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/External/VRCDeveloperTool/Editor/HumanoidPoseResetter.meta
vendored
Normal file
8
Assets/External/VRCDeveloperTool/Editor/HumanoidPoseResetter.meta
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cbaf9806198075042b23b2457593a9cb
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
81
Assets/External/VRCDeveloperTool/Editor/HumanoidPoseResetter/HumanoidPoseResetter.cs
vendored
Normal file
81
Assets/External/VRCDeveloperTool/Editor/HumanoidPoseResetter/HumanoidPoseResetter.cs
vendored
Normal file
@ -0,0 +1,81 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
// ver 1.2
|
||||
// (c) 2019 gatosyocora
|
||||
|
||||
namespace VRCDeveloperTool
|
||||
{
|
||||
|
||||
public static class HumanoidPoseResetter
|
||||
{
|
||||
|
||||
private static HumanBodyBones[] boneList
|
||||
= {
|
||||
HumanBodyBones.Hips,
|
||||
HumanBodyBones.LeftUpperArm, HumanBodyBones.LeftLowerArm,
|
||||
HumanBodyBones.RightUpperArm, HumanBodyBones.RightLowerArm,
|
||||
HumanBodyBones.LeftUpperLeg, HumanBodyBones.LeftLowerLeg,
|
||||
HumanBodyBones.RightUpperLeg,HumanBodyBones.RightLowerLeg,
|
||||
/*HumanBodyBones.LeftThumbDistal, */HumanBodyBones.LeftThumbIntermediate, HumanBodyBones.LeftThumbProximal,
|
||||
HumanBodyBones.LeftIndexDistal, HumanBodyBones.LeftIndexIntermediate, HumanBodyBones.LeftIndexProximal,
|
||||
HumanBodyBones.LeftMiddleDistal, HumanBodyBones.LeftMiddleIntermediate, HumanBodyBones.LeftMiddleProximal,
|
||||
HumanBodyBones.LeftRingDistal, HumanBodyBones.LeftRingIntermediate, HumanBodyBones.LeftRingProximal,
|
||||
HumanBodyBones.LeftLittleDistal, HumanBodyBones.LeftLittleIntermediate, HumanBodyBones.LeftLittleProximal,
|
||||
/*HumanBodyBones.RightThumbDistal, */HumanBodyBones.RightThumbIntermediate, HumanBodyBones.RightThumbProximal,
|
||||
HumanBodyBones.RightIndexDistal, HumanBodyBones.RightIndexIntermediate, HumanBodyBones.RightIndexProximal,
|
||||
HumanBodyBones.RightMiddleDistal, HumanBodyBones.RightMiddleIntermediate, HumanBodyBones.RightMiddleProximal,
|
||||
HumanBodyBones.RightRingDistal, HumanBodyBones.RightRingIntermediate, HumanBodyBones.RightRingProximal,
|
||||
HumanBodyBones.RightLittleDistal, HumanBodyBones.RightLittleIntermediate, HumanBodyBones.RightLittleProximal
|
||||
};
|
||||
|
||||
public static void ResetPose(GameObject obj)
|
||||
{
|
||||
/* 対象オブジェクトのポーズを取得 */
|
||||
Animator animator = obj.GetComponent<Animator>();
|
||||
if (animator == null) return;
|
||||
|
||||
var sourcePath = AssetDatabase.GetAssetPath(animator.avatar);
|
||||
|
||||
var sourceObj = AssetDatabase.LoadAssetAtPath(sourcePath, typeof(GameObject)) as GameObject;
|
||||
|
||||
var boneTrans = new Transform[boneList.Length];
|
||||
|
||||
for (int i = 0; i < boneList.Length; i++)
|
||||
{
|
||||
boneTrans[i] = animator.GetBoneTransform(boneList[i]);
|
||||
}
|
||||
|
||||
/* 対象オブジェクトの親Prefabのポーズを取得 */
|
||||
Animator sourceAnim = sourceObj.GetComponent<Animator>();
|
||||
if (sourceAnim == null) return;
|
||||
|
||||
var boneTrans_p = new Transform[boneList.Length];
|
||||
|
||||
for (int i = 0; i < boneList.Length; i++)
|
||||
boneTrans_p[i] = sourceAnim.GetBoneTransform(boneList[i]);
|
||||
|
||||
|
||||
for (int j = 0; j < boneList.Length; j++)
|
||||
{
|
||||
var trans = boneTrans[j];
|
||||
var prefabTrans = boneTrans_p[j];
|
||||
|
||||
if (trans == null)
|
||||
{
|
||||
Debug.Log("[Transform not found]:" + j + ":" + boneList[j]);
|
||||
continue;
|
||||
}
|
||||
|
||||
Undo.RecordObject(trans, "Change Transform " + trans.name);
|
||||
|
||||
|
||||
trans.localPosition = prefabTrans.localPosition;
|
||||
trans.localRotation = prefabTrans.localRotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
11
Assets/External/VRCDeveloperTool/Editor/HumanoidPoseResetter/HumanoidPoseResetter.cs.meta
vendored
Normal file
11
Assets/External/VRCDeveloperTool/Editor/HumanoidPoseResetter/HumanoidPoseResetter.cs.meta
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1bdf532e6fe46b148a65d0eae915bc28
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
76
Assets/External/VRCDeveloperTool/Editor/HumanoidPoseResetter/HumanoidPoseResetterEditor.cs
vendored
Normal file
76
Assets/External/VRCDeveloperTool/Editor/HumanoidPoseResetter/HumanoidPoseResetterEditor.cs
vendored
Normal file
@ -0,0 +1,76 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
// ver 1.2
|
||||
// © 2019 gatosyocora
|
||||
|
||||
namespace VRCDeveloperTool
|
||||
{
|
||||
public class HumanoidPoseResetterEditor : EditorWindow
|
||||
{
|
||||
|
||||
private GameObject targetObject = null;
|
||||
|
||||
private static HumanBodyBones[] boneList
|
||||
= {
|
||||
HumanBodyBones.Hips,
|
||||
HumanBodyBones.LeftUpperArm, HumanBodyBones.LeftLowerArm,
|
||||
HumanBodyBones.RightUpperArm, HumanBodyBones.RightLowerArm,
|
||||
HumanBodyBones.LeftUpperLeg, HumanBodyBones.LeftLowerLeg,
|
||||
HumanBodyBones.RightUpperLeg,HumanBodyBones.RightLowerLeg,
|
||||
/*HumanBodyBones.LeftThumbDistal, */HumanBodyBones.LeftThumbIntermediate, HumanBodyBones.LeftThumbProximal,
|
||||
HumanBodyBones.LeftIndexDistal, HumanBodyBones.LeftIndexIntermediate, HumanBodyBones.LeftIndexProximal,
|
||||
HumanBodyBones.LeftMiddleDistal, HumanBodyBones.LeftMiddleIntermediate, HumanBodyBones.LeftMiddleProximal,
|
||||
HumanBodyBones.LeftRingDistal, HumanBodyBones.LeftRingIntermediate, HumanBodyBones.LeftRingProximal,
|
||||
HumanBodyBones.LeftLittleDistal, HumanBodyBones.LeftLittleIntermediate, HumanBodyBones.LeftLittleProximal,
|
||||
/*HumanBodyBones.RightThumbDistal, */HumanBodyBones.RightThumbIntermediate, HumanBodyBones.RightThumbProximal,
|
||||
HumanBodyBones.RightIndexDistal, HumanBodyBones.RightIndexIntermediate, HumanBodyBones.RightIndexProximal,
|
||||
HumanBodyBones.RightMiddleDistal, HumanBodyBones.RightMiddleIntermediate, HumanBodyBones.RightMiddleProximal,
|
||||
HumanBodyBones.RightRingDistal, HumanBodyBones.RightRingIntermediate, HumanBodyBones.RightRingProximal,
|
||||
HumanBodyBones.RightLittleDistal, HumanBodyBones.RightLittleIntermediate, HumanBodyBones.RightLittleProximal
|
||||
};
|
||||
|
||||
[MenuItem("VRCDeveloperTool/HumanoidPose Resetter")]
|
||||
private static void Create()
|
||||
{
|
||||
GetWindow<HumanoidPoseResetterEditor>("HumanoidPose Resetter");
|
||||
}
|
||||
|
||||
[MenuItem("GameObject/VRCDeveloperTool/Reset Pose", false, 20)]
|
||||
public static void ResetPoseFromHierarchy(MenuCommand command)
|
||||
{
|
||||
var obj = command.context as GameObject;
|
||||
HumanoidPoseResetter.ResetPose(obj);
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
targetObject = EditorGUILayout.ObjectField(
|
||||
"TargetObject",
|
||||
targetObject,
|
||||
typeof(GameObject),
|
||||
true
|
||||
) as GameObject;
|
||||
|
||||
GuiAction();
|
||||
|
||||
}
|
||||
|
||||
private void GuiAction()
|
||||
{
|
||||
|
||||
EditorGUI.BeginDisabledGroup(targetObject == null);
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
if (GUILayout.Button("Reset Pose"))
|
||||
{
|
||||
HumanoidPoseResetter.ResetPose(targetObject);
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
EditorGUI.EndDisabledGroup();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
11
Assets/External/VRCDeveloperTool/Editor/HumanoidPoseResetter/HumanoidPoseResetterEditor.cs.meta
vendored
Normal file
11
Assets/External/VRCDeveloperTool/Editor/HumanoidPoseResetter/HumanoidPoseResetterEditor.cs.meta
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c08fbe5f95513a94bb86a4eccef27711
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/External/VRCDeveloperTool/Editor/MeshBoundsSetter.meta
vendored
Normal file
8
Assets/External/VRCDeveloperTool/Editor/MeshBoundsSetter.meta
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 03b40ddbf4e82064b8013d1a4c0712a0
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
128
Assets/External/VRCDeveloperTool/Editor/MeshBoundsSetter/MeshBoundsSetter.cs
vendored
Normal file
128
Assets/External/VRCDeveloperTool/Editor/MeshBoundsSetter/MeshBoundsSetter.cs
vendored
Normal file
@ -0,0 +1,128 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using UnityEditorInternal;
|
||||
|
||||
// ver 1.02
|
||||
// © 2019-2-1 gatosyocora
|
||||
|
||||
namespace VRCDeveloperTool
|
||||
{
|
||||
|
||||
public class MeshBoundsSetter : EditorWindow
|
||||
{
|
||||
|
||||
private GameObject targetObject = null;
|
||||
|
||||
private Vector3 boundsScale = new Vector3(1, 2, 1);
|
||||
|
||||
private List<GameObject> exclusions = new List<GameObject>();
|
||||
|
||||
[MenuItem("VRCDeveloperTool/MeshBounds Setter")]
|
||||
private static void Create()
|
||||
{
|
||||
GetWindow<MeshBoundsSetter>("MeshBounds Setter");
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
targetObject = EditorGUILayout.ObjectField(
|
||||
"TargetObject",
|
||||
targetObject,
|
||||
typeof(GameObject),
|
||||
true
|
||||
) as GameObject;
|
||||
|
||||
boundsScale = EditorGUILayout.Vector3Field("Bounds Scale", boundsScale);
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.LabelField("Exclusions");
|
||||
|
||||
if (GUILayout.Button("+"))
|
||||
{
|
||||
exclusions.Add(null);
|
||||
}
|
||||
if (GUILayout.Button("-"))
|
||||
{
|
||||
if (exclusions.Count > 0)
|
||||
exclusions.RemoveAt(exclusions.Count - 1);
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
for (int i = 0; i < exclusions.Count; i++)
|
||||
{
|
||||
exclusions[i] = EditorGUILayout.ObjectField(
|
||||
"Object " + (i + 1),
|
||||
exclusions[i],
|
||||
typeof(GameObject),
|
||||
true
|
||||
) as GameObject;
|
||||
}
|
||||
|
||||
guiAction();
|
||||
|
||||
}
|
||||
|
||||
private void guiAction()
|
||||
{
|
||||
|
||||
EditorGUI.BeginDisabledGroup(targetObject == null);
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
if (GUILayout.Button("Set Bounds"))
|
||||
{
|
||||
BoundsSetter(targetObject);
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
EditorGUI.EndDisabledGroup();
|
||||
}
|
||||
|
||||
private void BoundsSetter(GameObject parentObj)
|
||||
{
|
||||
var objs = GetAllChildrens(parentObj);
|
||||
|
||||
foreach (var obj in objs)
|
||||
{
|
||||
// 除外リストに含まれていれば処理しない
|
||||
if (exclusions.Contains(obj)) continue;
|
||||
|
||||
var mesh = obj.GetComponent<MeshRenderer>();
|
||||
var skinnedMesh = obj.GetComponent<SkinnedMeshRenderer>();
|
||||
|
||||
if (mesh == null && skinnedMesh == null) continue;
|
||||
|
||||
// Mesh Rendererの場合
|
||||
if (mesh != null)
|
||||
{
|
||||
Undo.RecordObject(mesh, "Change Transform " + mesh.name);
|
||||
}
|
||||
// SkinnedMeshRendererの場合
|
||||
else
|
||||
{
|
||||
Undo.RecordObject(skinnedMesh, "Change Transform " + skinnedMesh.name);
|
||||
|
||||
var objScale = skinnedMesh.gameObject.transform.localScale;
|
||||
var meshBoundsScale = new Vector3(boundsScale.x / objScale.x, boundsScale.y / objScale.y, boundsScale.z / objScale.z);
|
||||
skinnedMesh.localBounds = new Bounds(Vector3.zero, meshBoundsScale);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 指定オブジェクトの子オブジェクト以降をすべて取得する
|
||||
private List<GameObject> GetAllChildrens(GameObject parentObj)
|
||||
{
|
||||
List<GameObject> objs = new List<GameObject>();
|
||||
|
||||
var childTransform = parentObj.GetComponentsInChildren<Transform>();
|
||||
|
||||
foreach (Transform child in childTransform)
|
||||
{
|
||||
objs.Add(child.gameObject);
|
||||
}
|
||||
|
||||
return objs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
11
Assets/External/VRCDeveloperTool/Editor/MeshBoundsSetter/MeshBoundsSetter.cs.meta
vendored
Normal file
11
Assets/External/VRCDeveloperTool/Editor/MeshBoundsSetter/MeshBoundsSetter.cs.meta
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 71aa7b7ed4050f44c84d3ba57de2304a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/External/VRCDeveloperTool/Editor/ProbeAnchorSetter.meta
vendored
Normal file
8
Assets/External/VRCDeveloperTool/Editor/ProbeAnchorSetter.meta
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5d4e191026c25604d8a8f1d8554eca58
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
244
Assets/External/VRCDeveloperTool/Editor/ProbeAnchorSetter/ProbeAnchorSetter.cs
vendored
Normal file
244
Assets/External/VRCDeveloperTool/Editor/ProbeAnchorSetter/ProbeAnchorSetter.cs
vendored
Normal file
@ -0,0 +1,244 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
// ver 1.0
|
||||
// © 2019-2-16 gatosyocora
|
||||
|
||||
namespace VRCDeveloperTool
|
||||
{
|
||||
|
||||
public class ProbeAnchorSetter : EditorWindow
|
||||
{
|
||||
|
||||
private GameObject targetObject = null;
|
||||
|
||||
public enum TARGETPOS
|
||||
{
|
||||
HEAD,
|
||||
CHEST,
|
||||
//ARMATURE,
|
||||
ROOTOBJECT,
|
||||
}
|
||||
|
||||
private TARGETPOS targetPos = TARGETPOS.HEAD;
|
||||
|
||||
private const string TARGETOBJNAME = "Anchor Target";
|
||||
|
||||
private bool isGettingSkinnedMeshRenderer = true;
|
||||
private bool isGettingMeshRenderer = true;
|
||||
|
||||
private bool isOpeningRendererList = false;
|
||||
|
||||
private List<SkinnedMeshRenderer> skinnedMeshList;
|
||||
private List<MeshRenderer> meshList;
|
||||
|
||||
private bool[] isSettingToSkinnedMesh = null;
|
||||
private bool[] isSettingToMesh = null;
|
||||
|
||||
private Vector2 leftScrollPos = Vector2.zero;
|
||||
|
||||
[MenuItem("VRCDeveloperTool/ProbeAnchor Setter")]
|
||||
private static void Create()
|
||||
{
|
||||
GetWindow<ProbeAnchorSetter>("ProbeAnchor Setter");
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
targetObject = EditorGUILayout.ObjectField(
|
||||
"TargetObject",
|
||||
targetObject,
|
||||
typeof(GameObject),
|
||||
true
|
||||
) as GameObject;
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
if (targetObject != null)
|
||||
{
|
||||
skinnedMeshList = GetSkinnedMeshList(targetObject);
|
||||
meshList = GetMeshList(targetObject);
|
||||
isSettingToSkinnedMesh = new bool[skinnedMeshList.Count];
|
||||
for (int i = 0; i < skinnedMeshList.Count; i++) isSettingToSkinnedMesh[i] = true;
|
||||
isSettingToMesh = new bool[meshList.Count];
|
||||
for (int i = 0; i < meshList.Count; i++) isSettingToMesh[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// 設定するRendererの選択
|
||||
isGettingSkinnedMeshRenderer = EditorGUILayout.Toggle("Set To SkinnedMeshRenderer", isGettingSkinnedMeshRenderer);
|
||||
isGettingMeshRenderer = EditorGUILayout.Toggle("Set To MeshRenderer", isGettingMeshRenderer);
|
||||
|
||||
// ライティングの計算の基準とする位置を選択
|
||||
targetPos = (TARGETPOS)EditorGUILayout.EnumPopup("TargetPosition", targetPos);
|
||||
|
||||
// Rendererの一覧を表示
|
||||
if (targetObject != null)
|
||||
{
|
||||
isOpeningRendererList = EditorGUILayout.Foldout(isOpeningRendererList, "Renderer List");
|
||||
|
||||
if (isOpeningRendererList)
|
||||
{
|
||||
leftScrollPos = EditorGUILayout.BeginScrollView(leftScrollPos, GUI.skin.box);
|
||||
{
|
||||
|
||||
EditorGUI.indentLevel++;
|
||||
|
||||
int index = 0;
|
||||
|
||||
if (isGettingSkinnedMeshRenderer)
|
||||
{
|
||||
foreach (var skinnedMesh in skinnedMeshList)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
isSettingToSkinnedMesh[index] = EditorGUILayout.Toggle(skinnedMesh.gameObject.name, isSettingToSkinnedMesh[index]);
|
||||
if (GUILayout.Button("Select"))
|
||||
Selection.activeGameObject = skinnedMesh.gameObject;
|
||||
EditorGUILayout.EndHorizontal();
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
index = 0;
|
||||
|
||||
if (isGettingMeshRenderer)
|
||||
{
|
||||
foreach (var mesh in meshList)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
isSettingToMesh[index] = EditorGUILayout.Toggle(mesh.gameObject.name, isSettingToMesh[index]);
|
||||
if (GUILayout.Button("Select"))
|
||||
Selection.activeGameObject = mesh.gameObject;
|
||||
EditorGUILayout.EndHorizontal();
|
||||
index++;
|
||||
}
|
||||
}
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
EditorGUILayout.EndScrollView();
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUI.BeginDisabledGroup(targetObject == null);
|
||||
if (GUILayout.Button("Set ProbeAnchor"))
|
||||
{
|
||||
SetProbeAnchor(targetObject);
|
||||
}
|
||||
EditorGUI.EndDisabledGroup();
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 特定のオブジェクト以下のRendererのProbeAnchorに設定する
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
private void SetProbeAnchor(GameObject obj)
|
||||
{
|
||||
var animator = obj.GetComponent<Animator>();
|
||||
if (animator == null) return;
|
||||
|
||||
// AnchorTargetを設定する基準の場所を取得
|
||||
Transform targetPosTrans = null;
|
||||
if (targetPos == TARGETPOS.HEAD)
|
||||
{
|
||||
targetPosTrans = animator.GetBoneTransform(HumanBodyBones.Head);
|
||||
}
|
||||
else if (targetPos == TARGETPOS.CHEST)
|
||||
{
|
||||
targetPosTrans = animator.GetBoneTransform(HumanBodyBones.Chest);
|
||||
}
|
||||
/*else if (targetPos == TARGETPOS.ARMATURE)
|
||||
{
|
||||
var hipsTrans = animator.GetBoneTransform(HumanBodyBones.Hips);
|
||||
targetPosTrans = hipsTrans.parent;
|
||||
}*/
|
||||
else if (targetPos == TARGETPOS.ROOTOBJECT)
|
||||
{
|
||||
targetPosTrans = obj.transform;
|
||||
}
|
||||
if (targetPosTrans == null) return;
|
||||
|
||||
// AnchorTargetに設定用のオブジェクトを作成
|
||||
GameObject anchorTargetObj = GameObject.Find(obj.name + "/" + TARGETOBJNAME);
|
||||
if (anchorTargetObj == null)
|
||||
{
|
||||
anchorTargetObj = new GameObject(TARGETOBJNAME);
|
||||
anchorTargetObj.transform.parent = obj.transform;
|
||||
}
|
||||
anchorTargetObj.transform.position = targetPosTrans.position;
|
||||
|
||||
// SkiinedMeshRendererに設定
|
||||
if (isGettingSkinnedMeshRenderer)
|
||||
{
|
||||
int index = 0;
|
||||
var skinnedMeshes = skinnedMeshList;
|
||||
foreach (var skinnedMesh in skinnedMeshes)
|
||||
{
|
||||
if (isSettingToSkinnedMesh[index++])
|
||||
skinnedMesh.probeAnchor = anchorTargetObj.transform;
|
||||
else
|
||||
skinnedMesh.probeAnchor = null;
|
||||
}
|
||||
}
|
||||
|
||||
// MeshRendererに設定
|
||||
if (isGettingMeshRenderer)
|
||||
{
|
||||
int index = 0;
|
||||
var meshes = meshList;
|
||||
foreach (var mesh in meshes)
|
||||
{
|
||||
if (isSettingToMesh[index++])
|
||||
mesh.probeAnchor = anchorTargetObj.transform;
|
||||
else
|
||||
mesh.probeAnchor = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 指定オブジェクト以下のSkinnedMeshRendererのリストを取得する
|
||||
/// </summary>
|
||||
/// <param name="parentObj">親オブジェクト</param>
|
||||
/// <returns>SkinnedMeshRendererのリスト</returns>
|
||||
private List<SkinnedMeshRenderer> GetSkinnedMeshList(GameObject parentObj)
|
||||
{
|
||||
var skinnedMeshList = new List<SkinnedMeshRenderer>();
|
||||
|
||||
var skinnedMeshes = parentObj.GetComponentsInChildren<SkinnedMeshRenderer>(true);
|
||||
|
||||
foreach (var skinnedMesh in skinnedMeshes)
|
||||
{
|
||||
skinnedMeshList.Add(skinnedMesh);
|
||||
}
|
||||
|
||||
return skinnedMeshList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 指定オブジェクト以下のMeshRendererのリストを取得する
|
||||
/// </summary>
|
||||
/// <param name="parentObj">親オブジェクト</param>
|
||||
/// <returns>MeshRendererのリスト</returns>
|
||||
private List<MeshRenderer> GetMeshList(GameObject parentObj)
|
||||
{
|
||||
var meshList = new List<MeshRenderer>();
|
||||
|
||||
var meshes = parentObj.GetComponentsInChildren<MeshRenderer>(true);
|
||||
|
||||
foreach (var mesh in meshes)
|
||||
{
|
||||
meshList.Add(mesh);
|
||||
}
|
||||
|
||||
return meshList;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
11
Assets/External/VRCDeveloperTool/Editor/ProbeAnchorSetter/ProbeAnchorSetter.cs.meta
vendored
Normal file
11
Assets/External/VRCDeveloperTool/Editor/ProbeAnchorSetter/ProbeAnchorSetter.cs.meta
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3d8a4080ea13a5749994d099d4a6149a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/External/VRCDeveloperTool/Editor/ShapeKeyDeleter.meta
vendored
Normal file
8
Assets/External/VRCDeveloperTool/Editor/ShapeKeyDeleter.meta
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 394a8c1a4729a6742a4182a7922497fe
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
165
Assets/External/VRCDeveloperTool/Editor/ShapeKeyDeleter/ShapeKeyDeleter.cs
vendored
Normal file
165
Assets/External/VRCDeveloperTool/Editor/ShapeKeyDeleter/ShapeKeyDeleter.cs
vendored
Normal file
@ -0,0 +1,165 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/External/VRCDeveloperTool/Editor/ShapeKeyDeleter/ShapeKeyDeleter.cs.meta
vendored
Normal file
11
Assets/External/VRCDeveloperTool/Editor/ShapeKeyDeleter/ShapeKeyDeleter.cs.meta
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8a2159ac33f59084e8747b8b2a84b43b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/External/VRCDeveloperTool/Editor/ShapeKeyMixer.meta
vendored
Normal file
8
Assets/External/VRCDeveloperTool/Editor/ShapeKeyMixer.meta
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 64cbfc8dbdbd8b44e9828fd5431afb69
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
186
Assets/External/VRCDeveloperTool/Editor/ShapeKeyMixer/ShapeKeyMixer.cs
vendored
Normal file
186
Assets/External/VRCDeveloperTool/Editor/ShapeKeyMixer/ShapeKeyMixer.cs
vendored
Normal file
@ -0,0 +1,186 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
// ver 1.0
|
||||
// Copyright (c) 2019 gatosyocora
|
||||
|
||||
namespace VRCDeveloperTool
|
||||
{
|
||||
public class ShapeKeyMixer : EditorWindow
|
||||
{
|
||||
private SkinnedMeshRenderer renderer;
|
||||
|
||||
private List<string> shapeKeyNames;
|
||||
private bool[] selectedShapeKeys;
|
||||
private bool isOpenedBlendShape = true;
|
||||
private string combinedShapeKeyName = "";
|
||||
private bool deleteOriginShapeKey = true;
|
||||
private Vector2 shapeKeyScrollPos = Vector2.zero;
|
||||
|
||||
|
||||
[MenuItem("VRCDeveloperTool/Mesh/ShapeKey Mixer")]
|
||||
private static void Open()
|
||||
{
|
||||
GetWindow<ShapeKeyMixer>("ShapeKey Mixer");
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
renderer = null;
|
||||
shapeKeyNames = null;
|
||||
selectedShapeKeys = null;
|
||||
isOpenedBlendShape = true;
|
||||
combinedShapeKeyName = "";
|
||||
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;
|
||||
for (int i = 0; i < shapeKeyNames.Count(); i++)
|
||||
{
|
||||
selectedShapeKeys[i] = EditorGUILayout.ToggleLeft(shapeKeyNames[i], selectedShapeKeys[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
deleteOriginShapeKey = EditorGUILayout.Toggle("Delete Origin ShapeKey", deleteOriginShapeKey);
|
||||
combinedShapeKeyName = EditorGUILayout.TextField("Mixed ShapeKey Name", combinedShapeKeyName);
|
||||
}
|
||||
|
||||
using (new EditorGUI.DisabledScope(renderer == null || combinedShapeKeyName == "" || (selectedShapeKeys != null && selectedShapeKeys.Sum(x => x ? 1 : 0) <= 1)))
|
||||
{
|
||||
if (GUILayout.Button("Mix ShapeKeys"))
|
||||
{
|
||||
// 2つ以上が選択されている
|
||||
if (selectedShapeKeys.Sum(x => x ? 1 : 0) > 1)
|
||||
{
|
||||
// 選択されている要素のインデックスの配列
|
||||
var selectedBlendShapeIndexs = selectedShapeKeys
|
||||
.Select((isSelect, index) => new { Index = index, Value = isSelect })
|
||||
.Where(x => x.Value)
|
||||
.Select(x => x.Index)
|
||||
.ToArray();
|
||||
|
||||
MixShapeKey(renderer, selectedBlendShapeIndexs, combinedShapeKeyName, deleteOriginShapeKey);
|
||||
}
|
||||
|
||||
shapeKeyNames = GetBlendShapeListFromRenderer(renderer);
|
||||
selectedShapeKeys = new bool[shapeKeyNames.Count()];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool MixShapeKey(SkinnedMeshRenderer renderer, int[] selectedShapeKeyIndexs, string combinedBlendShapeName, bool deleteOriginShapeKey)
|
||||
{
|
||||
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;
|
||||
|
||||
var combinedDeltaVertices = new Vector3[mesh.vertexCount];
|
||||
var combinedDeltaNormals = new Vector3[mesh.vertexCount];
|
||||
var combinedDeltaTangents = new Vector3[mesh.vertexCount];
|
||||
float combinedWeight = 0;
|
||||
|
||||
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))
|
||||
{
|
||||
for (int i = 0; i < mesh.vertexCount; i++)
|
||||
{
|
||||
combinedDeltaVertices[i] += deltaVertices[i];
|
||||
combinedDeltaNormals[i] += deltaNormals[i];
|
||||
combinedDeltaTangents[i] += deltaTangents[i];
|
||||
combinedWeight = Mathf.Max(combinedWeight, weight);
|
||||
}
|
||||
|
||||
if (!deleteOriginShapeKey)
|
||||
{
|
||||
shapeKeyName = mesh.GetBlendShapeName(blendShapeIndex);
|
||||
mesh_custom.AddBlendShapeFrame(shapeKeyName, weight, deltaVertices, deltaNormals, deltaTangents);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
shapeKeyName = mesh.GetBlendShapeName(blendShapeIndex);
|
||||
mesh_custom.AddBlendShapeFrame(shapeKeyName, weight, deltaVertices, deltaNormals, deltaTangents);
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedShapeKeyIndexs.Length > 0)
|
||||
mesh_custom.AddBlendShapeFrame(combinedShapeKeyName, combinedWeight, combinedDeltaVertices, combinedDeltaNormals, combinedDeltaTangents);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SkinnedMeshRendererのもつメッシュのシェイプキーの名前のリストを取得する
|
||||
/// </summary>
|
||||
/// <param name="renderer"></param>
|
||||
/// <returns></returns>
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/External/VRCDeveloperTool/Editor/ShapeKeyMixer/ShapeKeyMixer.cs.meta
vendored
Normal file
11
Assets/External/VRCDeveloperTool/Editor/ShapeKeyMixer/ShapeKeyMixer.cs.meta
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9134ffb5949591d44911390f91211dcc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/External/VRCDeveloperTool/Editor/ShapeKeyNameChanger.meta
vendored
Normal file
8
Assets/External/VRCDeveloperTool/Editor/ShapeKeyNameChanger.meta
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 359dd1b9f7cde6c43978974cd33a2a52
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/External/VRCDeveloperTool/Editor/ShapeKeyNameChanger/Resources.meta
vendored
Normal file
8
Assets/External/VRCDeveloperTool/Editor/ShapeKeyNameChanger/Resources.meta
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 608b764bb9c5e1e428df13219c16514b
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1ac7f172661b0a74299f8e583d5c7695
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Assets/External/VRCDeveloperTool/Editor/ShapeKeyNameChanger/Resources/ShapeKeyNameChanger/shapekeynames.json
(Stored with Git LFS)
vendored
Normal file
BIN
Assets/External/VRCDeveloperTool/Editor/ShapeKeyNameChanger/Resources/ShapeKeyNameChanger/shapekeynames.json
(Stored with Git LFS)
vendored
Normal file
Binary file not shown.
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 931bf2795a569b2478bc0b01f922683b
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
269
Assets/External/VRCDeveloperTool/Editor/ShapeKeyNameChanger/ShapeKeyNameChanger.cs
vendored
Normal file
269
Assets/External/VRCDeveloperTool/Editor/ShapeKeyNameChanger/ShapeKeyNameChanger.cs
vendored
Normal file
@ -0,0 +1,269 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/External/VRCDeveloperTool/Editor/ShapeKeyNameChanger/ShapeKeyNameChanger.cs.meta
vendored
Normal file
11
Assets/External/VRCDeveloperTool/Editor/ShapeKeyNameChanger/ShapeKeyNameChanger.cs.meta
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1e5e446425695a2428c640bf776865be
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/External/VRCDeveloperTool/Editor/ShapeKeyReorder.meta
vendored
Normal file
8
Assets/External/VRCDeveloperTool/Editor/ShapeKeyReorder.meta
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 91e09be55fd184f469aadf4c0caf5f89
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
237
Assets/External/VRCDeveloperTool/Editor/ShapeKeyReorder/ShapeKeyReorder.cs
vendored
Normal file
237
Assets/External/VRCDeveloperTool/Editor/ShapeKeyReorder/ShapeKeyReorder.cs
vendored
Normal file
@ -0,0 +1,237 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System.Linq;
|
||||
using UnityEditorInternal;
|
||||
using System.IO;
|
||||
|
||||
// ver 1.00
|
||||
// (C) 2019 gatosyocora
|
||||
|
||||
namespace VRCDeveloperTool
|
||||
{
|
||||
public class ShapeKeyReorder : EditorWindow
|
||||
{
|
||||
private ReorderableList blendShapeReorderableList;
|
||||
private SkinnedMeshRenderer renderer;
|
||||
|
||||
private Vector2 scrollPos = Vector2.zero;
|
||||
|
||||
public class BlendShape
|
||||
{
|
||||
public int index;
|
||||
public string name;
|
||||
|
||||
public BlendShape(int index, string name)
|
||||
{
|
||||
this.index = index;
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
[MenuItem("VRCDeveloperTool/Mesh/ShapeKey Reorder")]
|
||||
private static void Open()
|
||||
{
|
||||
GetWindow<ShapeKeyReorder>("ShapeKey Reorder");
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
renderer = null;
|
||||
blendShapeReorderableList = null;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
var blendShapePairList = new List<BlendShape>();
|
||||
var mesh = renderer.sharedMesh;
|
||||
var blendShapeCount = mesh.blendShapeCount;
|
||||
for (int i = 0; i < blendShapeCount; i++)
|
||||
{
|
||||
blendShapePairList.Add(new BlendShape(i, mesh.GetBlendShapeName(i)));
|
||||
}
|
||||
blendShapeReorderableList = InitializeReorderableList<BlendShape>(blendShapePairList);
|
||||
}
|
||||
else
|
||||
{
|
||||
blendShapeReorderableList = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (blendShapeReorderableList != null)
|
||||
{
|
||||
using (var scroll = new EditorGUILayout.ScrollViewScope(scrollPos))
|
||||
{
|
||||
scrollPos = scroll.scrollPosition;
|
||||
blendShapeReorderableList.DoLayoutList();
|
||||
}
|
||||
}
|
||||
|
||||
using (new EditorGUI.DisabledGroupScope(renderer == null))
|
||||
{
|
||||
EditorGUILayout.LabelField("Auto Sort");
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
if (GUILayout.Button("UnSort"))
|
||||
{
|
||||
blendShapeReorderableList.list
|
||||
= blendShapeReorderableList.list
|
||||
.Cast<BlendShape>()
|
||||
.OrderBy(x => x.index)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
if (GUILayout.Button("VRChat Default"))
|
||||
{
|
||||
blendShapeReorderableList.list
|
||||
= SortByVRChatDefault(
|
||||
blendShapeReorderableList.list as List<BlendShape>
|
||||
);
|
||||
}
|
||||
|
||||
if (GUILayout.Button("A-Z"))
|
||||
{
|
||||
blendShapeReorderableList.list
|
||||
= blendShapeReorderableList.list
|
||||
.Cast<BlendShape>()
|
||||
.OrderBy(x => x.name)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Z-A"))
|
||||
{
|
||||
blendShapeReorderableList.list
|
||||
= blendShapeReorderableList.list
|
||||
.Cast<BlendShape>()
|
||||
.OrderByDescending(x => x.name)
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
if (GUILayout.Button("Change ShapeKey order"))
|
||||
{
|
||||
CreateNewShapeKeyNameMesh(renderer, blendShapeReorderableList.list as List<BlendShape>);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// シェイプキーの順番を変えたメッシュを作成し, SkinnedMeshRendererに設定する
|
||||
/// </summary>
|
||||
/// <param name="renderer">シェイプキーの順番を変更したいメッシュを持つSkinnedMeshRenderer</param>
|
||||
/// <param name="reorderdBlendShapeList">変更後のシェイプキーの名称のリスト</param>
|
||||
/// <returns></returns>
|
||||
private bool CreateNewShapeKeyNameMesh(SkinnedMeshRenderer renderer, List<BlendShape> reorderdBlendShapeList)
|
||||
{
|
||||
var mesh = renderer.sharedMesh;
|
||||
if (mesh == null) return false;
|
||||
|
||||
if (reorderdBlendShapeList.Count != mesh.blendShapeCount) return false;
|
||||
|
||||
var mesh_custom = Object.Instantiate<Mesh>(mesh);
|
||||
|
||||
mesh_custom.ClearBlendShapes();
|
||||
|
||||
var blendShapeIndex = 0;
|
||||
var frameIndex = 0;
|
||||
var shapeKeyName = "";
|
||||
Vector3[] deltaVertices, deltaNormals, deltaTangents;
|
||||
for (int i = 0; i < reorderdBlendShapeList.Count; i++)
|
||||
{
|
||||
deltaVertices = new Vector3[mesh.vertexCount];
|
||||
deltaNormals = new Vector3[mesh.vertexCount];
|
||||
deltaTangents = new Vector3[mesh.vertexCount];
|
||||
|
||||
blendShapeIndex = reorderdBlendShapeList[i].index;
|
||||
|
||||
mesh.GetBlendShapeFrameVertices(blendShapeIndex, frameIndex, deltaVertices, deltaNormals, deltaTangents);
|
||||
var weight = mesh.GetBlendShapeFrameWeight(blendShapeIndex, frameIndex);
|
||||
shapeKeyName = reorderdBlendShapeList[i].name;
|
||||
|
||||
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 + "_reorderd.asset";
|
||||
AssetDatabase.CreateAsset(mesh_custom, AssetDatabase.GenerateUniqueAssetPath(path));
|
||||
AssetDatabase.SaveAssets();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// シェイプキーの順番をVRChat標準のものに変更する
|
||||
/// </summary>
|
||||
/// <param name="list"></param>
|
||||
/// <returns></returns>
|
||||
private List<BlendShape> SortByVRChatDefault(List<BlendShape> list)
|
||||
{
|
||||
var vrcBlendShapes
|
||||
= new string[]{
|
||||
"vrc.blink_left",
|
||||
"vrc.blink_right",
|
||||
"vrc.lowerlid_left",
|
||||
"vrc.lowerlid_right",
|
||||
};
|
||||
|
||||
var newList = new List<BlendShape>();
|
||||
|
||||
for (int i = 0; i < vrcBlendShapes.Length; i++)
|
||||
{
|
||||
var index = list.Select(x => x.name)
|
||||
.ToList()
|
||||
.IndexOf(vrcBlendShapes[i]);
|
||||
|
||||
if (index == -1) continue;
|
||||
|
||||
var blendShape = list[index];
|
||||
list.RemoveAt(index);
|
||||
newList.Add(blendShape);
|
||||
}
|
||||
|
||||
newList.AddRange(list);
|
||||
|
||||
return newList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ReorderableListを作成する
|
||||
/// </summary>
|
||||
/// <param name="list"></param>
|
||||
/// <returns></returns>
|
||||
private ReorderableList InitializeReorderableList<T>(List<T> list)
|
||||
{
|
||||
var reorderbleList = new ReorderableList(list, typeof(T));
|
||||
reorderbleList.drawHeaderCallback = rect => EditorGUI.LabelField(rect, "BlendShape");
|
||||
reorderbleList.drawElementCallback = (rect, index, isActive, isFoused) =>
|
||||
{
|
||||
var item = reorderbleList.list[index] as BlendShape;
|
||||
rect.height = EditorGUIUtility.singleLineHeight;
|
||||
EditorGUI.LabelField(rect, item.name);
|
||||
};
|
||||
reorderbleList.displayAdd = false;
|
||||
reorderbleList.displayRemove = false;
|
||||
|
||||
return reorderbleList;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
11
Assets/External/VRCDeveloperTool/Editor/ShapeKeyReorder/ShapeKeyReorder.cs.meta
vendored
Normal file
11
Assets/External/VRCDeveloperTool/Editor/ShapeKeyReorder/ShapeKeyReorder.cs.meta
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6ed3c5d0ba2f70545b6b5ae60e0ab634
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/External/VRCDeveloperTool/Editor/SubMeshDeleter.meta
vendored
Normal file
8
Assets/External/VRCDeveloperTool/Editor/SubMeshDeleter.meta
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f87b301891c2eab4782b10287033b78b
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
299
Assets/External/VRCDeveloperTool/Editor/SubMeshDeleter/SubMeshDeleter.cs
vendored
Normal file
299
Assets/External/VRCDeveloperTool/Editor/SubMeshDeleter/SubMeshDeleter.cs
vendored
Normal file
@ -0,0 +1,299 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
// ver 1.0.1
|
||||
// Copyright (c) 2019 gatosyocora
|
||||
|
||||
namespace VRCDeveloperTool
|
||||
{
|
||||
public class SubMeshDeleter : EditorWindow
|
||||
{
|
||||
private SkinnedMeshRenderer renderer;
|
||||
private List<SubMeshInfo> subMeshList;
|
||||
private int triangleCount = 0;
|
||||
|
||||
private string saveFolder = "Assets/";
|
||||
private bool isOpenedSubMesh = true;
|
||||
private Vector2 subMeshScrollPos = Vector2.zero;
|
||||
|
||||
[MenuItem("VRCDeveloperTool/Mesh/SubMesh Deleter")]
|
||||
private static void Open()
|
||||
{
|
||||
GetWindow<SubMeshDeleter>("SubMeshDeleter");
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
renderer = null;
|
||||
subMeshList = null;
|
||||
triangleCount = 0;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
var mesh = renderer.sharedMesh;
|
||||
if (mesh != null)
|
||||
{
|
||||
subMeshList = GetSubMeshList(mesh);
|
||||
triangleCount = GetMeshTriangleCount(mesh);
|
||||
saveFolder = GetMeshPath(mesh);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
subMeshList = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (subMeshList != null)
|
||||
{
|
||||
isOpenedSubMesh = EditorGUILayout.Foldout(isOpenedSubMesh, "SubMesh");
|
||||
if (isOpenedSubMesh)
|
||||
{
|
||||
using (var scroll = new EditorGUILayout.ScrollViewScope(subMeshScrollPos))
|
||||
{
|
||||
subMeshScrollPos = scroll.scrollPosition;
|
||||
for (int i = 0; i < subMeshList.Count(); i++)
|
||||
{
|
||||
subMeshList[i].selected = EditorGUILayout.ToggleLeft("subMesh " + (i + 1) + "(" + renderer.sharedMaterials[i].name + "):" + subMeshList[i].triangleCount, subMeshList[i].selected);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
EditorGUILayout.LabelField("Triangle Count", triangleCount+"");
|
||||
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
EditorGUILayout.LabelField("Mesh SaveFolder", saveFolder);
|
||||
|
||||
if (GUILayout.Button("Select Folder", GUILayout.Width(100)))
|
||||
{
|
||||
saveFolder = EditorUtility.OpenFolderPanel("Select saved folder", saveFolder, "");
|
||||
var match = Regex.Match(saveFolder, @"Assets/.*");
|
||||
saveFolder = match.Value + "/";
|
||||
if (saveFolder == "/") saveFolder = "Assets/";
|
||||
}
|
||||
}
|
||||
|
||||
using (new EditorGUI.DisabledGroupScope(subMeshList == null || subMeshList.Count() <= 1))
|
||||
{
|
||||
if (GUILayout.Button("Delete SubMesh"))
|
||||
{
|
||||
DeleteSelectedSubMesh(renderer, subMeshList);
|
||||
|
||||
var mesh = renderer.sharedMesh;
|
||||
if (mesh != null)
|
||||
{
|
||||
subMeshList = GetSubMeshList(mesh);
|
||||
triangleCount = GetMeshTriangleCount(mesh);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 選択中のサブメッシュを削除する
|
||||
/// </summary>
|
||||
/// <param name="renderer"></param>
|
||||
/// <param name="subMeshList"></param>
|
||||
/// <returns></returns>
|
||||
private bool DeleteSelectedSubMesh(SkinnedMeshRenderer renderer, List<SubMeshInfo> subMeshList)
|
||||
{
|
||||
// 削除する頂点インデックスのリスト(読み取り専用, 降順)
|
||||
var deleteVerticesIndicesUniqueDescending
|
||||
= subMeshList
|
||||
.Where(x => x.selected)
|
||||
.SelectMany(x => x.verticesIndices)
|
||||
.Distinct()
|
||||
.OrderByDescending(x => x)
|
||||
.ToList()
|
||||
.AsReadOnly();
|
||||
|
||||
// 削除するサブメッシュのインデックスのリスト
|
||||
var deleteSubMeshIndexList
|
||||
= subMeshList
|
||||
.Select((value, index) => new { Value = value, Index = index })
|
||||
.Where(x => x.Value.selected)
|
||||
.Select(x => x.Index)
|
||||
.ToList()
|
||||
.AsReadOnly();
|
||||
|
||||
var mesh = renderer.sharedMesh;
|
||||
var mesh_custom = Instantiate(mesh);
|
||||
|
||||
mesh_custom.Clear();
|
||||
|
||||
// 頂点を削除
|
||||
var vertices = mesh.vertices.ToList();
|
||||
var boneWeights = mesh.boneWeights.ToList();
|
||||
var uvs = mesh.uv.ToList();
|
||||
var normals = mesh.normals.ToList();
|
||||
var tangents = mesh.tangents.ToList();
|
||||
var uv2s = mesh.uv2.ToList();
|
||||
var uv3s = mesh.uv3.ToList();
|
||||
var uv4s = mesh.uv4.ToList();
|
||||
foreach (var deleteVertexIndex in deleteVerticesIndicesUniqueDescending)
|
||||
{
|
||||
vertices.RemoveAt(deleteVertexIndex);
|
||||
boneWeights.RemoveAt(deleteVertexIndex);
|
||||
normals.RemoveAt(deleteVertexIndex);
|
||||
tangents.RemoveAt(deleteVertexIndex);
|
||||
if (deleteVertexIndex < uvs.Count())
|
||||
uvs.RemoveAt(deleteVertexIndex);
|
||||
if (deleteVertexIndex < uv2s.Count())
|
||||
uv2s.RemoveAt(deleteVertexIndex);
|
||||
if (deleteVertexIndex < uv3s.Count())
|
||||
uv3s.RemoveAt(deleteVertexIndex);
|
||||
if (deleteVertexIndex < uv4s.Count())
|
||||
uv4s.RemoveAt(deleteVertexIndex);
|
||||
}
|
||||
mesh_custom.SetVertices(vertices);
|
||||
mesh_custom.boneWeights = boneWeights.ToArray();
|
||||
mesh_custom.normals = normals.ToArray();
|
||||
mesh_custom.tangents = tangents.ToArray();
|
||||
mesh_custom.SetUVs(0, uvs);
|
||||
mesh_custom.SetUVs(1, uv2s);
|
||||
mesh_custom.SetUVs(2, uv3s);
|
||||
mesh_custom.SetUVs(3, uv4s);
|
||||
|
||||
// サブメッシュごとにポリゴンを処理
|
||||
mesh_custom.subMeshCount = mesh.subMeshCount - deleteSubMeshIndexList.Count();
|
||||
var subMeshNumber = 0;
|
||||
for (int subMeshIndex = 0; subMeshIndex < mesh.subMeshCount; subMeshIndex++)
|
||||
{
|
||||
if (deleteSubMeshIndexList.Contains(subMeshIndex)) continue;
|
||||
|
||||
var subMeshTriangles = mesh.GetTriangles(subMeshIndex);
|
||||
// インデックスがずれるので各頂点への対応付けが必要
|
||||
// インデックスが大きいものから順に処理していく
|
||||
// O(n*m)
|
||||
foreach (var deleteVerticesIndex in deleteVerticesIndicesUniqueDescending) // n
|
||||
for (int i = 0; i < subMeshTriangles.Count(); i++) // m
|
||||
if (subMeshTriangles[i] > deleteVerticesIndex)
|
||||
subMeshTriangles[i]--;
|
||||
mesh_custom.SetTriangles(subMeshTriangles, subMeshNumber++);
|
||||
}
|
||||
|
||||
// BlendShapeを設定する
|
||||
string blendShapeName;
|
||||
float frameWeight;
|
||||
var deltaVertices = new Vector3[mesh.vertexCount];
|
||||
var deltaNormals = new Vector3[mesh.vertexCount];
|
||||
var deltaTangents = new Vector3[mesh.vertexCount];
|
||||
List<Vector3> deltaVerticesList, deltaNormalsList, deltaTangentsList;
|
||||
for (int blendshapeIndex = 0; blendshapeIndex < mesh.blendShapeCount; blendshapeIndex++)
|
||||
{
|
||||
blendShapeName = mesh.GetBlendShapeName(blendshapeIndex);
|
||||
frameWeight = mesh.GetBlendShapeFrameWeight(blendshapeIndex, 0);
|
||||
mesh.GetBlendShapeFrameVertices(blendshapeIndex, 0, deltaVertices, deltaNormals, deltaTangents);
|
||||
deltaVerticesList = deltaVertices.ToList();
|
||||
deltaNormalsList = deltaNormals.ToList();
|
||||
deltaTangentsList = deltaTangents.ToList();
|
||||
foreach (var deleteVertexIndex in deleteVerticesIndicesUniqueDescending)
|
||||
{
|
||||
deltaVerticesList.RemoveAt(deleteVertexIndex);
|
||||
deltaNormalsList.RemoveAt(deleteVertexIndex);
|
||||
deltaTangentsList.RemoveAt(deleteVertexIndex);
|
||||
}
|
||||
mesh_custom.AddBlendShapeFrame(blendShapeName, frameWeight,
|
||||
deltaVerticesList.ToArray(),
|
||||
deltaNormalsList.ToArray(),
|
||||
deltaTangentsList.ToArray());
|
||||
}
|
||||
|
||||
AssetDatabase.CreateAsset(mesh_custom, AssetDatabase.GenerateUniqueAssetPath(saveFolder + mesh.name + "_deleteSubmesh.asset"));
|
||||
AssetDatabase.SaveAssets();
|
||||
|
||||
Undo.RecordObject(renderer, "Change mesh " + mesh_custom.name);
|
||||
renderer.sharedMesh = mesh_custom;
|
||||
|
||||
// 削除したサブメッシュのマテリアルを参照から外す
|
||||
var materials = renderer.sharedMaterials.ToList();
|
||||
for (var index = materials.Count() - 1; index >= 0; index--)
|
||||
if (deleteSubMeshIndexList.Contains(index))
|
||||
materials.RemoveAt(index);
|
||||
renderer.sharedMaterials = materials.ToArray();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// サブメッシュのリストを取得する
|
||||
/// </summary>
|
||||
/// <param name="mesh"></param>
|
||||
/// <returns></returns>
|
||||
private List<SubMeshInfo> GetSubMeshList(Mesh mesh)
|
||||
{
|
||||
List<SubMeshInfo> subMeshList = new List<SubMeshInfo>();
|
||||
|
||||
for (int subMeshIndex = 0; subMeshIndex < mesh.subMeshCount; subMeshIndex++)
|
||||
{
|
||||
var meshInfo = new SubMeshInfo(mesh, subMeshIndex);
|
||||
subMeshList.Add(meshInfo);
|
||||
}
|
||||
|
||||
return subMeshList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Meshのポリゴン数を取得する
|
||||
/// </summary>
|
||||
/// <param name="mesh"></param>
|
||||
/// <returns></returns>
|
||||
private int GetMeshTriangleCount(Mesh mesh)
|
||||
{
|
||||
return mesh.triangles.Length / 3;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// mesh保存先のパスを取得する
|
||||
/// </summary>
|
||||
/// <param name="Mesh"></param>
|
||||
/// <returns></returns>
|
||||
private string GetMeshPath(Mesh mesh)
|
||||
{
|
||||
return Path.GetDirectoryName(AssetDatabase.GetAssetPath(mesh))+"/";
|
||||
}
|
||||
|
||||
public class SubMeshInfo
|
||||
{
|
||||
public int subMeshIndex;
|
||||
public int[] verticesIndices;
|
||||
public int vertexCount;
|
||||
public int triangleCount;
|
||||
public bool selected = false;
|
||||
|
||||
public SubMeshInfo(Mesh mesh, int subMeshIndex)
|
||||
{
|
||||
this.subMeshIndex = subMeshIndex;
|
||||
this.verticesIndices = mesh.GetIndices(subMeshIndex);
|
||||
vertexCount = verticesIndices.Length;
|
||||
triangleCount = mesh.GetTriangles(subMeshIndex).Length / 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/External/VRCDeveloperTool/Editor/SubMeshDeleter/SubMeshDeleter.cs.meta
vendored
Normal file
11
Assets/External/VRCDeveloperTool/Editor/SubMeshDeleter/SubMeshDeleter.cs.meta
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 39615a0c8ecb8ba48b303c82d3524389
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/External/VRCDeveloperTool/Editor/Utilitys.meta
vendored
Normal file
8
Assets/External/VRCDeveloperTool/Editor/Utilitys.meta
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 27ecb87b1ac306e4e840689971bda2a7
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
199
Assets/External/VRCDeveloperTool/Editor/Utilitys/GatoEditorUtility.cs
vendored
Normal file
199
Assets/External/VRCDeveloperTool/Editor/Utilitys/GatoEditorUtility.cs
vendored
Normal file
@ -0,0 +1,199 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Linq;
|
||||
|
||||
// MIT License
|
||||
/*
|
||||
* Copyright 2020 gatosyocora
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
namespace VRCDeveloperTool
|
||||
{
|
||||
public class GatoEditorUtility
|
||||
{
|
||||
private const char BSLASH = '\\';
|
||||
|
||||
/// <summary>
|
||||
/// インデントなしのHelpbox
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="messageType"></param>
|
||||
public static void NonIndentHelpBox(string message, MessageType messageType)
|
||||
{
|
||||
var currentIndentLevel = EditorGUI.indentLevel;
|
||||
EditorGUI.indentLevel = 0;
|
||||
EditorGUILayout.HelpBox(message, messageType);
|
||||
EditorGUI.indentLevel = currentIndentLevel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// インデントなしのButton
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
/// <param name="action"></param>
|
||||
public static void NonIndentButton(string text, Action action)
|
||||
{
|
||||
var currentIndentLevel = EditorGUI.indentLevel;
|
||||
EditorGUI.indentLevel = 0;
|
||||
if (GUILayout.Button(text))
|
||||
{
|
||||
action.Invoke();
|
||||
}
|
||||
EditorGUI.indentLevel = currentIndentLevel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// パス内で存在しないフォルダを作成する
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <returns></returns>
|
||||
public static bool CreateNoExistFolders(string path)
|
||||
{
|
||||
string directoryPath;
|
||||
if (string.IsNullOrEmpty(Path.GetExtension(path)))
|
||||
{
|
||||
directoryPath = path;
|
||||
}
|
||||
else
|
||||
{
|
||||
directoryPath = Path.GetDirectoryName(path);
|
||||
}
|
||||
|
||||
if (!Directory.Exists(directoryPath))
|
||||
{
|
||||
var directories = directoryPath.Split(BSLASH);
|
||||
|
||||
directoryPath = "Assets";
|
||||
for (int i = 1; i < directories.Length; i++)
|
||||
{
|
||||
if (!Directory.Exists(directoryPath + BSLASH + directories[i]))
|
||||
{
|
||||
AssetDatabase.CreateFolder(directoryPath, directories[i]);
|
||||
}
|
||||
|
||||
directoryPath += BSLASH + directories[i];
|
||||
}
|
||||
AssetDatabase.SaveAssets();
|
||||
AssetDatabase.Refresh();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 任意のアセットを複製する
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="newAssetName"></param>
|
||||
/// <param name="saveFolderPath"></param>
|
||||
/// <returns></returns>
|
||||
public static T DuplicateAsset<T>(T source, string newAssetPath) where T : UnityEngine.Object
|
||||
{
|
||||
var sourcePath = AssetDatabase.GetAssetPath(source);
|
||||
return DuplicateAsset<T>(sourcePath, newAssetPath);
|
||||
}
|
||||
|
||||
public static T DuplicateAsset<T>(string sourcePath, string newAssetPath) where T : UnityEngine.Object
|
||||
{
|
||||
var newFolderPath = Path.GetDirectoryName(newAssetPath);
|
||||
CreateNoExistFolders(newFolderPath);
|
||||
var newPath = AssetDatabase.GenerateUniqueAssetPath(newAssetPath);
|
||||
AssetDatabase.CopyAsset(sourcePath, newPath);
|
||||
AssetDatabase.SaveAssets();
|
||||
AssetDatabase.Refresh();
|
||||
|
||||
var newAsset = AssetDatabase.LoadAssetAtPath(newPath, typeof(T)) as T;
|
||||
|
||||
return newAsset;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 最後にキーワードを追加する(重複なし)
|
||||
/// </summary>
|
||||
/// <param name="target"></param>
|
||||
/// <param name="keyword"></param>
|
||||
/// <returns></returns>
|
||||
public static string AddKeywordToEnd(string target, string keyword)
|
||||
{
|
||||
if (string.IsNullOrEmpty(keyword)) return target;
|
||||
|
||||
var normalString = Regex.Replace(target, keyword + ".*", string.Empty);
|
||||
return normalString + keyword;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 特定のオブジェクトから特定のオブジェクトまでのパスを取得する
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetHierarchyPathFromObj1ToObj2(GameObject obj1, GameObject obj2)
|
||||
{
|
||||
string path = obj2.name;
|
||||
var parent = obj2.transform.parent;
|
||||
while (parent != null)
|
||||
{
|
||||
if (parent.gameObject.name == obj1.name) return path;
|
||||
|
||||
path = parent.name + "/" + path;
|
||||
parent = parent.parent;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 特定のオブジェクトまでのパスを取得する
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetHierarchyPath(GameObject obj)
|
||||
{
|
||||
string path = obj.name;
|
||||
Transform parent = obj.transform.parent;
|
||||
while (parent != null)
|
||||
{
|
||||
if (parent.parent == null) return path;
|
||||
|
||||
path = parent.name + "/" + path;
|
||||
parent = parent.parent;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// フォルダ名からフォルダパスを取得する
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetFolderPathFromName(string folderName)
|
||||
{
|
||||
var guid = AssetDatabase.FindAssets(folderName + " t:Folder").FirstOrDefault();
|
||||
return AssetDatabase.GUIDToAssetPath(guid);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 複製された2つのオブジェクト間で片方の特定のTransformに対応したTransformを取得する
|
||||
/// </summary>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="duplicated"></param>
|
||||
/// <param name="target"></param>
|
||||
/// <returns></returns>
|
||||
public static Transform GetCorrespondTransformBetweenDuplicatedObjects(GameObject source, GameObject duplicated, Transform target)
|
||||
{
|
||||
if (source.transform == target) return duplicated.transform;
|
||||
|
||||
var path = GetHierarchyPathFromObj1ToObj2(source, target.gameObject);
|
||||
|
||||
return duplicated.transform.Find(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/External/VRCDeveloperTool/Editor/Utilitys/GatoEditorUtility.cs.meta
vendored
Normal file
11
Assets/External/VRCDeveloperTool/Editor/Utilitys/GatoEditorUtility.cs.meta
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ea831e1b44c1f2e40a8b07d7fcad1be8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/External/VRCDeveloperTool/Editor/VRCAssetCreator.meta
vendored
Normal file
8
Assets/External/VRCDeveloperTool/Editor/VRCAssetCreator.meta
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1d61406e20153444092677a33f354983
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
37
Assets/External/VRCDeveloperTool/Editor/VRCAssetCreator/VRCAssetCreator.cs
vendored
Normal file
37
Assets/External/VRCDeveloperTool/Editor/VRCAssetCreator/VRCAssetCreator.cs
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
|
||||
// ver 1.0
|
||||
// Copyright (c) 2020 gatosyocora
|
||||
|
||||
namespace VRCDeveloperTool
|
||||
{
|
||||
public class VRCAssetCreator : Editor
|
||||
{
|
||||
#if VRC_SDK_VRCSDK2
|
||||
[MenuItem("Assets/Create/VRChat/CustomOverrideController", priority = 0)]
|
||||
public static void CreateVRCCustomOverrideController()
|
||||
{
|
||||
var outputFolderPath = AssetDatabase.GetAssetPath(Selection.activeInstanceID);
|
||||
|
||||
var originalGuid = AssetDatabase.FindAssets("CustomOverrideEmpty").First();
|
||||
var originalPath = AssetDatabase.GUIDToAssetPath(originalGuid);
|
||||
var outputPath = outputFolderPath + "/" + Path.GetFileName(originalPath);
|
||||
DuplicateAsset(originalPath, outputPath);
|
||||
}
|
||||
#endif
|
||||
|
||||
private static void DuplicateAsset(string originalPath, string outputPath)
|
||||
{
|
||||
outputPath = AssetDatabase.GenerateUniqueAssetPath(outputPath);
|
||||
AssetDatabase.CopyAsset(originalPath, outputPath);
|
||||
AssetDatabase.SaveAssets();
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
11
Assets/External/VRCDeveloperTool/Editor/VRCAssetCreator/VRCAssetCreator.cs.meta
vendored
Normal file
11
Assets/External/VRCDeveloperTool/Editor/VRCAssetCreator/VRCAssetCreator.cs.meta
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 99d09038281ca144e87244fd8ff48e42
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/External/VRCDeveloperTool/Editor/VRCAvatarTester.meta
vendored
Normal file
8
Assets/External/VRCDeveloperTool/Editor/VRCAvatarTester.meta
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7ebf40d759e151f4a86f46b6de8580cf
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/External/VRCDeveloperTool/Editor/VRCAvatarTester/Resources.meta
vendored
Normal file
8
Assets/External/VRCDeveloperTool/Editor/VRCAvatarTester/Resources.meta
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d8e14459547668344b92d23570c122e5
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/External/VRCDeveloperTool/Editor/VRCAvatarTester/Resources/Tester.meta
vendored
Normal file
8
Assets/External/VRCDeveloperTool/Editor/VRCAvatarTester/Resources/Tester.meta
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a93d8c7d5fa23224db2d4765580f70d9
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Assets/External/VRCDeveloperTool/Editor/VRCAvatarTester/Resources/Tester/PoseConstrainter.prefab
(Stored with Git LFS)
vendored
Normal file
BIN
Assets/External/VRCDeveloperTool/Editor/VRCAvatarTester/Resources/Tester/PoseConstrainter.prefab
(Stored with Git LFS)
vendored
Normal file
Binary file not shown.
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 595f725aaeb14c74ebbc662992c556b6
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
376
Assets/External/VRCDeveloperTool/Editor/VRCAvatarTester/VRCAvatarTester.cs
vendored
Normal file
376
Assets/External/VRCDeveloperTool/Editor/VRCAvatarTester/VRCAvatarTester.cs
vendored
Normal file
@ -0,0 +1,376 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
using UnityEditor.Animations;
|
||||
using UnityEditor.SceneManagement;
|
||||
#if VRC_SDK_VRCSDK2
|
||||
using VRCSDK2;
|
||||
#endif
|
||||
|
||||
// ver 1.0
|
||||
// Copyright (c) 2020 gatosyocora
|
||||
|
||||
namespace VRCDeveloperTool
|
||||
{
|
||||
public class VRCAvatarTester : EditorWindow
|
||||
{
|
||||
#if VRC_SDK_VRCSDK2
|
||||
private VRC_AvatarDescriptor avatar;
|
||||
#endif
|
||||
[SerializeField]
|
||||
private Animator animator;
|
||||
[SerializeField]
|
||||
private AnimatorOverrideController controller;
|
||||
[SerializeField]
|
||||
private RuntimeAnimatorController defaultController;
|
||||
|
||||
public enum PlayingType
|
||||
{
|
||||
NONE, OVERRIDE, EMOTE
|
||||
};
|
||||
private PlayingType playingType = PlayingType.NONE;
|
||||
public enum PlayingHand
|
||||
{
|
||||
NONE, RIGHT, LEFT, BOTH
|
||||
};
|
||||
private PlayingHand playingHand = PlayingHand.NONE;
|
||||
|
||||
private static readonly string[] OVERRIDES = new string[]
|
||||
{
|
||||
"FIST", "HANDOPEN", "FINGERPOINT", "VICTORY", "ROCKNROLL", "HANDGUN", "THUMBSUP"
|
||||
};
|
||||
|
||||
private static readonly string[] EMOTES = new string[]
|
||||
{
|
||||
"EMOTE1", "EMOTE2", "EMOTE3", "EMOTE4", "EMOTE5", "EMOTE6", "EMOTE7", "EMOTE8"
|
||||
};
|
||||
|
||||
[SerializeField]
|
||||
private GameObject poseConstraintObj;
|
||||
private PoseConstraint poseConstraint;
|
||||
|
||||
[MenuItem("VRCDeveloperTool/VRCAvatarTester")]
|
||||
public static void Open()
|
||||
{
|
||||
GetWindow<VRCAvatarTester>(nameof(VRCAvatarTester));
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
#if VRC_SDK_VRCSDK2
|
||||
// 再生中
|
||||
if (EditorApplication.isPlayingOrWillChangePlaymode)
|
||||
{
|
||||
// 毎回取得しないとActiveへの変更がなぜか適用されない
|
||||
poseConstraint = poseConstraintObj.GetComponent<PoseConstraint>();
|
||||
|
||||
animator.runtimeAnimatorController = controller;
|
||||
if (playingType == PlayingType.OVERRIDE)
|
||||
{
|
||||
poseConstraint.Active = true;
|
||||
animator.SetInteger($"Emote", 0);
|
||||
|
||||
switch (playingHand)
|
||||
{
|
||||
case PlayingHand.NONE:
|
||||
animator.SetLayerWeight(animator.GetLayerIndex("HandLeft"), 0);
|
||||
animator.SetLayerWeight(animator.GetLayerIndex("HandRight"), 0);
|
||||
break;
|
||||
case PlayingHand.RIGHT:
|
||||
animator.SetLayerWeight(animator.GetLayerIndex("HandLeft"), 0);
|
||||
animator.SetLayerWeight(animator.GetLayerIndex("HandRight"), 1);
|
||||
break;
|
||||
case PlayingHand.LEFT:
|
||||
animator.SetLayerWeight(animator.GetLayerIndex("HandLeft"), 1);
|
||||
animator.SetLayerWeight(animator.GetLayerIndex("HandRight"), 0);
|
||||
break;
|
||||
case PlayingHand.BOTH:
|
||||
animator.SetLayerWeight(animator.GetLayerIndex("HandLeft"), 1);
|
||||
animator.SetLayerWeight(animator.GetLayerIndex("HandRight"), 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (playingType == PlayingType.EMOTE)
|
||||
{
|
||||
poseConstraint.Active = false;
|
||||
animator.SetLayerWeight(animator.GetLayerIndex("HandLeft"), 0);
|
||||
animator.SetLayerWeight(animator.GetLayerIndex("HandRight"), 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
poseConstraint.Active = true;
|
||||
animator.SetLayerWeight(animator.GetLayerIndex("HandLeft"), 0);
|
||||
animator.SetLayerWeight(animator.GetLayerIndex("HandRight"), 0);
|
||||
}
|
||||
}
|
||||
// 未再生
|
||||
else
|
||||
{
|
||||
if (animator != null && controller != null)
|
||||
{
|
||||
animator.runtimeAnimatorController = defaultController;
|
||||
animator.SetLayerWeight(animator.GetLayerIndex("HandLeft"), 0);
|
||||
animator.SetLayerWeight(animator.GetLayerIndex("HandRight"), 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
#if VRC_SDK_VRCSDK2
|
||||
using (var check = new EditorGUI.ChangeCheckScope())
|
||||
{
|
||||
avatar = EditorGUILayout.ObjectField("Avatar", avatar, typeof(VRC_AvatarDescriptor), true) as VRC_AvatarDescriptor;
|
||||
|
||||
if (check.changed)
|
||||
{
|
||||
if (avatar != null)
|
||||
{
|
||||
animator = avatar.gameObject.GetComponent<Animator>();
|
||||
controller = avatar.CustomStandingAnims;
|
||||
}
|
||||
else
|
||||
{
|
||||
animator = null;
|
||||
controller = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.LabelField("Camera", EditorStyles.boldLabel);
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
if (GUILayout.Button("Scene View"))
|
||||
{
|
||||
EditorApplication.ExecuteMenuItem("Window/General/Scene");
|
||||
}
|
||||
if (GUILayout.Button("Game View"))
|
||||
{
|
||||
EditorApplication.ExecuteMenuItem("Window/General/Game");
|
||||
}
|
||||
}
|
||||
/*
|
||||
using (new EditorGUI.DisabledGroupScope(animator is null))
|
||||
{
|
||||
if (GUILayout.Button("Focus on Avatar"))
|
||||
{
|
||||
var sceneViewCamera = SceneView.lastActiveSceneView.camera;
|
||||
sceneViewCamera.transform.position = animator.transform.position;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
GUILayout.Space(15);
|
||||
|
||||
EditorGUILayout.LabelField("Testing", EditorStyles.boldLabel);
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
using (new EditorGUI.DisabledGroupScope(EditorApplication.isPlayingOrWillChangePlaymode || avatar == null))
|
||||
{
|
||||
if (GUILayout.Button("Play"))
|
||||
{
|
||||
defaultController = animator.runtimeAnimatorController;
|
||||
animator.runtimeAnimatorController = controller;
|
||||
|
||||
poseConstraintObj = CreatePoseConstrainterToRootIfNeeded();
|
||||
poseConstraint = poseConstraintObj.GetComponent<PoseConstraint>();
|
||||
poseConstraint.UpdateBoneInfo(animator);
|
||||
|
||||
EditorApplication.isPlaying = true;
|
||||
}
|
||||
}
|
||||
using (new EditorGUI.DisabledGroupScope(!EditorApplication.isPlayingOrWillChangePlaymode))
|
||||
{
|
||||
if (GUILayout.Button("Stop"))
|
||||
{
|
||||
EditorApplication.isPlaying = false;
|
||||
animator.runtimeAnimatorController = defaultController;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (avatar == null && !EditorApplication.isPlaying)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Avatarを設定してください", MessageType.Error);
|
||||
}
|
||||
|
||||
if (avatar != null && animator != null && controller != null)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Playを選択するとテストが実行できます", MessageType.Info);
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
using (new EditorGUI.DisabledGroupScope(!EditorApplication.isPlayingOrWillChangePlaymode))
|
||||
{
|
||||
if (GUILayout.Button("Reset All"))
|
||||
{
|
||||
playingType = PlayingType.NONE;
|
||||
playingHand = PlayingHand.NONE;
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.LabelField("AnimationOverrides", EditorStyles.boldLabel);
|
||||
using (new EditorGUI.IndentLevelScope())
|
||||
{
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
EditorGUILayout.LabelField("NONE");
|
||||
if (GUILayout.Button("Left"))
|
||||
{
|
||||
if (playingType == PlayingType.OVERRIDE &&
|
||||
playingHand == PlayingHand.BOTH)
|
||||
{
|
||||
playingHand = PlayingHand.RIGHT;
|
||||
}
|
||||
else
|
||||
{
|
||||
playingType = PlayingType.NONE;
|
||||
}
|
||||
PlayOverride("Left", 0, animator);
|
||||
}
|
||||
if (GUILayout.Button("Right"))
|
||||
{
|
||||
if (playingType == PlayingType.OVERRIDE &&
|
||||
playingHand == PlayingHand.BOTH)
|
||||
{
|
||||
playingHand = PlayingHand.LEFT;
|
||||
}
|
||||
else
|
||||
{
|
||||
playingType = PlayingType.NONE;
|
||||
}
|
||||
PlayOverride("Right", 0, animator);
|
||||
}
|
||||
}
|
||||
for (int overrideNumber = 0; overrideNumber < OVERRIDES.Length; overrideNumber++)
|
||||
{
|
||||
AnimationClip overrideAnimation = null;
|
||||
string overrideName = string.Empty;
|
||||
|
||||
if (controller != null)
|
||||
{
|
||||
overrideAnimation = controller[OVERRIDES[overrideNumber]];
|
||||
|
||||
if (overrideAnimation.name != OVERRIDES[overrideNumber])
|
||||
{
|
||||
overrideName = $"({overrideAnimation.name})";
|
||||
}
|
||||
}
|
||||
|
||||
// AnimationClipとOVERRIDES[overrideNumber]の名前が同じであれば未設定
|
||||
using (new EditorGUI.DisabledGroupScope(controller == null || overrideAnimation.name == OVERRIDES[overrideNumber]))
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
EditorGUILayout.LabelField(OVERRIDES[overrideNumber], overrideName);
|
||||
|
||||
if (GUILayout.Button("Left"))
|
||||
{
|
||||
playingType = PlayingType.OVERRIDE;
|
||||
if (playingHand == PlayingHand.RIGHT ||
|
||||
playingHand == PlayingHand.BOTH)
|
||||
{
|
||||
playingHand = PlayingHand.BOTH;
|
||||
}
|
||||
else
|
||||
{
|
||||
playingHand = PlayingHand.LEFT;
|
||||
}
|
||||
PlayOverride("Left", overrideNumber, animator);
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Right"))
|
||||
{
|
||||
playingType = PlayingType.OVERRIDE;
|
||||
if (playingHand == PlayingHand.LEFT ||
|
||||
playingHand == PlayingHand.BOTH)
|
||||
{
|
||||
playingHand = PlayingHand.BOTH;
|
||||
}
|
||||
else
|
||||
{
|
||||
playingHand = PlayingHand.RIGHT;
|
||||
}
|
||||
PlayOverride("Right", overrideNumber, animator);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
using (new EditorGUI.DisabledGroupScope(!EditorApplication.isPlayingOrWillChangePlaymode))
|
||||
{
|
||||
EditorGUILayout.LabelField("Emotes", EditorStyles.boldLabel);
|
||||
using (new EditorGUI.IndentLevelScope())
|
||||
{
|
||||
for (int emoteNumber = 0; emoteNumber < EMOTES.Length; emoteNumber++)
|
||||
{
|
||||
AnimationClip emoteAnimation = null;
|
||||
string buttonText = EMOTES[emoteNumber];
|
||||
if (controller != null)
|
||||
{
|
||||
emoteAnimation = controller[EMOTES[emoteNumber]];
|
||||
buttonText = emoteAnimation.name;
|
||||
}
|
||||
|
||||
// 取得できるAnimationClipの名前が"EMOTE*"だったら設定されていない
|
||||
using (new EditorGUI.DisabledGroupScope(emoteAnimation == null || emoteAnimation.name == EMOTES[emoteNumber]))
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
EditorGUILayout.LabelField(EMOTES[emoteNumber]);
|
||||
|
||||
if (GUILayout.Button(buttonText) && emoteAnimation != null)
|
||||
{
|
||||
if (animator.GetInteger($"Emote") != 0) return;
|
||||
|
||||
playingType = PlayingType.EMOTE;
|
||||
playingHand = PlayingHand.NONE;
|
||||
PlayEmote(emoteNumber + 1, animator, emoteAnimation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
EditorGUILayout.HelpBox("使用するにはVRCSDK2がプロジェクトにインポートされている必要があります", MessageType.Error);
|
||||
#endif
|
||||
}
|
||||
|
||||
private void PlayOverride(string hand, int overrideNumber, Animator animator)
|
||||
{
|
||||
animator.SetInteger($"HandGesture{hand}", overrideNumber);
|
||||
}
|
||||
|
||||
private async void PlayEmote(int emoteNumber, Animator animator, AnimationClip animationClip)
|
||||
{
|
||||
int waitMilliSecond = (int)(animationClip.length * 1000);
|
||||
if (animationClip == null) waitMilliSecond = 1000;
|
||||
animator.SetInteger($"Emote", emoteNumber);
|
||||
// EmoteAnimationの実行が終わるまで待つ必要がある
|
||||
await Task.Delay(waitMilliSecond);
|
||||
animator.SetInteger($"Emote", 0);
|
||||
}
|
||||
|
||||
private GameObject CreatePoseConstrainterToRootIfNeeded()
|
||||
{
|
||||
var obj = GameObject.Find("PoseConstrainter");
|
||||
if (obj is null)
|
||||
{
|
||||
var prefab = Resources.Load("Tester/PoseConstrainter");
|
||||
obj = PrefabUtility.InstantiatePrefab(prefab) as GameObject;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/External/VRCDeveloperTool/Editor/VRCAvatarTester/VRCAvatarTester.cs.meta
vendored
Normal file
11
Assets/External/VRCDeveloperTool/Editor/VRCAvatarTester/VRCAvatarTester.cs.meta
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ad6a8a6e01f535447b7c5b353726db9a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Assets/External/VRCDeveloperTool/LICENSE.txt
(Stored with Git LFS)
vendored
Normal file
BIN
Assets/External/VRCDeveloperTool/LICENSE.txt
(Stored with Git LFS)
vendored
Normal file
Binary file not shown.
7
Assets/External/VRCDeveloperTool/LICENSE.txt.meta
vendored
Normal file
7
Assets/External/VRCDeveloperTool/LICENSE.txt.meta
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8ab5348371ff39442bb728561d7afefc
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Assets/External/VRCDeveloperTool/README_VRCDeveloperTool.txt
(Stored with Git LFS)
vendored
Normal file
BIN
Assets/External/VRCDeveloperTool/README_VRCDeveloperTool.txt
(Stored with Git LFS)
vendored
Normal file
Binary file not shown.
8
Assets/External/VRCDeveloperTool/README_VRCDeveloperTool.txt.meta
vendored
Normal file
8
Assets/External/VRCDeveloperTool/README_VRCDeveloperTool.txt.meta
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f58d8d4097bd56349ba1953e6c80e2d9
|
||||
timeCreated: 1537082424
|
||||
licenseType: Free
|
||||
TextScriptImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/External/VRCDeveloperTool/ScaleLimitVisualizer.meta
vendored
Normal file
8
Assets/External/VRCDeveloperTool/ScaleLimitVisualizer.meta
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: efb64c83056940b49ab22f22512cc222
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
31
Assets/External/VRCDeveloperTool/ScaleLimitVisualizer/ScaleLimitVisualizer.cs
vendored
Normal file
31
Assets/External/VRCDeveloperTool/ScaleLimitVisualizer/ScaleLimitVisualizer.cs
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
// ver 1.00
|
||||
// © 2019-1-31 gatosyocora
|
||||
|
||||
public class ScaleLimitVisualizer : MonoBehaviour {
|
||||
|
||||
public Vector3 scaleLimit = new Vector3(4, 5, 3);
|
||||
|
||||
public bool isWireFrame = true;
|
||||
|
||||
void OnDrawGizmos()
|
||||
{
|
||||
var pos = transform.position + new Vector3(0, (float)(scaleLimit.y / 2.0), 0);
|
||||
|
||||
if (isWireFrame)
|
||||
{
|
||||
Gizmos.color = Color.yellow;
|
||||
Gizmos.DrawWireCube(pos, scaleLimit);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
Gizmos.color = new Color(1, 1, 0, 0.8f);
|
||||
Gizmos.DrawCube(pos, scaleLimit);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
11
Assets/External/VRCDeveloperTool/ScaleLimitVisualizer/ScaleLimitVisualizer.cs.meta
vendored
Normal file
11
Assets/External/VRCDeveloperTool/ScaleLimitVisualizer/ScaleLimitVisualizer.cs.meta
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5be28f395556f6b47937df98fb2db262
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Assets/External/VRCDeveloperTool/ScaleLimitVisualizer/ScaleLimitVisualizer.prefab
(Stored with Git LFS)
vendored
Normal file
BIN
Assets/External/VRCDeveloperTool/ScaleLimitVisualizer/ScaleLimitVisualizer.prefab
(Stored with Git LFS)
vendored
Normal file
Binary file not shown.
8
Assets/External/VRCDeveloperTool/ScaleLimitVisualizer/ScaleLimitVisualizer.prefab.meta
vendored
Normal file
8
Assets/External/VRCDeveloperTool/ScaleLimitVisualizer/ScaleLimitVisualizer.prefab.meta
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: af0898226daf7164999ceea1e2c8092d
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 100100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/External/VRCDeveloperTool/Scripts.meta
vendored
Normal file
8
Assets/External/VRCDeveloperTool/Scripts.meta
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 76f28943da1e75c4f89da9708fdca076
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
88
Assets/External/VRCDeveloperTool/Scripts/PoseConstraint.cs
vendored
Normal file
88
Assets/External/VRCDeveloperTool/Scripts/PoseConstraint.cs
vendored
Normal file
@ -0,0 +1,88 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace VRCDeveloperTool
|
||||
{
|
||||
public class PoseConstraint : MonoBehaviour
|
||||
{
|
||||
[Serializable]
|
||||
public class BoneInfo
|
||||
{
|
||||
public Transform Transform { get; set; }
|
||||
public Vector3 Position { get; set; }
|
||||
public Quaternion Rotation { get; set; }
|
||||
}
|
||||
|
||||
private List<BoneInfo> boneList;
|
||||
|
||||
public Animator animator;
|
||||
public bool Active = true;
|
||||
|
||||
public void Start()
|
||||
{
|
||||
boneList = GetBoneInfo(animator);
|
||||
Active = true;
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
if (Active && boneList != null) SetBoneInfo(boneList);
|
||||
}
|
||||
|
||||
public void UpdateBoneInfo(Animator animator)
|
||||
{
|
||||
this.animator = animator;
|
||||
#if UNITY_EDITOR
|
||||
EditorUtility.SetDirty(this);
|
||||
#endif
|
||||
boneList = GetBoneInfo(animator);
|
||||
}
|
||||
|
||||
private List<BoneInfo> GetBoneInfo(Animator animator)
|
||||
{
|
||||
return Enum.GetNames(typeof(HumanBodyBones))
|
||||
.Select(boneName =>
|
||||
{
|
||||
if (Enum.TryParse(boneName, out HumanBodyBones bone))
|
||||
{
|
||||
Transform trans;
|
||||
try
|
||||
{
|
||||
trans = animator.GetBoneTransform(bone);
|
||||
}
|
||||
catch (IndexOutOfRangeException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (trans is null) return null;
|
||||
return new BoneInfo
|
||||
{
|
||||
Transform = trans,
|
||||
Position = trans.position,
|
||||
Rotation = trans.rotation
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.Where(x => x != null)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private void SetBoneInfo(List<BoneInfo> boneList)
|
||||
{
|
||||
foreach (var bone in boneList)
|
||||
{
|
||||
bone.Transform.position = bone.Position;
|
||||
bone.Transform.rotation = bone.Rotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/External/VRCDeveloperTool/Scripts/PoseConstraint.cs.meta
vendored
Normal file
11
Assets/External/VRCDeveloperTool/Scripts/PoseConstraint.cs.meta
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ced8b4af24d7fee4e8b95e1c85e26eeb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Loading…
x
Reference in New Issue
Block a user