diff --git a/Assets/VRM10/Editor/Components/Expression/ExpressionEditorHelper.cs b/Assets/VRM10/Editor/Components/Expression/ExpressionEditorHelper.cs index d14f699ed..bfeb668cf 100644 --- a/Assets/VRM10/Editor/Components/Expression/ExpressionEditorHelper.cs +++ b/Assets/VRM10/Editor/Components/Expression/ExpressionEditorHelper.cs @@ -57,7 +57,7 @@ namespace UniVRM10 public static bool FloatSlider(Rect rect, SerializedProperty prop, float maxValue) { var oldValue = prop.floatValue; - var newValue = EditorGUI.Slider(rect, prop.floatValue, 0, 100f); + var newValue = EditorGUI.Slider(rect, prop.floatValue, 0, maxValue); if (newValue != oldValue) { prop.floatValue = newValue; diff --git a/Assets/VRM10/Editor/Components/Expression/ReorderableMorphTargetBindingList.cs b/Assets/VRM10/Editor/Components/Expression/ReorderableMorphTargetBindingList.cs index 5f1bdabe6..98f962115 100644 --- a/Assets/VRM10/Editor/Components/Expression/ReorderableMorphTargetBindingList.cs +++ b/Assets/VRM10/Editor/Components/Expression/ReorderableMorphTargetBindingList.cs @@ -57,7 +57,7 @@ namespace UniVRM10 y += height; rect = new Rect(position.x, y, position.width, height); - if (ExpressionEditorHelper.FloatSlider(rect, property.FindPropertyRelative(nameof(MorphTargetBinding.Weight)), 100)) + if (ExpressionEditorHelper.FloatSlider(rect, property.FindPropertyRelative(nameof(MorphTargetBinding.Weight)), MorphTargetBinding.MAX_WEIGHT)) { changed = true; } diff --git a/Assets/VRM10/Editor/Components/Expression/SerializedExpressionEditor.cs b/Assets/VRM10/Editor/Components/Expression/SerializedExpressionEditor.cs index 249bea2f0..782d355a3 100644 --- a/Assets/VRM10/Editor/Components/Expression/SerializedExpressionEditor.cs +++ b/Assets/VRM10/Editor/Components/Expression/SerializedExpressionEditor.cs @@ -192,11 +192,11 @@ namespace UniVRM10 //EditorGUI.indentLevel += 1; for (int i = 0; i < mesh.blendShapeCount; ++i) { - var src = renderer.GetBlendShapeWeight(i); - var dst = EditorGUILayout.Slider(mesh.GetBlendShapeName(i), src, 0, 100.0f); + var src = renderer.GetBlendShapeWeight(i) * MorphTargetBinding.UNITY_TO_VRM; + var dst = EditorGUILayout.Slider(mesh.GetBlendShapeName(i), src, 0, MorphTargetBinding.MAX_WEIGHT); if (dst != src) { - renderer.SetBlendShapeWeight(i, dst); + renderer.SetBlendShapeWeight(i, dst * MorphTargetBinding.VRM_TO_UNITY); changed = true; } } @@ -210,7 +210,7 @@ namespace UniVRM10 MorphTargetBinding[] GetBindings(out string _maxWeightName) { - var maxWeight = 0.0f; + var maxUnityWeight = 0.0f; var maxWeightName = ""; // weightのついたblendShapeを集める var values = m_items @@ -225,18 +225,18 @@ namespace UniVRM10 { for (int i = 0; i < mesh.blendShapeCount; ++i) { - var weight = x.SkinnedMeshRenderer.GetBlendShapeWeight(i); - if (weight == 0) + var unityWeight = x.SkinnedMeshRenderer.GetBlendShapeWeight(i); + if (unityWeight == 0) { continue; } var name = mesh.GetBlendShapeName(i); - if (weight > maxWeight) + if (unityWeight > maxUnityWeight) { maxWeightName = name; - maxWeight = weight; + maxUnityWeight = unityWeight; } - list.Add(new MorphTargetBinding(relativePath, i, weight)); + list.Add(new MorphTargetBinding(relativePath, i, unityWeight * MorphTargetBinding.UNITY_TO_VRM)); } } return list; diff --git a/Assets/VRM10/Editor/EditorTool/VRM10ExpressionEditorTool.cs b/Assets/VRM10/Editor/EditorTool/VRM10ExpressionEditorTool.cs index 15285914d..2a9cba1e5 100644 --- a/Assets/VRM10/Editor/EditorTool/VRM10ExpressionEditorTool.cs +++ b/Assets/VRM10/Editor/EditorTool/VRM10ExpressionEditorTool.cs @@ -47,6 +47,10 @@ namespace UniVRM10 public override void OnToolGUI(EditorWindow window) { + if (Selection.activeTransform == null) + { + return; + } var root = Selection.activeTransform.GetComponent(); if (root == null) { diff --git a/Assets/VRM10/Runtime/Components/Expression/MorphTargetBinding.cs b/Assets/VRM10/Runtime/Components/Expression/MorphTargetBinding.cs index 6d5fb1c4d..9a4ca77c3 100644 --- a/Assets/VRM10/Runtime/Components/Expression/MorphTargetBinding.cs +++ b/Assets/VRM10/Runtime/Components/Expression/MorphTargetBinding.cs @@ -1,10 +1,23 @@ using System; +using UnityEngine; namespace UniVRM10 { [Serializable] public struct MorphTargetBinding : IEquatable { + /// + /// Unity の BlendShape の値域は 0-100 + /// + public const float VRM_TO_UNITY = 100.0f; + + /// + /// VRM-1.0 の MorphTargetBinding.Weight の値域は 0-1.0 + /// + public const float UNITY_TO_VRM = 0.01f; + + public const float MAX_WEIGHT = 1.0f; + /// /// SkinnedMeshRenderer.BlendShape[Index].Weight を 指し示す。 /// @@ -27,11 +40,15 @@ namespace UniVRM10 /// /// /// - /// 0 to 100 + /// 0 to 1.0 public MorphTargetBinding(string path, int index, float weight) { RelativePath = path; Index = index; + if (weight > MAX_WEIGHT) + { + Debug.LogWarning($"MorphTargetBinding: {weight} > {MAX_WEIGHT}"); + } Weight = weight; } diff --git a/Assets/VRM10/Runtime/Components/Expression/MorphTargetBindingMerger.cs b/Assets/VRM10/Runtime/Components/Expression/MorphTargetBindingMerger.cs index 0606f7fc5..f9758414f 100644 --- a/Assets/VRM10/Runtime/Components/Expression/MorphTargetBindingMerger.cs +++ b/Assets/VRM10/Runtime/Components/Expression/MorphTargetBindingMerger.cs @@ -59,7 +59,13 @@ namespace UniVRM10 { m_morphTargetSetterMap.Add(binding, x => { - target.SetBlendShapeWeight(binding.Index, x); + if (target == null) + { + // recompile in editor ? + return; + } + // VRM-1.0 weight is 0-1 + target.SetBlendShapeWeight(binding.Index, x * MorphTargetBinding.VRM_TO_UNITY); }); } else diff --git a/Assets/VRM10/Runtime/Components/Expression/Preview/PreviewMeshItem.cs b/Assets/VRM10/Runtime/Components/Expression/Preview/PreviewMeshItem.cs index e5a4348ae..913f9cf53 100644 --- a/Assets/VRM10/Runtime/Components/Expression/Preview/PreviewMeshItem.cs +++ b/Assets/VRM10/Runtime/Components/Expression/Preview/PreviewMeshItem.cs @@ -79,7 +79,7 @@ namespace UniVRM10 { if (x.Index >= 0 && x.Index < SkinnedMeshRenderer.sharedMesh.blendShapeCount) { - SkinnedMeshRenderer.SetBlendShapeWeight(x.Index, x.Weight * weight); + SkinnedMeshRenderer.SetBlendShapeWeight(x.Index, x.Weight * weight * MorphTargetBinding.VRM_TO_UNITY); } else { diff --git a/Assets/VRM10/Runtime/IO/ExpressionExtensions.cs b/Assets/VRM10/Runtime/IO/ExpressionExtensions.cs index efba8431b..189c60547 100644 --- a/Assets/VRM10/Runtime/IO/ExpressionExtensions.cs +++ b/Assets/VRM10/Runtime/IO/ExpressionExtensions.cs @@ -13,8 +13,7 @@ namespace UniVRM10 var node = loader.Nodes[libNode].transform; var mesh = loader.Meshes[libNode.MeshGroup]; var relativePath = node.RelativePathFrom(root.transform); - // VRM-1.0 では値域は [0-1.0f] - return new UniVRM10.MorphTargetBinding(relativePath, bind.Index.Value, bind.Weight.Value * 100.0f); + return new UniVRM10.MorphTargetBinding(relativePath, bind.Index.Value, bind.Weight.Value); } public static UniVRM10.MaterialColorBinding? Build10(this MaterialColorBind bind, IReadOnlyList materials) diff --git a/Assets/VRM10/Tests/SerializationTests.cs b/Assets/VRM10/Tests/SerializationTests.cs index 85f0aca51..1b7f2c6de 100644 --- a/Assets/VRM10/Tests/SerializationTests.cs +++ b/Assets/VRM10/Tests/SerializationTests.cs @@ -210,9 +210,14 @@ namespace UniVRM10 { var data = new UniGLTF.Extensions.VRMC_vrm.Expression(); data.OverrideBlink = UniGLTF.Extensions.VRMC_vrm.ExpressionOverrideType.block; + data.MorphTargetBinds = new List{ + new UniGLTF.Extensions.VRMC_vrm.MorphTargetBind{ + Weight=1.0f + } + }; var json = Serialize(data, UniGLTF.Extensions.VRMC_vrm.GltfSerializer.__expressions_Serialize_Custom_ITEM); - Assert.AreEqual($"{{{q}overrideBlink{q}:{q}block{q},{q}overrideLookAt{q}:{q}none{q},{q}overrideMouth{q}:{q}none{q}}}", json); + Assert.AreEqual($"{{{q}morphTargetBinds{q}:[{{{q}weight{q}:1}}],{q}overrideBlink{q}:{q}block{q},{q}overrideLookAt{q}:{q}none{q},{q}overrideMouth{q}:{q}none{q}}}", json); } {