Merge pull request #1877 from ousttrue/feature10/vrm1_editor_setup

[1.0] AddComponent による新規セットアップ関連
This commit is contained in:
ousttrue
2022-10-26 16:04:34 +09:00
committed by GitHub
6 changed files with 185 additions and 41 deletions

View File

@@ -35,15 +35,15 @@ namespace UniGLTF
return path;
}
public static string GetDir(string title, string name)
public static string GetDir(string title, string dir = null)
{
string directory = m_lastExportDir;
string directory = string.IsNullOrEmpty(dir) ? m_lastExportDir : dir;
if (string.IsNullOrEmpty(directory))
{
directory = Directory.GetParent(Application.dataPath).ToString();
}
var path = EditorUtility.SaveFolderPanel(title, directory, name);
var path = EditorUtility.SaveFolderPanel(title, directory, null);
if (!string.IsNullOrEmpty(path))
{
m_lastExportDir = Path.GetDirectoryName(path).Replace("\\", "/");

View File

@@ -173,7 +173,35 @@ namespace UniHumanoid
}
}
static void HorizontalFields(string label, params SerializedProperty[] props)
static int? HorizontalFields(string label, params SerializedProperty[] props)
{
int? changed = default;
try
{
EditorGUILayout.BeginHorizontal();
GUILayout.Label(label, GUILayout.Width(LABEL_WIDTH));
GUILayout.FlexibleSpace();
for (int i = 0; i < props.Length; ++i)
{
var prop = props[i];
var prev = prop.objectReferenceValue;
EditorGUILayout.PropertyField(prop, GUIContent.none, true, GUILayout.MinWidth(100));
if (prev != prop.objectReferenceValue)
{
changed = i;
}
}
}
finally
{
EditorGUILayout.EndHorizontal();
}
return changed;
}
static void FingerFields(string label, params SerializedProperty[] props)
{
try
{
@@ -182,9 +210,15 @@ namespace UniHumanoid
GUILayout.Label(label, GUILayout.Width(LABEL_WIDTH));
GUILayout.FlexibleSpace();
foreach (var prop in props)
for (int i = 0; i < props.Length; ++i)
{
var prop = props[i];
var prev = prop.objectReferenceValue;
EditorGUILayout.PropertyField(prop, GUIContent.none, true, GUILayout.MinWidth(100));
if (prev != prop.objectReferenceValue)
{
SetFirstChildrenIfNull(prop, props.Skip(1).ToArray());
}
}
}
finally
@@ -197,7 +231,7 @@ namespace UniHumanoid
static bool s_legFold;
static bool s_armFold;
static bool s_fingerFold;
static string GetDialogDir(UnityEngine.Object obj)
static string GetDialogDir(GameObject obj)
{
var prefab = PrefabUtility.GetCorrespondingObjectFromSource(obj);
if (prefab == null)
@@ -221,6 +255,62 @@ namespace UniHumanoid
return true;
}
static void SetFirstChildrenIfNull(SerializedProperty start, params SerializedProperty[] children)
{
var parent = start.objectReferenceValue as Transform;
if (parent == null)
{
return;
}
var current = parent;
foreach (var prop in children)
{
if (prop.objectReferenceValue != null)
{
// already assigned. exit
break;
}
if (current.childCount == 0)
{
// no child. exit
break;
}
current = current.GetChild(0);
prop.objectReferenceValue = current;
}
}
static bool PropFieldIsUpdated(SerializedProperty prop)
{
var prev = prop.objectReferenceValue;
EditorGUILayout.PropertyField(prop);
return prop.objectReferenceValue != prev;
}
static void LRProps(params (string Name, SerializedProperty L, SerializedProperty R)[] fields)
{
for (int i = 0; i < fields.Length; ++i)
{
var field = fields[i];
var changed = HorizontalFields(field.Name, field.L, field.R);
if (i == 0)
{
if (changed == 0)
{
// left
SetFirstChildrenIfNull(field.L, fields.Skip(1).Select(x => x.L).ToArray());
}
else if (changed == 1)
{
// right
SetFirstChildrenIfNull(field.R, fields.Skip(1).Select(x => x.R).ToArray());
}
}
}
}
public override void OnInspectorGUI()
{
foreach (var validation in m_target.Validate())
@@ -236,10 +326,16 @@ namespace UniHumanoid
s_spineFold = EditorGUILayout.Foldout(s_spineFold, "Body");
if (s_spineFold)
{
EditorGUILayout.PropertyField(m_Spine);
if (PropFieldIsUpdated(m_Spine))
{
SetFirstChildrenIfNull(m_Spine, m_Chest, m_UpperChest);
}
EditorGUILayout.PropertyField(m_Chest);
EditorGUILayout.PropertyField(m_UpperChest);
EditorGUILayout.PropertyField(m_Neck);
if (PropFieldIsUpdated(m_Neck))
{
SetFirstChildrenIfNull(m_Neck, m_Head);
}
EditorGUILayout.PropertyField(m_Head);
EditorGUILayout.PropertyField(m_Jaw);
HorizontalFields("Eye", m_LeftEye, m_RightEye);
@@ -248,34 +344,38 @@ namespace UniHumanoid
s_legFold = EditorGUILayout.Foldout(s_legFold, "Leg");
if (s_legFold)
{
HorizontalFields("UpperLeg", m_LeftUpperLeg, m_RightUpperLeg);
HorizontalFields("LowerLeg", m_LeftLowerLeg, m_RightLowerLeg);
HorizontalFields("Foot", m_LeftFoot, m_RightFoot);
HorizontalFields("Toes", m_LeftToes, m_RightToes);
LRProps(
("UpperLeg", m_LeftUpperLeg, m_RightUpperLeg),
("LowerLeg", m_LeftLowerLeg, m_RightLowerLeg),
("Foot", m_LeftFoot, m_RightFoot),
("Toes", m_LeftToes, m_RightToes)
);
}
s_armFold = EditorGUILayout.Foldout(s_armFold, "Arm");
if (s_armFold)
{
HorizontalFields("Shoulder", m_LeftShoulder, m_RightShoulder);
HorizontalFields("UpperArm", m_LeftUpperArm, m_RightUpperArm);
HorizontalFields("LowerArm", m_LeftLowerArm, m_RightLowerArm);
HorizontalFields("Hand", m_LeftHand, m_RightHand);
LRProps(
("Shoulder", m_LeftShoulder, m_RightShoulder),
("UpperArm", m_LeftUpperArm, m_RightUpperArm),
("LowerArm", m_LeftLowerArm, m_RightLowerArm),
("Hand", m_LeftHand, m_RightHand)
);
}
s_fingerFold = EditorGUILayout.Foldout(s_fingerFold, "Finger");
if (s_fingerFold)
{
HorizontalFields("LeftThumb", m_LeftThumbProximal, m_LeftThumbIntermediate, m_LeftThumbDistal);
HorizontalFields("LeftIndex", m_LeftIndexProximal, m_LeftIndexIntermediate, m_LeftIndexDistal);
HorizontalFields("LeftMiddle", m_LeftMiddleProximal, m_LeftMiddleIntermediate, m_LeftMiddleDistal);
HorizontalFields("LeftRing", m_LeftRingProximal, m_LeftRingIntermediate, m_LeftRingDistal);
HorizontalFields("LeftLittle", m_LeftLittleProximal, m_LeftLittleIntermediate, m_LeftLittleDistal);
HorizontalFields("RightThumb", m_RightThumbProximal, m_RightThumbIntermediate, m_RightThumbDistal);
HorizontalFields("RightIndex", m_RightIndexProximal, m_RightIndexIntermediate, m_RightIndexDistal);
HorizontalFields("RightMiddle", m_RightMiddleProximal, m_RightMiddleIntermediate, m_RightMiddleDistal);
HorizontalFields("RightRing", m_RightRingProximal, m_RightRingIntermediate, m_RightRingDistal);
HorizontalFields("RightLittle", m_RightLittleProximal, m_RightLittleIntermediate, m_RightLittleDistal);
FingerFields("LeftThumb", m_LeftThumbProximal, m_LeftThumbIntermediate, m_LeftThumbDistal);
FingerFields("LeftIndex", m_LeftIndexProximal, m_LeftIndexIntermediate, m_LeftIndexDistal);
FingerFields("LeftMiddle", m_LeftMiddleProximal, m_LeftMiddleIntermediate, m_LeftMiddleDistal);
FingerFields("LeftRing", m_LeftRingProximal, m_LeftRingIntermediate, m_LeftRingDistal);
FingerFields("LeftLittle", m_LeftLittleProximal, m_LeftLittleIntermediate, m_LeftLittleDistal);
FingerFields("RightThumb", m_RightThumbProximal, m_RightThumbIntermediate, m_RightThumbDistal);
FingerFields("RightIndex", m_RightIndexProximal, m_RightIndexIntermediate, m_RightIndexDistal);
FingerFields("RightMiddle", m_RightMiddleProximal, m_RightMiddleIntermediate, m_RightMiddleDistal);
FingerFields("RightRing", m_RightRingProximal, m_RightRingIntermediate, m_RightRingDistal);
FingerFields("RightLittle", m_RightLittleProximal, m_RightLittleIntermediate, m_RightLittleDistal);
}
serializedObject.ApplyModifiedProperties();
@@ -285,7 +385,7 @@ namespace UniHumanoid
{
var path = EditorUtility.SaveFilePanel(
"Save avatar",
GetDialogDir(m_target),
GetDialogDir(m_target.gameObject),
string.Format("{0}.avatar.asset", serializedObject.targetObject.name),
"asset");
if (TryGetAssetPath(path, out string unityPath))

View File

@@ -8,7 +8,11 @@ namespace UniHumanoid
{
/// <summary>
/// Bone割り当てを保持する。
/// ヒエラルキーのルート(おそらくHipsの親)にアタッチする
/// ヒエラルキーのルートにアタッチする
/// root は以下の条件を満たすべし。
/// * root は 原点に配置、回転なし、スケールなし。
/// * root は Hips の祖先
/// * root の親は null
/// </summary>
[DisallowMultipleComponent]
public class Humanoid : MonoBehaviour

View File

@@ -13,7 +13,7 @@ namespace UniVRM10
const string SaveTitle = "New folder for vrm-1.0 assets...";
static string[] SaveExtensions = new string[] { "asset" };
static VRM10Object CreateAsset(string path, Dictionary<ExpressionPreset, VRM10Expression> expressions)
static VRM10Object CreateAsset(string path, Dictionary<ExpressionPreset, VRM10Expression> expressions, Vrm10Instance instance)
{
if (string.IsNullOrEmpty(path))
{
@@ -27,6 +27,8 @@ namespace UniVRM10
}
var asset = ScriptableObject.CreateInstance<VRM10Object>();
asset.Prefab = PrefabUtility.GetCorrespondingObjectFromOriginalSource(instance?.gameObject);
foreach (var kv in expressions)
{
switch (kv.Key)
@@ -104,10 +106,12 @@ namespace UniVRM10
return true;
}
static VRM10Expression CreateAndSaveExpression(ExpressionPreset preset, string dir)
static VRM10Expression CreateAndSaveExpression(ExpressionPreset preset, string dir, Vrm10Instance instance)
{
var prefab = PrefabUtility.GetCorrespondingObjectFromOriginalSource(instance.gameObject);
var clip = ScriptableObject.CreateInstance<VRM10Expression>();
clip.name = preset.ToString();
clip.Prefab = prefab;
var path = System.IO.Path.Combine(dir, $"{preset}.asset");
var unityPath = UnityPath.FromFullpath(path);
unityPath.CreateAsset(clip);
@@ -115,6 +119,21 @@ namespace UniVRM10
return loaded;
}
static string GetSaveName(Vrm10Instance instance)
{
if (instance == null)
{
return "Assets/vrm-1.0.assets";
}
if (VRMShaders.PathObject.TryGetFromAsset(instance, out var asset))
{
return (asset.Parent.Child(instance.name + ".asset")).UnityAssetPath;
}
return $"Assets/{instance.name}.assets";
}
void SetupVRM10Object(Vrm10Instance instance)
{
if (!CheckHumanoid(instance.gameObject))
@@ -124,10 +143,17 @@ namespace UniVRM10
}
EditorGUILayout.HelpBox("Humanoid OK.", MessageType.Info);
if (GUILayout.Button("Create new VRM10Object"))
// VRM10Object
var prop = serializedObject.FindProperty(nameof(Vrm10Instance.Vrm));
if (prop.objectReferenceValue == null)
{
var saveName = (instance.name ?? "vrm-1.0");
var dir = SaveFileDialog.GetDir(SaveTitle, saveName);
EditorGUILayout.HelpBox("No VRM10Object.", MessageType.Error);
}
if (GUILayout.Button("Create new VRM10Object and default Expressions. select target folder"))
{
var saveName = GetSaveName(instance);
var dir = SaveFileDialog.GetDir(SaveTitle, System.IO.Path.GetDirectoryName(saveName));
if (!string.IsNullOrEmpty(dir))
{
var expressions = new Dictionary<ExpressionPreset, VRM10Expression>();
@@ -137,16 +163,15 @@ namespace UniVRM10
{
continue;
}
expressions[expression] = CreateAndSaveExpression(expression, dir);
expressions[expression] = CreateAndSaveExpression(expression, dir, instance);
}
var path = System.IO.Path.Combine(dir, (instance.name ?? "VRMObject") + ".asset");
var asset = CreateAsset(path, expressions);
var asset = CreateAsset(path, expressions, instance);
if (asset != null)
{
// update editor
serializedObject.Update();
var prop = serializedObject.FindProperty(nameof(Vrm10Instance.Vrm));
prop.objectReferenceValue = asset;
serializedObject.ApplyModifiedProperties();
}

View File

@@ -92,6 +92,13 @@ namespace UniVRM10
void Start()
{
if (Vrm == null)
{
Debug.LogError("no VRM10Object");
enabled = false;
return;
}
// cause new Vrm10Runtime.
// init LookAt init rotation.
var runtime = Runtime;

View File

@@ -161,14 +161,22 @@ namespace VRMShaders
}
var assetPath = AssetDatabase.GetAssetPath(src);
if (string.IsNullOrEmpty(assetPath))
if (!string.IsNullOrEmpty(assetPath))
{
dst = default;
return false;
dst = FromUnityAssetPath(assetPath);
return true;
}
dst = FromUnityAssetPath(assetPath);
return true;
var prefab = PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(src);
if (!string.IsNullOrEmpty(prefab))
{
dst = FromUnityAssetPath(prefab);
return true;
}
dst = default;
return false;
}
public void ImportAsset()