From fbae0d857f73d9ce3b2a19c88967e725f0ce380d Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Thu, 22 Jan 2026 01:34:43 +0530 Subject: [PATCH 01/15] Fix MToon material importers ignoring custom shader --- .../Import/Materials/BuiltInVrm10MToonMaterialImporter.cs | 2 +- .../URP/Import/Materials/UrpVrm10MToonMaterialImporter.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Packages/VRM10/Runtime/IO/Material/BuiltInRP/Import/Materials/BuiltInVrm10MToonMaterialImporter.cs b/Packages/VRM10/Runtime/IO/Material/BuiltInRP/Import/Materials/BuiltInVrm10MToonMaterialImporter.cs index 6fba92303..1a4f62fec 100644 --- a/Packages/VRM10/Runtime/IO/Material/BuiltInRP/Import/Materials/BuiltInVrm10MToonMaterialImporter.cs +++ b/Packages/VRM10/Runtime/IO/Material/BuiltInRP/Import/Materials/BuiltInVrm10MToonMaterialImporter.cs @@ -44,7 +44,7 @@ namespace UniVRM10 // use material.name, because material name may renamed in GltfParser. matDesc = new MaterialDescriptor( m.name, - Shader.Find(MToon10Meta.UnityShaderName), + Shader, null, Vrm10MToonTextureImporter.EnumerateAllTextures(data, m, mtoon).ToDictionary(tuple => tuple.key, tuple => tuple.Item2.Item2), TryGetAllFloats(m, mtoon).ToDictionary(tuple => tuple.key, tuple => tuple.value), diff --git a/Packages/VRM10/Runtime/IO/Material/URP/Import/Materials/UrpVrm10MToonMaterialImporter.cs b/Packages/VRM10/Runtime/IO/Material/URP/Import/Materials/UrpVrm10MToonMaterialImporter.cs index ada10ec84..24eb37478 100644 --- a/Packages/VRM10/Runtime/IO/Material/URP/Import/Materials/UrpVrm10MToonMaterialImporter.cs +++ b/Packages/VRM10/Runtime/IO/Material/URP/Import/Materials/UrpVrm10MToonMaterialImporter.cs @@ -39,7 +39,7 @@ namespace UniVRM10 // use material.name, because material name may renamed in GltfParser. matDesc = new MaterialDescriptor( m.name, - Shader.Find(MToon10Meta.UnityUrpShaderName), + Shader, null, Vrm10MToonTextureImporter.EnumerateAllTextures(data, m, mtoon).ToDictionary(tuple => tuple.key, tuple => tuple.Item2.Item2), BuiltInVrm10MToonMaterialImporter.TryGetAllFloats(m, mtoon).ToDictionary(tuple => tuple.key, tuple => tuple.value), From 635e2a6b2df20ed55264af28f4697812811debd6 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Fri, 23 Jan 2026 14:49:02 +0900 Subject: [PATCH 02/15] BoneTransformBindingMerger --- .../Expression/BoneTransformMerger.cs | 25 +++++++++++++++++++ .../Expression/BoneTransformMerger.cs.meta | 11 ++++++++ .../Components/Expression/ExpressionMerger.cs | 4 +++ 3 files changed, 40 insertions(+) create mode 100644 Packages/VRM10/Runtime/Components/Expression/BoneTransformMerger.cs create mode 100644 Packages/VRM10/Runtime/Components/Expression/BoneTransformMerger.cs.meta diff --git a/Packages/VRM10/Runtime/Components/Expression/BoneTransformMerger.cs b/Packages/VRM10/Runtime/Components/Expression/BoneTransformMerger.cs new file mode 100644 index 000000000..64134e6e6 --- /dev/null +++ b/Packages/VRM10/Runtime/Components/Expression/BoneTransformMerger.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + + +namespace UniVRM10 +{ + internal sealed class BoneTransformBindingMerger + { + public BoneTransformBindingMerger(Transform root) + { + + } + + public void Apply() + { + throw new NotImplementedException(); + } + + public void AccumulateValue(VRM10Expression clip, float value) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/Packages/VRM10/Runtime/Components/Expression/BoneTransformMerger.cs.meta b/Packages/VRM10/Runtime/Components/Expression/BoneTransformMerger.cs.meta new file mode 100644 index 000000000..1e48344b2 --- /dev/null +++ b/Packages/VRM10/Runtime/Components/Expression/BoneTransformMerger.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fe2bf5e71647b0f4d93ca6c22bb9fb7f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/VRM10/Runtime/Components/Expression/ExpressionMerger.cs b/Packages/VRM10/Runtime/Components/Expression/ExpressionMerger.cs index dd54cb70d..45664fed4 100644 --- a/Packages/VRM10/Runtime/Components/Expression/ExpressionMerger.cs +++ b/Packages/VRM10/Runtime/Components/Expression/ExpressionMerger.cs @@ -23,6 +23,7 @@ namespace UniVRM10 MorphTargetBindingMerger m_morphTargetBindingMerger; MaterialValueBindingMerger m_materialValueBindingMerger; + BoneTransformBindingMerger m_boneTransformBindingMerger; public ExpressionMerger(VRM10ObjectExpression expressions, Transform root, bool isPrefabInstance) @@ -35,6 +36,7 @@ namespace UniVRM10 m_valueMap = new Dictionary(ExpressionKey.Comparer); m_morphTargetBindingMerger = new MorphTargetBindingMerger(m_clipMap, root); m_materialValueBindingMerger = new MaterialValueBindingMerger(m_clipMap, root, isPrefabInstance); + m_boneTransformBindingMerger = new BoneTransformBindingMerger(root); } /// @@ -50,6 +52,7 @@ namespace UniVRM10 m_morphTargetBindingMerger.Apply(); m_materialValueBindingMerger.Apply(); + m_boneTransformBindingMerger.Apply(); } private void AccumulateValue(ExpressionKey key, float value) @@ -69,6 +72,7 @@ namespace UniVRM10 m_morphTargetBindingMerger.AccumulateValue(key, value); m_materialValueBindingMerger.AccumulateValue(clip, value); + m_boneTransformBindingMerger.AccumulateValue(clip, value); } public void Dispose() From 38b636e417badf3b066c42e3c6c78ac31fad37bd Mon Sep 17 00:00:00 2001 From: ousttrue Date: Fri, 23 Jan 2026 21:45:29 +0900 Subject: [PATCH 03/15] Vrm10BoneTransfromExpression --- .../Expression/BoneTransformMerger.cs | 27 ++++++++++++++----- .../Components/Expression/ExpressionMerger.cs | 2 +- .../Vrm10BoneTransformExpression.cs | 19 +++++++++++++ .../Vrm10BoneTransformExpression.cs.meta | 11 ++++++++ 4 files changed, 51 insertions(+), 8 deletions(-) create mode 100644 Packages/VRM10/Runtime/Components/Expression/Vrm10BoneTransformExpression.cs create mode 100644 Packages/VRM10/Runtime/Components/Expression/Vrm10BoneTransformExpression.cs.meta diff --git a/Packages/VRM10/Runtime/Components/Expression/BoneTransformMerger.cs b/Packages/VRM10/Runtime/Components/Expression/BoneTransformMerger.cs index 64134e6e6..4bd642973 100644 --- a/Packages/VRM10/Runtime/Components/Expression/BoneTransformMerger.cs +++ b/Packages/VRM10/Runtime/Components/Expression/BoneTransformMerger.cs @@ -1,5 +1,5 @@ -using System; using System.Collections.Generic; +using UniGLTF; using UnityEngine; @@ -7,19 +7,32 @@ namespace UniVRM10 { internal sealed class BoneTransformBindingMerger { + Dictionary _acum = new(); + // Vrm10BoneTransformExpression[] _expressions; + Transform _root; + public BoneTransformBindingMerger(Transform root) { + // _expressions = root.GetComponentsInChildren(); + _root = root; + } + public void AccumulateValue(ExpressionKey key, float value) + { + _acum[key] = value; } public void Apply() { - throw new NotImplementedException(); - } - - public void AccumulateValue(VRM10Expression clip, float value) - { - throw new NotImplementedException(); + foreach (var expression in _root.GetComponentsInChildren()) + { + var transform = expression.transform; + var tr = expression.Expression.Transformation; + var m = Matrix4x4.TRS(tr.Translation, tr.Rotation, Vector3.one); + var w = m * transform.localToWorldMatrix; + var (t, r, s) = w.Decompose(); + transform.SetPositionAndRotation(t, r); + } } } } \ No newline at end of file diff --git a/Packages/VRM10/Runtime/Components/Expression/ExpressionMerger.cs b/Packages/VRM10/Runtime/Components/Expression/ExpressionMerger.cs index 45664fed4..d28bc2521 100644 --- a/Packages/VRM10/Runtime/Components/Expression/ExpressionMerger.cs +++ b/Packages/VRM10/Runtime/Components/Expression/ExpressionMerger.cs @@ -72,7 +72,7 @@ namespace UniVRM10 m_morphTargetBindingMerger.AccumulateValue(key, value); m_materialValueBindingMerger.AccumulateValue(clip, value); - m_boneTransformBindingMerger.AccumulateValue(clip, value); + m_boneTransformBindingMerger.AccumulateValue(key, value); } public void Dispose() diff --git a/Packages/VRM10/Runtime/Components/Expression/Vrm10BoneTransformExpression.cs b/Packages/VRM10/Runtime/Components/Expression/Vrm10BoneTransformExpression.cs new file mode 100644 index 000000000..9c7f55ec6 --- /dev/null +++ b/Packages/VRM10/Runtime/Components/Expression/Vrm10BoneTransformExpression.cs @@ -0,0 +1,19 @@ +using System; +using UniGLTF.Utils; +using UnityEngine; + +namespace UniVRM10 +{ + [DisallowMultipleComponent] + public class Vrm10BoneTransformExpression : MonoBehaviour + { + [Serializable] + public class BoneTransformExpression + { + public ExpressionPreset Preset; + public EuclideanTransform Transformation = new EuclideanTransform(Quaternion.identity, Vector3.zero); + } + + public BoneTransformExpression Expression; + } +} \ No newline at end of file diff --git a/Packages/VRM10/Runtime/Components/Expression/Vrm10BoneTransformExpression.cs.meta b/Packages/VRM10/Runtime/Components/Expression/Vrm10BoneTransformExpression.cs.meta new file mode 100644 index 000000000..1622ca50d --- /dev/null +++ b/Packages/VRM10/Runtime/Components/Expression/Vrm10BoneTransformExpression.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1520687d88c34af4eb8c16bb37ee0391 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From aa90bcc85417083e2b537c165d9d9f98bc370792 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Mon, 26 Jan 2026 15:26:25 +0900 Subject: [PATCH 04/15] SetLocalPositionAndRotation --- .../Expression/BoneTransformMerger.cs | 17 ++++++++++------- .../Components/Expression/ExpressionMerger.cs | 5 +++-- .../Expression/Vrm10BoneTransformExpression.cs | 7 +++++-- .../Components/Vrm10Runtime/Vrm10Runtime.cs | 2 +- .../Vrm10Runtime/Vrm10RuntimeExpression.cs | 10 ++++++---- 5 files changed, 25 insertions(+), 16 deletions(-) diff --git a/Packages/VRM10/Runtime/Components/Expression/BoneTransformMerger.cs b/Packages/VRM10/Runtime/Components/Expression/BoneTransformMerger.cs index 4bd642973..114edf0c5 100644 --- a/Packages/VRM10/Runtime/Components/Expression/BoneTransformMerger.cs +++ b/Packages/VRM10/Runtime/Components/Expression/BoneTransformMerger.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using UniGLTF; +using UniGLTF.Utils; using UnityEngine; @@ -22,16 +23,18 @@ namespace UniVRM10 _acum[key] = value; } - public void Apply() + public void Apply(IReadOnlyDictionary initPose) { foreach (var expression in _root.GetComponentsInChildren()) { - var transform = expression.transform; - var tr = expression.Expression.Transformation; - var m = Matrix4x4.TRS(tr.Translation, tr.Rotation, Vector3.one); - var w = m * transform.localToWorldMatrix; - var (t, r, s) = w.Decompose(); - transform.SetPositionAndRotation(t, r); + if (initPose.TryGetValue(expression.transform, out var init)) + { + var weight = _acum.GetValueOrDefault(expression.Expression.ExpressionKey, 0); + expression.transform.SetLocalPositionAndRotation( + init.LocalPosition + expression.Expression.Translation * weight, + Quaternion.Slerp(init.LocalRotation, init.LocalRotation * expression.Expression.Rotation, weight) + ); + } } } } diff --git a/Packages/VRM10/Runtime/Components/Expression/ExpressionMerger.cs b/Packages/VRM10/Runtime/Components/Expression/ExpressionMerger.cs index d28bc2521..4d85995f5 100644 --- a/Packages/VRM10/Runtime/Components/Expression/ExpressionMerger.cs +++ b/Packages/VRM10/Runtime/Components/Expression/ExpressionMerger.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using UniGLTF.Utils; using UnityEngine; namespace UniVRM10 @@ -43,7 +44,7 @@ namespace UniVRM10 /// まとめて反映する。1フレームに1回呼び出されることを想定 /// /// - public void SetValues(Dictionary expressionWeights) + public void SetValues(Dictionary expressionWeights, IReadOnlyDictionary initPose) { foreach (var (key, weight) in expressionWeights) { @@ -52,7 +53,7 @@ namespace UniVRM10 m_morphTargetBindingMerger.Apply(); m_materialValueBindingMerger.Apply(); - m_boneTransformBindingMerger.Apply(); + m_boneTransformBindingMerger.Apply(initPose); } private void AccumulateValue(ExpressionKey key, float value) diff --git a/Packages/VRM10/Runtime/Components/Expression/Vrm10BoneTransformExpression.cs b/Packages/VRM10/Runtime/Components/Expression/Vrm10BoneTransformExpression.cs index 9c7f55ec6..1f33be137 100644 --- a/Packages/VRM10/Runtime/Components/Expression/Vrm10BoneTransformExpression.cs +++ b/Packages/VRM10/Runtime/Components/Expression/Vrm10BoneTransformExpression.cs @@ -10,8 +10,11 @@ namespace UniVRM10 [Serializable] public class BoneTransformExpression { - public ExpressionPreset Preset; - public EuclideanTransform Transformation = new EuclideanTransform(Quaternion.identity, Vector3.zero); + public ExpressionPreset Preset = ExpressionPreset.custom; + public string Name = "custom"; + public ExpressionKey ExpressionKey => new(Preset, Name); + public Quaternion Rotation = Quaternion.identity; + public Vector3 Translation = Vector3.zero; } public BoneTransformExpression Expression; diff --git a/Packages/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs b/Packages/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs index e702496b1..46429762e 100644 --- a/Packages/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs +++ b/Packages/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs @@ -153,7 +153,7 @@ namespace UniVRM10 // 5. Apply Expression // LookAt の角度制限などはこちらで処理されます。 - Expression.Process(eyeDirection); + Expression.Process(eyeDirection, _initPose); // 6. SpringBone SpringBone.Process(Time.deltaTime); diff --git a/Packages/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeExpression.cs b/Packages/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeExpression.cs index 0a38b0481..276735700 100644 --- a/Packages/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeExpression.cs +++ b/Packages/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeExpression.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; using System.Linq; +using UniGLTF.Utils; +using UnityEngine; namespace UniVRM10 { @@ -58,9 +60,9 @@ namespace UniVRM10 _eyeDirectionApplicable = null; } - internal void Process(LookAtEyeDirection inputEyeDirection) + internal void Process(LookAtEyeDirection inputEyeDirection, IReadOnlyDictionary initPose = null) { - Apply(inputEyeDirection); + Apply(inputEyeDirection, initPose); } public IDictionary GetWeights() @@ -112,7 +114,7 @@ namespace UniVRM10 /// 入力 Weight を基に、Validation を行い実際にモデルに適用される Weights を計算し、Merger を介して適用する。 /// この際、LookAt の情報を pull してそれも適用する。 /// - private void Apply(LookAtEyeDirection inputEyeDirection) + private void Apply(LookAtEyeDirection inputEyeDirection, IReadOnlyDictionary initPose) { // 1. Validate user input, and Output as actual weights. _validator.Validate(_inputWeights, _actualWeights, @@ -123,7 +125,7 @@ namespace UniVRM10 _eyeDirectionApplicable?.Apply(_actualEyeDirection, _actualWeights); // 3. Set actual weights to raw blendshapes. - _merger.SetValues(_actualWeights); + _merger.SetValues(_actualWeights, initPose); BlinkOverrideRate = blink; LookAtOverrideRate = lookAt; From 1e84c70bc2d0e50d5d46409cd4ee188463b5a608 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 5 Feb 2026 15:10:43 +0900 Subject: [PATCH 05/15] generate Format/ExpressionsNodeTransform --- .../VRM10/Editor/Vrm10SerializerGenerator.cs | 11 +- .../Format/ExpressionsNodeTransform.meta | 8 + .../Deserializer.g.cs | 145 ++++++++++++++++++ .../Deserializer.g.cs.meta | 11 ++ .../ExpressionsNodeTransform/Format.g.cs | 43 ++++++ .../ExpressionsNodeTransform/Format.g.cs.meta | 11 ++ .../ExpressionsNodeTransform/Serializer.g.cs | 141 +++++++++++++++++ .../Serializer.g.cs.meta | 11 ++ .../Format/SpringBoneLimit/Format.g.cs | 4 +- 9 files changed, 382 insertions(+), 3 deletions(-) create mode 100644 Packages/VRM10/Runtime/Format/ExpressionsNodeTransform.meta create mode 100644 Packages/VRM10/Runtime/Format/ExpressionsNodeTransform/Deserializer.g.cs create mode 100644 Packages/VRM10/Runtime/Format/ExpressionsNodeTransform/Deserializer.g.cs.meta create mode 100644 Packages/VRM10/Runtime/Format/ExpressionsNodeTransform/Format.g.cs create mode 100644 Packages/VRM10/Runtime/Format/ExpressionsNodeTransform/Format.g.cs.meta create mode 100644 Packages/VRM10/Runtime/Format/ExpressionsNodeTransform/Serializer.g.cs create mode 100644 Packages/VRM10/Runtime/Format/ExpressionsNodeTransform/Serializer.g.cs.meta diff --git a/Packages/VRM10/Editor/Vrm10SerializerGenerator.cs b/Packages/VRM10/Editor/Vrm10SerializerGenerator.cs index ec5b753d9..cd3b24015 100644 --- a/Packages/VRM10/Editor/Vrm10SerializerGenerator.cs +++ b/Packages/VRM10/Editor/Vrm10SerializerGenerator.cs @@ -36,6 +36,7 @@ namespace UniVRM10 private const string Vrm10SpecDir = "vrm-specification/specification"; private const string Vrm10FormatGeneratedDir = "Packages/VRM10/Runtime/Format"; + private const string UniGltfFormatGeneratedDir = "Packages/UniGLTF/Runtime/UniGLTF/Format"; public static void Run(bool debug) { @@ -48,7 +49,7 @@ namespace UniVRM10 // VRMC_hdr_emissiveMultiplier new GenerateInfo( $"{Vrm10SpecDir}/VRMC_materials_hdr_emissiveMultiplier-1.0/schema/VRMC_materials_hdr_emissiveMultiplier.json", - "Assets/UniGLTF/Runtime/UniGLTF/Format/ExtensionsAndExtras/EmissiveMultiplier" + $"{UniGltfFormatGeneratedDir}/ExtensionsAndExtras/EmissiveMultiplier" ), // VRMC_vrm @@ -94,6 +95,14 @@ namespace UniVRM10 $"{Vrm10SpecDir}/VRMC_springBone_limit-1.0/schema/VRMC_springBone_limit.schema.json", $"{Vrm10FormatGeneratedDir}/SpringBoneLimit" ), + + // VRMC_vrm_expressions_node_transform-1.0 + // (experimental) + // https://github.com/ousttrue/vrm-specification/tree/VRMC_vrm_expression_joint + new GenerateInfo( + $"{Vrm10SpecDir}/VRMC_vrm_expressions_node_transform-1.0/schema/VRMC_vrm_expressions_node_transform.schema.json", + $"{Vrm10FormatGeneratedDir}/ExpressionsNodeTransform" + ), }; foreach (var arg in args) diff --git a/Packages/VRM10/Runtime/Format/ExpressionsNodeTransform.meta b/Packages/VRM10/Runtime/Format/ExpressionsNodeTransform.meta new file mode 100644 index 000000000..e63834052 --- /dev/null +++ b/Packages/VRM10/Runtime/Format/ExpressionsNodeTransform.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d80842db26fe76645bf195c10b9c6bf7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/VRM10/Runtime/Format/ExpressionsNodeTransform/Deserializer.g.cs b/Packages/VRM10/Runtime/Format/ExpressionsNodeTransform/Deserializer.g.cs new file mode 100644 index 000000000..dfa8a3469 --- /dev/null +++ b/Packages/VRM10/Runtime/Format/ExpressionsNodeTransform/Deserializer.g.cs @@ -0,0 +1,145 @@ +// This file is generated from JsonSchema. Don't modify this source code. +using UniJSON; +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace UniGLTF.Extensions.VRMC_vrm_expressions_node_transform { + +public static class GltfDeserializer +{ + public static readonly Utf8String ExtensionNameUtf8 = Utf8String.From(VRMC_vrm_expressions_node_transform.ExtensionName); + +public static bool TryGet(UniGLTF.glTFExtension src, out VRMC_vrm_expressions_node_transform extension) +{ + if(src is UniGLTF.glTFExtensionImport extensions) + { + foreach(var kv in extensions.ObjectItems()) + { + if(kv.Key.GetUtf8String() == ExtensionNameUtf8) + { + extension = Deserialize(kv.Value); + return true; + } + } + } + + extension = default; + return false; +} + + +public static VRMC_vrm_expressions_node_transform Deserialize(JsonNode parsed) +{ + var value = new VRMC_vrm_expressions_node_transform(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="nodeTransformBinds"){ + value.NodeTransformBinds = Deserialize_NodeTransformBinds(kv.Value); + continue; + } + + } + return value; +} + +public static List Deserialize_NodeTransformBinds(JsonNode parsed) +{ + var value = new List(); + foreach(var x in parsed.ArrayItems()) + { + value.Add(Deserialize_NodeTransformBinds_ITEM(x)); + } + return value; +} + +public static NodeTransformBind Deserialize_NodeTransformBinds_ITEM(JsonNode parsed) +{ + var value = new NodeTransformBind(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="extensions"){ + value.Extensions = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="extras"){ + value.Extras = new glTFExtensionImport(kv.Value); + continue; + } + + if(key=="node"){ + value.Node = kv.Value.GetInt32(); + continue; + } + + if(key=="rotation"){ + value.Rotation = __nodeTransformBinds_ITEM_Deserialize_Rotation(kv.Value); + continue; + } + + if(key=="scale"){ + value.Scale = __nodeTransformBinds_ITEM_Deserialize_Scale(kv.Value); + continue; + } + + if(key=="translation"){ + value.Translation = __nodeTransformBinds_ITEM_Deserialize_Translation(kv.Value); + continue; + } + + } + return value; +} + +public static float[] __nodeTransformBinds_ITEM_Deserialize_Rotation(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static float[] __nodeTransformBinds_ITEM_Deserialize_Scale(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +public static float[] __nodeTransformBinds_ITEM_Deserialize_Translation(JsonNode parsed) +{ + var value = new float[parsed.GetArrayCount()]; + int i=0; + foreach(var x in parsed.ArrayItems()) + { + value[i++] = x.GetSingle(); + } + return value; +} + +} // GltfDeserializer +} // UniGLTF diff --git a/Packages/VRM10/Runtime/Format/ExpressionsNodeTransform/Deserializer.g.cs.meta b/Packages/VRM10/Runtime/Format/ExpressionsNodeTransform/Deserializer.g.cs.meta new file mode 100644 index 000000000..4d946ab7e --- /dev/null +++ b/Packages/VRM10/Runtime/Format/ExpressionsNodeTransform/Deserializer.g.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0a0544899292fe54e961d98e2f7d755c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/VRM10/Runtime/Format/ExpressionsNodeTransform/Format.g.cs b/Packages/VRM10/Runtime/Format/ExpressionsNodeTransform/Format.g.cs new file mode 100644 index 000000000..48421d4b1 --- /dev/null +++ b/Packages/VRM10/Runtime/Format/ExpressionsNodeTransform/Format.g.cs @@ -0,0 +1,43 @@ +// This file is generated from JsonSchema. Don't modify this source code. +using System; +using System.Collections.Generic; + + +namespace UniGLTF.Extensions.VRMC_vrm_expressions_node_transform +{ + + public class NodeTransformBind + { + // Dictionary object with extension-specific objects. + public object Extensions; + + // Application-specific data. + public object Extras; + + // The node index. + public int? Node; + + // The node's unit quaternion rotation in the order (x, y, z, w), where w is the scalar. + public float[] Rotation; + + // The node's non-uniform scale, given as the scaling factors along the x, y, and z axes. + public float[] Scale; + + // The node's translation along the x, y, and z axes. + public float[] Translation; + } + + public class VRMC_vrm_expressions_node_transform + { + public const string ExtensionName = "VRMC_vrm_expressions_node_transform"; + + // Dictionary object with extension-specific objects. + public object Extensions; + + // Application-specific data. + public object Extras; + + // Specify a node transform + public List NodeTransformBinds; + } +} diff --git a/Packages/VRM10/Runtime/Format/ExpressionsNodeTransform/Format.g.cs.meta b/Packages/VRM10/Runtime/Format/ExpressionsNodeTransform/Format.g.cs.meta new file mode 100644 index 000000000..311817f13 --- /dev/null +++ b/Packages/VRM10/Runtime/Format/ExpressionsNodeTransform/Format.g.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3f6d0369358084249b383bea969b16a6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/VRM10/Runtime/Format/ExpressionsNodeTransform/Serializer.g.cs b/Packages/VRM10/Runtime/Format/ExpressionsNodeTransform/Serializer.g.cs new file mode 100644 index 000000000..a3f38a515 --- /dev/null +++ b/Packages/VRM10/Runtime/Format/ExpressionsNodeTransform/Serializer.g.cs @@ -0,0 +1,141 @@ +// This file is generated from JsonSchema. Don't modify this source code. +using System; +using System.Collections.Generic; +using System.Linq; +using UniJSON; + +namespace UniGLTF.Extensions.VRMC_vrm_expressions_node_transform { + + static public class GltfSerializer + { + + public static void SerializeTo(ref UniGLTF.glTFExtension dst, VRMC_vrm_expressions_node_transform extension) + { + if (dst is glTFExtensionImport) + { + throw new NotImplementedException(); + } + + if (!(dst is glTFExtensionExport extensions)) + { + extensions = new glTFExtensionExport(); + dst = extensions; + } + + var f = new JsonFormatter(); + Serialize(f, extension); + extensions.Add(VRMC_vrm_expressions_node_transform.ExtensionName, f.GetStoreBytes()); + } + + +public static void Serialize(JsonFormatter f, VRMC_vrm_expressions_node_transform value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.NodeTransformBinds!=null&&value.NodeTransformBinds.Count()>=1){ + f.Key("nodeTransformBinds"); + Serialize_NodeTransformBinds(f, value.NodeTransformBinds); + } + + f.EndMap(); +} + +public static void Serialize_NodeTransformBinds(JsonFormatter f, List value) +{ + f.BeginList(); + + foreach(var item in value) + { + Serialize_NodeTransformBinds_ITEM(f, item); + + } + f.EndList(); +} + +public static void Serialize_NodeTransformBinds_ITEM(JsonFormatter f, NodeTransformBind value) +{ + f.BeginMap(); + + + if(value.Extensions!=null){ + f.Key("extensions"); + (value.Extensions as glTFExtension).Serialize(f); + } + + if(value.Extras!=null){ + f.Key("extras"); + (value.Extras as glTFExtension).Serialize(f); + } + + if(value.Node.HasValue){ + f.Key("node"); + f.Value(value.Node.GetValueOrDefault()); + } + + if(value.Rotation!=null&&value.Rotation.Count()>=4){ + f.Key("rotation"); + __nodeTransformBinds_ITEM_Serialize_Rotation(f, value.Rotation); + } + + if(value.Scale!=null&&value.Scale.Count()>=3){ + f.Key("scale"); + __nodeTransformBinds_ITEM_Serialize_Scale(f, value.Scale); + } + + if(value.Translation!=null&&value.Translation.Count()>=3){ + f.Key("translation"); + __nodeTransformBinds_ITEM_Serialize_Translation(f, value.Translation); + } + + f.EndMap(); +} + +public static void __nodeTransformBinds_ITEM_Serialize_Rotation(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __nodeTransformBinds_ITEM_Serialize_Scale(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __nodeTransformBinds_ITEM_Serialize_Translation(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + + } // class +} // namespace diff --git a/Packages/VRM10/Runtime/Format/ExpressionsNodeTransform/Serializer.g.cs.meta b/Packages/VRM10/Runtime/Format/ExpressionsNodeTransform/Serializer.g.cs.meta new file mode 100644 index 000000000..773237b4d --- /dev/null +++ b/Packages/VRM10/Runtime/Format/ExpressionsNodeTransform/Serializer.g.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 16a49328d069d9f47840c104597af4a4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/VRM10/Runtime/Format/SpringBoneLimit/Format.g.cs b/Packages/VRM10/Runtime/Format/SpringBoneLimit/Format.g.cs index f820abb77..655df84f1 100644 --- a/Packages/VRM10/Runtime/Format/SpringBoneLimit/Format.g.cs +++ b/Packages/VRM10/Runtime/Format/SpringBoneLimit/Format.g.cs @@ -44,10 +44,10 @@ namespace UniGLTF.Extensions.VRMC_springBone_limit // Application-specific data. public object Extras; - // The phi angle of the spherical limit in radians. If the phi angle is set to π or greater, the angle will be interpreted as π by the implementation. + // The pitch angle of the spherical limit in radians. If the pitch angle is set to π or greater, the angle will be interpreted as π by the implementation. public float? Pitch; - // The theta angle of the spherical limit in radians. If the theta angle is set to π/2 or greater, the angle will be interpreted as π/2 by the implementation. + // The yaw angle of the spherical limit in radians. If the yaw angle is set to π/2 or greater, the angle will be interpreted as π/2 by the implementation. public float? Yaw; // The rotation from the default orientation of the spherical limit. The rotation is represented as a quaternion (x, y, z, w), where w is the scalar. From e04d0248af457c86770efb3cb132121def94a96f Mon Sep 17 00:00:00 2001 From: ousttrue Date: Fri, 6 Feb 2026 15:58:00 +0900 Subject: [PATCH 06/15] impl importer, exporter and editor --- .../Expression/ExpressionEditorHelper.cs | 15 ++ .../Expression/PreviewFaceRenderer.cs | 4 + .../ReorderableNodeTransformBindingList.cs | 131 ++++++++++++++++++ ...orderableNodeTransformBindingList.cs.meta} | 2 +- .../Expression/SerializedExpressionEditor.cs | 45 +++--- .../Expression/BoneTransformMerger.cs | 41 ------ .../Components/Expression/ExpressionMerger.cs | 13 +- .../Expression/NodeTransformBindingMerger.cs | 51 +++++++ ...eta => NodeTransformBindingMerger.cs.meta} | 0 .../Expression/NodeTransformtBinding.cs | 53 +++++++ .../Expression/NodeTransformtBinding.cs.meta | 11 ++ .../Expression/Preview/PreviewSceneManager.cs | 47 +++++-- .../Components/Expression/VRM10Expression.cs | 6 + .../Vrm10BoneTransformExpression.cs | 22 --- .../Components/Vrm10Runtime/Vrm10Runtime.cs | 4 +- .../Vrm10Runtime/Vrm10RuntimeExpression.cs | 16 ++- .../VRM10/Runtime/IO/ExpressionExtensions.cs | 25 ++++ Packages/VRM10/Runtime/IO/Vrm10Exporter.cs | 52 ++++++- Packages/VRM10/Runtime/IO/Vrm10Importer.cs | 20 +++ 19 files changed, 452 insertions(+), 106 deletions(-) create mode 100644 Packages/VRM10/Editor/Components/Expression/ReorderableNodeTransformBindingList.cs rename Packages/VRM10/{Runtime/Components/Expression/Vrm10BoneTransformExpression.cs.meta => Editor/Components/Expression/ReorderableNodeTransformBindingList.cs.meta} (83%) delete mode 100644 Packages/VRM10/Runtime/Components/Expression/BoneTransformMerger.cs create mode 100644 Packages/VRM10/Runtime/Components/Expression/NodeTransformBindingMerger.cs rename Packages/VRM10/Runtime/Components/Expression/{BoneTransformMerger.cs.meta => NodeTransformBindingMerger.cs.meta} (100%) create mode 100644 Packages/VRM10/Runtime/Components/Expression/NodeTransformtBinding.cs create mode 100644 Packages/VRM10/Runtime/Components/Expression/NodeTransformtBinding.cs.meta delete mode 100644 Packages/VRM10/Runtime/Components/Expression/Vrm10BoneTransformExpression.cs diff --git a/Packages/VRM10/Editor/Components/Expression/ExpressionEditorHelper.cs b/Packages/VRM10/Editor/Components/Expression/ExpressionEditorHelper.cs index 4791a460a..bc23218ea 100644 --- a/Packages/VRM10/Editor/Components/Expression/ExpressionEditorHelper.cs +++ b/Packages/VRM10/Editor/Components/Expression/ExpressionEditorHelper.cs @@ -99,6 +99,21 @@ namespace UniVRM10 } } + public static bool Vec3Prop(Rect rect, SerializedProperty prop) + { + var oldValue = prop.vector3Value; + var newValue = EditorGUI.Vector3Field(rect, prop.displayName, oldValue); + if (newValue != oldValue) + { + prop.vector3Value = newValue; + return true; + } + else + { + return false; + } + } + static Rect AdvanceRect(ref float x, float y, float w, float h) { var rect = new Rect(x, y, w, h); diff --git a/Packages/VRM10/Editor/Components/Expression/PreviewFaceRenderer.cs b/Packages/VRM10/Editor/Components/Expression/PreviewFaceRenderer.cs index 4020fcf06..db49a99c0 100644 --- a/Packages/VRM10/Editor/Components/Expression/PreviewFaceRenderer.cs +++ b/Packages/VRM10/Editor/Components/Expression/PreviewFaceRenderer.cs @@ -110,6 +110,10 @@ namespace UniVRM10 int subMeshCount = item.Mesh.subMeshCount; for (int i = 0; i < subMeshCount; i++) { + if (item.SkinnedMeshRenderer != null) + { + item.SkinnedMeshRenderer.BakeMesh(item.Mesh); + } m_previewUtility.DrawMesh(item.Mesh, item.Position, item.Rotation, item.Materials[i], i); diff --git a/Packages/VRM10/Editor/Components/Expression/ReorderableNodeTransformBindingList.cs b/Packages/VRM10/Editor/Components/Expression/ReorderableNodeTransformBindingList.cs new file mode 100644 index 000000000..1903f7014 --- /dev/null +++ b/Packages/VRM10/Editor/Components/Expression/ReorderableNodeTransformBindingList.cs @@ -0,0 +1,131 @@ +using System; +using UnityEditor; +using UnityEditorInternal; +using UnityEngine; + + +namespace UniVRM10 +{ + public class ReorderableNodeTransformBindingList + { + ReorderableList m_ValuesList; + SerializedProperty m_valuesProp; + bool m_changed; + + public ReorderableNodeTransformBindingList(SerializedObject serializedObject, PreviewSceneManager previewSceneManager, int height) + { + m_valuesProp = serializedObject.FindProperty(nameof(VRM10Expression.NodeTransformBindings)); + m_ValuesList = new ReorderableList(serializedObject, m_valuesProp); + m_ValuesList.elementHeight = height * 4; + m_ValuesList.drawElementCallback = + (rect, index, isActive, isFocused) => + { + var element = m_valuesProp.GetArrayElementAtIndex(index); + rect.height -= 4; + rect.y += 2; + if (DrawNodeTransformBinding(rect, element, previewSceneManager, height)) + { + m_changed = true; + } + }; + } + + /// + /// NodeTransform List のElement描画 + /// + static bool DrawNodeTransformBinding(Rect position, SerializedProperty property, + PreviewSceneManager scene, int height) + { + bool changed = false; + if (scene != null) + { + var y = position.y; + var rect = new Rect(position.x, y, position.width, height); + int pathIndex; + if (ExpressionEditorHelper.StringPopup(rect, property.FindPropertyRelative(nameof(NodeTransformBinding.RelativePath)), scene.NodeTransformPathList, out pathIndex)) + { + changed = true; + } + + // T` + y += height; + rect = new Rect(position.x, y, position.width, height); + if (ExpressionEditorHelper.Vec3Prop(rect, property.FindPropertyRelative(nameof(NodeTransformBinding.OffsetTranslation)))) + { + changed = true; + } + + // R + y += height; + rect = new Rect(position.x, y, position.width, height); + if (EditorGUI.PropertyField(rect, property.FindPropertyRelative(nameof(NodeTransformBinding.OffsetRotation)))) + { + changed = true; + } + + // S + y += height; + rect = new Rect(position.x, y, position.width, height); + if (ExpressionEditorHelper.Vec3Prop(rect, property.FindPropertyRelative(nameof(NodeTransformBinding.TargetScale)))) + { + changed = true; + } + } + return changed; + } + + public void SetValues(NodeTransformBinding[] bindings) + { + m_valuesProp.ClearArray(); + m_valuesProp.arraySize = bindings.Length; + for (int i = 0; i < bindings.Length; ++i) + { + var item = m_valuesProp.GetArrayElementAtIndex(i); + + var endProperty = item.GetEndProperty(); + while (item.NextVisible(true)) + { + if (SerializedProperty.EqualContents(item, endProperty)) + { + break; + } + + switch (item.name) + { + case nameof(NodeTransformBinding.RelativePath): + item.stringValue = bindings[i].RelativePath; + break; + + case nameof(NodeTransformBinding.OffsetTranslation): + item.vector3Value = bindings[i].OffsetTranslation; + break; + + case nameof(NodeTransformBinding.OffsetRotation): + item.quaternionValue = bindings[i].OffsetRotation; + break; + + case nameof(NodeTransformBinding.TargetScale): + item.vector3Value = bindings[i].TargetScale; + break; + + default: + throw new Exception(); + } + } + } + + } + + public bool Draw(string label) + { + m_changed = false; + m_ValuesList.DoLayoutList(); + if (GUILayout.Button($"Clear {label}")) + { + m_changed = true; + m_valuesProp.arraySize = 0; + } + return m_changed; + } + } +} diff --git a/Packages/VRM10/Runtime/Components/Expression/Vrm10BoneTransformExpression.cs.meta b/Packages/VRM10/Editor/Components/Expression/ReorderableNodeTransformBindingList.cs.meta similarity index 83% rename from Packages/VRM10/Runtime/Components/Expression/Vrm10BoneTransformExpression.cs.meta rename to Packages/VRM10/Editor/Components/Expression/ReorderableNodeTransformBindingList.cs.meta index 1622ca50d..3c72f298b 100644 --- a/Packages/VRM10/Runtime/Components/Expression/Vrm10BoneTransformExpression.cs.meta +++ b/Packages/VRM10/Editor/Components/Expression/ReorderableNodeTransformBindingList.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 1520687d88c34af4eb8c16bb37ee0391 +guid: 186e6dd105c86904497f3ac0dfd61212 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Packages/VRM10/Editor/Components/Expression/SerializedExpressionEditor.cs b/Packages/VRM10/Editor/Components/Expression/SerializedExpressionEditor.cs index 782d355a3..768cc15f0 100644 --- a/Packages/VRM10/Editor/Components/Expression/SerializedExpressionEditor.cs +++ b/Packages/VRM10/Editor/Components/Expression/SerializedExpressionEditor.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Linq; using UnityEditor; @@ -28,21 +29,24 @@ namespace UniVRM10 ReorderableMorphTargetBindingList m_morphTargetBindings; ReorderableMaterialColorBindingList m_materialColorBindings; ReorderableMaterialUVBindingList m_materialUVBindings; - + ReorderableNodeTransformBindingList m_nodeTransformBindings; #region Editor values bool m_changed; - static int s_Mode; static bool s_MorphTargetFoldout = true; static bool s_OptionFoldout; static bool s_ListFoldout; - static string[] MODES = new[]{ - "MorphTarget", - "Material Color", - "Texture Transform" - }; + enum ListMode + { + MorphTarget, + MaterialColor, + TextureTransform, + NodeTransform, + } + static ListMode s_Mode; + static string[] MODES = ((ListMode[])Enum.GetValues(typeof(ListMode))).Select(x => x.ToString()).ToArray(); PreviewMeshItem[] m_items; #endregion @@ -71,6 +75,7 @@ namespace UniVRM10 m_morphTargetBindings = new ReorderableMorphTargetBindingList(serializedObject, previewSceneManager, 20); m_materialColorBindings = new ReorderableMaterialColorBindingList(serializedObject, previewSceneManager?.MaterialNames, 20); m_materialUVBindings = new ReorderableMaterialUVBindingList(serializedObject, previewSceneManager?.MaterialNames, 20); + m_nodeTransformBindings = new ReorderableNodeTransformBindingList(serializedObject, previewSceneManager, 20); m_items = previewSceneManager.EnumRenderItems .Where(x => x.SkinnedMeshRenderer != null) @@ -109,33 +114,39 @@ namespace UniVRM10 if (s_ListFoldout) { EditorGUI.indentLevel++; - s_Mode = GUILayout.Toolbar(s_Mode, MODES); + s_Mode = (ListMode)GUILayout.Toolbar((int)s_Mode, MODES); switch (s_Mode) { - case 0: - // MorphTarget + case ListMode.MorphTarget: { - if (m_morphTargetBindings.Draw("MorphTarget")) + if (m_morphTargetBindings.Draw(s_Mode.ToString())) { m_changed = true; } } break; - case 1: - // Material + case ListMode.MaterialColor: { - if (m_materialColorBindings.Draw("MaterialColor")) + if (m_materialColorBindings.Draw(s_Mode.ToString())) { m_changed = true; } } break; - case 2: - // TextureTransform + case ListMode.TextureTransform: { - if (m_materialUVBindings.Draw("TextureTransform")) + if (m_materialUVBindings.Draw(s_Mode.ToString())) + { + m_changed = true; + } + } + break; + + case ListMode.NodeTransform: + { + if (m_nodeTransformBindings.Draw(s_Mode.ToString())) { m_changed = true; } diff --git a/Packages/VRM10/Runtime/Components/Expression/BoneTransformMerger.cs b/Packages/VRM10/Runtime/Components/Expression/BoneTransformMerger.cs deleted file mode 100644 index 114edf0c5..000000000 --- a/Packages/VRM10/Runtime/Components/Expression/BoneTransformMerger.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System.Collections.Generic; -using UniGLTF; -using UniGLTF.Utils; -using UnityEngine; - - -namespace UniVRM10 -{ - internal sealed class BoneTransformBindingMerger - { - Dictionary _acum = new(); - // Vrm10BoneTransformExpression[] _expressions; - Transform _root; - - public BoneTransformBindingMerger(Transform root) - { - // _expressions = root.GetComponentsInChildren(); - _root = root; - } - - public void AccumulateValue(ExpressionKey key, float value) - { - _acum[key] = value; - } - - public void Apply(IReadOnlyDictionary initPose) - { - foreach (var expression in _root.GetComponentsInChildren()) - { - if (initPose.TryGetValue(expression.transform, out var init)) - { - var weight = _acum.GetValueOrDefault(expression.Expression.ExpressionKey, 0); - expression.transform.SetLocalPositionAndRotation( - init.LocalPosition + expression.Expression.Translation * weight, - Quaternion.Slerp(init.LocalRotation, init.LocalRotation * expression.Expression.Rotation, weight) - ); - } - } - } - } -} \ No newline at end of file diff --git a/Packages/VRM10/Runtime/Components/Expression/ExpressionMerger.cs b/Packages/VRM10/Runtime/Components/Expression/ExpressionMerger.cs index 4d85995f5..de9a6a55f 100644 --- a/Packages/VRM10/Runtime/Components/Expression/ExpressionMerger.cs +++ b/Packages/VRM10/Runtime/Components/Expression/ExpressionMerger.cs @@ -24,10 +24,13 @@ namespace UniVRM10 MorphTargetBindingMerger m_morphTargetBindingMerger; MaterialValueBindingMerger m_materialValueBindingMerger; - BoneTransformBindingMerger m_boneTransformBindingMerger; + NodeTransformBindingMerger m_boneTransformBindingMerger; - public ExpressionMerger(VRM10ObjectExpression expressions, Transform root, bool isPrefabInstance) + public ExpressionMerger(VRM10ObjectExpression expressions, + Transform root, + bool isPrefabInstance, + IReadOnlyDictionary initPose) { m_clipMap = expressions.Clips.ToDictionary( x => expressions.CreateKey(x.Clip), @@ -37,14 +40,14 @@ namespace UniVRM10 m_valueMap = new Dictionary(ExpressionKey.Comparer); m_morphTargetBindingMerger = new MorphTargetBindingMerger(m_clipMap, root); m_materialValueBindingMerger = new MaterialValueBindingMerger(m_clipMap, root, isPrefabInstance); - m_boneTransformBindingMerger = new BoneTransformBindingMerger(root); + m_boneTransformBindingMerger = new NodeTransformBindingMerger(m_clipMap, root, initPose); } /// /// まとめて反映する。1フレームに1回呼び出されることを想定 /// /// - public void SetValues(Dictionary expressionWeights, IReadOnlyDictionary initPose) + public void SetValues(Dictionary expressionWeights) { foreach (var (key, weight) in expressionWeights) { @@ -53,7 +56,7 @@ namespace UniVRM10 m_morphTargetBindingMerger.Apply(); m_materialValueBindingMerger.Apply(); - m_boneTransformBindingMerger.Apply(initPose); + m_boneTransformBindingMerger.Apply(); } private void AccumulateValue(ExpressionKey key, float value) diff --git a/Packages/VRM10/Runtime/Components/Expression/NodeTransformBindingMerger.cs b/Packages/VRM10/Runtime/Components/Expression/NodeTransformBindingMerger.cs new file mode 100644 index 000000000..c972a8437 --- /dev/null +++ b/Packages/VRM10/Runtime/Components/Expression/NodeTransformBindingMerger.cs @@ -0,0 +1,51 @@ +using System.Collections.Generic; +using UniGLTF.Utils; +using UnityEngine; + + +namespace UniVRM10 +{ + internal sealed class NodeTransformBindingMerger + { + IReadOnlyDictionary _clipMap; + Transform _root; + IReadOnlyDictionary _initPose; + Dictionary _weightMap = new(); + + public NodeTransformBindingMerger( + IReadOnlyDictionary clipMap, + Transform root, + IReadOnlyDictionary initPose) + { + _clipMap = clipMap; + _root = root; + _initPose = initPose; + } + + public void AccumulateValue(ExpressionKey key, float value) + { + _weightMap[key] = value; + } + + public void Apply() + { + foreach (var (k, weight) in _weightMap) + { + if (_clipMap.TryGetValue(k, out var clip)) + { + foreach (var b in clip.NodeTransformBindings) + { + var node = _root.GetFromPath(b.RelativePath); + if (node != null) + { + if (_initPose.TryGetValue(node, out var init)) + { + b.Apply(node, init, weight); + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/Packages/VRM10/Runtime/Components/Expression/BoneTransformMerger.cs.meta b/Packages/VRM10/Runtime/Components/Expression/NodeTransformBindingMerger.cs.meta similarity index 100% rename from Packages/VRM10/Runtime/Components/Expression/BoneTransformMerger.cs.meta rename to Packages/VRM10/Runtime/Components/Expression/NodeTransformBindingMerger.cs.meta diff --git a/Packages/VRM10/Runtime/Components/Expression/NodeTransformtBinding.cs b/Packages/VRM10/Runtime/Components/Expression/NodeTransformtBinding.cs new file mode 100644 index 000000000..d049fb858 --- /dev/null +++ b/Packages/VRM10/Runtime/Components/Expression/NodeTransformtBinding.cs @@ -0,0 +1,53 @@ +using System; +using UniGLTF.Utils; +using UnityEngine; + +namespace UniVRM10 +{ + [Serializable] + public struct NodeTransformBinding + { + public string RelativePath; + + /// + /// t = init_t + offset_t * weight + /// disable if offset_t = (0, 0, 0) + /// + public Vector3 OffsetTranslation; + + /// + /// r = slerp(init_t, init_t * offset r, weight) + /// disable if rotation_t = (0, 0, 0, 1) + /// + public Quaternion OffsetRotation; + + /// + /// s = lerp(init_s, blend_s, weight) + /// disalbe if blend_s = init_s. maybe(1, 1, 1) + /// + public Vector3 TargetScale; + + /// + /// + /// + /// + /// + /// 0 to 1.0 + public NodeTransformBinding(string path, in Vector3 t, in Quaternion r, in Vector3 s) + { + RelativePath = path; + OffsetTranslation = t; + OffsetRotation = r; + TargetScale = s; + } + + public void Apply(Transform node, in TransformState init, float weight) + { + node.SetLocalPositionAndRotation( + init.LocalPosition + this.OffsetTranslation * weight, + Quaternion.Slerp(init.LocalRotation, init.LocalRotation * this.OffsetRotation, weight) + ); + node.localScale = Vector3.Lerp(init.LocalScale, this.TargetScale, weight); + } + } +} \ No newline at end of file diff --git a/Packages/VRM10/Runtime/Components/Expression/NodeTransformtBinding.cs.meta b/Packages/VRM10/Runtime/Components/Expression/NodeTransformtBinding.cs.meta new file mode 100644 index 000000000..bb06db17f --- /dev/null +++ b/Packages/VRM10/Runtime/Components/Expression/NodeTransformtBinding.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dd660f7a77373234c85064f97150eef6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/VRM10/Runtime/Components/Expression/Preview/PreviewSceneManager.cs b/Packages/VRM10/Runtime/Components/Expression/Preview/PreviewSceneManager.cs index c93504344..30bdbe5a2 100644 --- a/Packages/VRM10/Runtime/Components/Expression/Preview/PreviewSceneManager.cs +++ b/Packages/VRM10/Runtime/Components/Expression/Preview/PreviewSceneManager.cs @@ -3,6 +3,7 @@ using System.Linq; using UnityEngine; using System; using UniGLTF; +using UniGLTF.Utils; namespace UniVRM10 @@ -16,6 +17,8 @@ namespace UniVRM10 public bool hasError; + private IReadOnlyDictionary m_defaultTransformStates; + #if UNITY_EDITOR public static PreviewSceneManager GetOrCreate(GameObject prefab) { @@ -85,7 +88,7 @@ namespace UniVRM10 private void Initialize(GameObject prefab) { hasError = false; - + Prefab = prefab; var materialNames = new List(); @@ -104,14 +107,14 @@ namespace UniVRM10 { dst = new Material(src); map.Add(src, dst); - + if (!PreviewMaterialUtil.TryCreateForPreview(dst, out var previewMaterialItem)) { hasError = true; // Return cloned material for preview return dst; } - + m_materialMap.Add(src.name, previewMaterialItem); materialNames.Add(src.name); @@ -119,6 +122,10 @@ namespace UniVRM10 return dst; }; + // initPose for nodeTransform + m_defaultTransformStates = transform.GetComponentsInChildren() + .ToDictionary(tf => tf, tf => new TransformState(tf)); + m_meshes = transform.Traverse() .Select(x => PreviewMeshItem.Create(x, transform, getOrCreateMaterial)) .Where(x => x != null) @@ -136,8 +143,13 @@ namespace UniVRM10 .Where(x => x.SkinnedMeshRenderer != null) .Select(x => x.Path) .ToArray(); + m_nodeTransformPathList = transform.GetComponentsInChildren() + .Select(x => x.RelativePathFrom(transform)) + .Where(x => x != null) + .ToArray() + ; - if(TryGetComponent(out var animator)) + if (TryGetComponent(out var animator)) { var head = animator.GetBoneTransform(HumanBodyBones.Head); if (head != null) @@ -184,6 +196,12 @@ namespace UniVRM10 get { return m_skinnedMeshRendererPathList; } } + string[] m_nodeTransformPathList; + public string[] NodeTransformPathList + { + get { return m_nodeTransformPathList; } + } + public string[] GetBlendShapeNames(int blendShapeMeshIndex) { if (blendShapeMeshIndex >= 0 && blendShapeMeshIndex < m_blendShapeMeshes.Length) @@ -228,19 +246,28 @@ namespace UniVRM10 return; } + // + // bake NodeTransform + // + foreach (var nodeTransform in bake.NodeTransformBindings) + { + var node = transform.GetFromPath(nodeTransform.RelativePath); + if (m_defaultTransformStates.TryGetValue(node, out var init)) + { + nodeTransform.Apply(node, init, weight); + } + } + // // Bake Expression // m_bounds = default(Bounds); if (m_meshes != null) { - if (bake != null) + foreach (var x in m_meshes) { - foreach (var x in m_meshes) - { - x.Bake(bake.MorphTargetBindings, weight); - m_bounds.Expand(x.Mesh.bounds.size); - } + x.Bake(bake.MorphTargetBindings, weight); + m_bounds.Expand(x.Mesh.bounds.size); } } diff --git a/Packages/VRM10/Runtime/Components/Expression/VRM10Expression.cs b/Packages/VRM10/Runtime/Components/Expression/VRM10Expression.cs index b75473e24..d0fd471d3 100644 --- a/Packages/VRM10/Runtime/Components/Expression/VRM10Expression.cs +++ b/Packages/VRM10/Runtime/Components/Expression/VRM10Expression.cs @@ -46,5 +46,11 @@ namespace UniVRM10 /// [SerializeField] public UniGLTF.Extensions.VRMC_vrm.ExpressionOverrideType OverrideMouth; + + /// + /// from UniVRM-132.0. experimental + /// + [SerializeField] + public NodeTransformBinding[] NodeTransformBindings = new NodeTransformBinding[] { }; } } diff --git a/Packages/VRM10/Runtime/Components/Expression/Vrm10BoneTransformExpression.cs b/Packages/VRM10/Runtime/Components/Expression/Vrm10BoneTransformExpression.cs deleted file mode 100644 index 1f33be137..000000000 --- a/Packages/VRM10/Runtime/Components/Expression/Vrm10BoneTransformExpression.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using UniGLTF.Utils; -using UnityEngine; - -namespace UniVRM10 -{ - [DisallowMultipleComponent] - public class Vrm10BoneTransformExpression : MonoBehaviour - { - [Serializable] - public class BoneTransformExpression - { - public ExpressionPreset Preset = ExpressionPreset.custom; - public string Name = "custom"; - public ExpressionKey ExpressionKey => new(Preset, Name); - public Quaternion Rotation = Quaternion.identity; - public Vector3 Translation = Vector3.zero; - } - - public BoneTransformExpression Expression; - } -} \ No newline at end of file diff --git a/Packages/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs b/Packages/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs index 46429762e..e22956304 100644 --- a/Packages/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs +++ b/Packages/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs @@ -77,7 +77,7 @@ namespace UniVRM10 } Constraints = instance.GetComponentsInChildren(); LookAt = new Vrm10RuntimeLookAt(instance, instance.Humanoid, ControlRig); - Expression = new Vrm10RuntimeExpression(instance, LookAt.EyeDirectionApplicable, isPrefabInstance); + Expression = new Vrm10RuntimeExpression(instance, LookAt.EyeDirectionApplicable, isPrefabInstance, initPose); SpringBone = springBoneRuntime; } @@ -153,7 +153,7 @@ namespace UniVRM10 // 5. Apply Expression // LookAt の角度制限などはこちらで処理されます。 - Expression.Process(eyeDirection, _initPose); + Expression.Process(eyeDirection); // 6. SpringBone SpringBone.Process(Time.deltaTime); diff --git a/Packages/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeExpression.cs b/Packages/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeExpression.cs index 276735700..3c13e449f 100644 --- a/Packages/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeExpression.cs +++ b/Packages/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeExpression.cs @@ -25,9 +25,13 @@ namespace UniVRM10 public float LookAtOverrideRate { get; private set; } public float MouthOverrideRate { get; private set; } - internal Vrm10RuntimeExpression(Vrm10Instance target, ILookAtEyeDirectionApplicable eyeDirectionApplicable, bool isPrefabInstance) + internal Vrm10RuntimeExpression(Vrm10Instance target, + ILookAtEyeDirectionApplicable eyeDirectionApplicable, + bool isPrefabInstance, + IReadOnlyDictionary initPose + ) { - _merger = new ExpressionMerger(target.Vrm.Expression, target.transform, isPrefabInstance); + _merger = new ExpressionMerger(target.Vrm.Expression, target.transform, isPrefabInstance, initPose); _keys = target.Vrm.Expression.Clips .Select(x => target.Vrm.Expression.CreateKey(x.Clip)) .ToList(); @@ -60,9 +64,9 @@ namespace UniVRM10 _eyeDirectionApplicable = null; } - internal void Process(LookAtEyeDirection inputEyeDirection, IReadOnlyDictionary initPose = null) + internal void Process(LookAtEyeDirection inputEyeDirection) { - Apply(inputEyeDirection, initPose); + Apply(inputEyeDirection); } public IDictionary GetWeights() @@ -114,7 +118,7 @@ namespace UniVRM10 /// 入力 Weight を基に、Validation を行い実際にモデルに適用される Weights を計算し、Merger を介して適用する。 /// この際、LookAt の情報を pull してそれも適用する。 /// - private void Apply(LookAtEyeDirection inputEyeDirection, IReadOnlyDictionary initPose) + private void Apply(LookAtEyeDirection inputEyeDirection) { // 1. Validate user input, and Output as actual weights. _validator.Validate(_inputWeights, _actualWeights, @@ -125,7 +129,7 @@ namespace UniVRM10 _eyeDirectionApplicable?.Apply(_actualEyeDirection, _actualWeights); // 3. Set actual weights to raw blendshapes. - _merger.SetValues(_actualWeights, initPose); + _merger.SetValues(_actualWeights); BlinkOverrideRate = blink; LookAtOverrideRate = lookAt; diff --git a/Packages/VRM10/Runtime/IO/ExpressionExtensions.cs b/Packages/VRM10/Runtime/IO/ExpressionExtensions.cs index 4ed7d05d3..41729d9b3 100644 --- a/Packages/VRM10/Runtime/IO/ExpressionExtensions.cs +++ b/Packages/VRM10/Runtime/IO/ExpressionExtensions.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using UniGLTF; using UniGLTF.Extensions.VRMC_vrm; +using UniGLTF.Extensions.VRMC_vrm_expressions_node_transform; using UnityEngine; namespace UniVRM10 @@ -86,5 +87,29 @@ namespace UniVRM10 } return binding; } + + public static NodeTransformBinding? Build10(this NodeTransformBind bind, GameObject root, Vrm10Importer importer) + { + if (bind.Node.TryGetValidIndex(importer.Nodes.Count, out var nodeIndex)) + { + var node = importer.Nodes[nodeIndex]; + var relativePath = node.RelativePathFrom(root.transform); + + var t = bind.Translation != null && bind.Translation.Length >= 3 + ? new Vector3(bind.Translation[0], bind.Translation[1], bind.Translation[2]) + : Vector3.zero; + var r = bind.Rotation != null && bind.Rotation.Length >= 4 + ? new Quaternion(bind.Rotation[0], bind.Rotation[1], bind.Rotation[2], bind.Rotation[3]) + : Quaternion.identity; + var s = bind.Scale != null && bind.Scale.Length >= 3 + ? new Vector3(bind.Scale[0], bind.Scale[1], bind.Scale[2]) + : Vector3.zero; + return new NodeTransformBinding(relativePath, t, r, s); + } + else + { + return default; + } + } } } diff --git a/Packages/VRM10/Runtime/IO/Vrm10Exporter.cs b/Packages/VRM10/Runtime/IO/Vrm10Exporter.cs index a0bf43867..32255cac1 100644 --- a/Packages/VRM10/Runtime/IO/Vrm10Exporter.cs +++ b/Packages/VRM10/Runtime/IO/Vrm10Exporter.cs @@ -779,6 +779,17 @@ namespace UniVRM10 }; } + static UniGLTF.Extensions.VRMC_vrm_expressions_node_transform.NodeTransformBind ExportNodeTransformBinding(NodeTransformBinding binding, Func getIndex) + { + return new UniGLTF.Extensions.VRMC_vrm_expressions_node_transform.NodeTransformBind + { + Node = getIndex(binding.RelativePath), + Translation = new float[] { binding.OffsetTranslation.x, binding.OffsetRotation.y, binding.OffsetTranslation.z }, + Rotation = new float[] { binding.OffsetRotation.x, binding.OffsetRotation.y, binding.OffsetRotation.z, binding.OffsetRotation.w }, + Scale = new float[] { binding.TargetScale.x, binding.TargetScale.y, binding.TargetScale.z }, + }; + } + static UniGLTF.Extensions.VRMC_vrm.Expression ExportExpression(VRM10Expression e, Vrm10Instance vrmController, Model model, ModelExporter converter) { if (e == null) @@ -786,7 +797,7 @@ namespace UniVRM10 return null; } - Func getIndexFromRelativePath = relativePath => + Func getRendererNodeIndexFromRelativePath = relativePath => { var rendererNode = vrmController.transform.GetFromPath(relativePath); var renderer = rendererNode.GetComponent(); @@ -831,7 +842,7 @@ namespace UniVRM10 { try { - var binding = ExportMorphTargetBinding(b, getIndexFromRelativePath); + var binding = ExportMorphTargetBinding(b, getRendererNodeIndexFromRelativePath); if (binding.Node < 0) { // node もしくは renderer が存在しない @@ -867,6 +878,43 @@ namespace UniVRM10 UniGLTFLogger.Warning($"{ex}"); } } + + if (e.NodeTransformBindings != null && e.NodeTransformBindings.Length > 0) + { + Func getNodeIndexFromRelativePath = relativePath => + { + var n = vrmController.transform.GetFromPath(relativePath); + var node = converter.Nodes[n.gameObject]; + return model.Nodes.IndexOf(node); + }; + + var nodeTransform = new UniGLTF.Extensions.VRMC_vrm_expressions_node_transform.VRMC_vrm_expressions_node_transform + { + NodeTransformBinds = new(), + }; + foreach (var b in e.NodeTransformBindings) + { + try + { + var binding = ExportNodeTransformBinding(b, getNodeIndexFromRelativePath); + if (binding.Node < 0) + { + // node もしくは renderer が存在しない + continue; + } + + nodeTransform.NodeTransformBinds.Add(binding); + } + catch (Exception ex) + { + UniGLTFLogger.Warning($"{ex}"); + } + } + glTFExtension extensions = default; + UniGLTF.Extensions.VRMC_vrm_expressions_node_transform.GltfSerializer.SerializeTo(ref extensions, nodeTransform); + vrmExpression.Extensions = extensions; + } + return vrmExpression; } diff --git a/Packages/VRM10/Runtime/IO/Vrm10Importer.cs b/Packages/VRM10/Runtime/IO/Vrm10Importer.cs index e0541a57d..ae51eb0ae 100644 --- a/Packages/VRM10/Runtime/IO/Vrm10Importer.cs +++ b/Packages/VRM10/Runtime/IO/Vrm10Importer.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using UniGLTF; using UniGLTF.Extensions.VRMC_springBone_limit; using UniGLTF.Utils; +using UnityEditor.Experimental.GraphView; using UnityEngine; namespace UniVRM10 @@ -286,6 +287,25 @@ namespace UniVRM10 clip.MaterialUVBindings = new MaterialUVBinding[] { }; } + if (UniGLTF.Extensions.VRMC_vrm_expressions_node_transform.GltfDeserializer.TryGet( + expression.Extensions as glTFExtension, + out UniGLTF.Extensions.VRMC_vrm_expressions_node_transform.VRMC_vrm_expressions_node_transform nodeTransform)) + { + if (nodeTransform.NodeTransformBinds != null) + { + clip.NodeTransformBindings = nodeTransform.NodeTransformBinds? + .Select(x => x.Build10(Root, this)) + .Where(x => x.HasValue) + .Select(x => x.Value) + .ToArray(); + } + else + { + clip.NodeTransformBindings = new NodeTransformBinding[] { }; + } + + } + m_expressions.Add((preset, clip)); } return clip; From 864f1c52ff1f3da37bbc1e18263ce60026b28f35 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Mon, 9 Feb 2026 16:26:44 +0900 Subject: [PATCH 07/15] fix preview bake --- .../Runtime/Components/Expression/Preview/PreviewMeshItem.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Packages/VRM10/Runtime/Components/Expression/Preview/PreviewMeshItem.cs b/Packages/VRM10/Runtime/Components/Expression/Preview/PreviewMeshItem.cs index 2765bd254..5d7a6a28b 100644 --- a/Packages/VRM10/Runtime/Components/Expression/Preview/PreviewMeshItem.cs +++ b/Packages/VRM10/Runtime/Components/Expression/Preview/PreviewMeshItem.cs @@ -123,7 +123,9 @@ namespace UniVRM10 { return new PreviewMeshItem(t.RelativePathFrom(root), t, skinnedMeshRenderer.sharedMaterials) { - Mesh = skinnedMeshRenderer.sharedMesh, + SkinnedMeshRenderer = skinnedMeshRenderer, + Mesh = new Mesh(), // for bake + BlendShapeNames = new string[]{}, }; } } From 2517ab54f234bbbd06a2551fb045527a74080a37 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 26 Feb 2026 21:22:44 +0900 Subject: [PATCH 08/15] Update Packages/VRM10/Runtime/Components/Expression/NodeTransformtBinding.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../Runtime/Components/Expression/NodeTransformtBinding.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Packages/VRM10/Runtime/Components/Expression/NodeTransformtBinding.cs b/Packages/VRM10/Runtime/Components/Expression/NodeTransformtBinding.cs index d049fb858..a6ecff11f 100644 --- a/Packages/VRM10/Runtime/Components/Expression/NodeTransformtBinding.cs +++ b/Packages/VRM10/Runtime/Components/Expression/NodeTransformtBinding.cs @@ -47,7 +47,10 @@ namespace UniVRM10 init.LocalPosition + this.OffsetTranslation * weight, Quaternion.Slerp(init.LocalRotation, init.LocalRotation * this.OffsetRotation, weight) ); - node.localScale = Vector3.Lerp(init.LocalScale, this.TargetScale, weight); + if (this.TargetScale != Vector3.zero) + { + node.localScale = Vector3.Lerp(init.LocalScale, this.TargetScale, weight); + } } } } \ No newline at end of file From e7251ec522e8c68ccb90edc0060b603727f2d215 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 26 Feb 2026 21:23:18 +0900 Subject: [PATCH 09/15] Update Packages/VRM10/Editor/Components/Expression/ReorderableNodeTransformBindingList.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../Expression/ReorderableNodeTransformBindingList.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Packages/VRM10/Editor/Components/Expression/ReorderableNodeTransformBindingList.cs b/Packages/VRM10/Editor/Components/Expression/ReorderableNodeTransformBindingList.cs index 1903f7014..55dcf27f3 100644 --- a/Packages/VRM10/Editor/Components/Expression/ReorderableNodeTransformBindingList.cs +++ b/Packages/VRM10/Editor/Components/Expression/ReorderableNodeTransformBindingList.cs @@ -58,7 +58,9 @@ namespace UniVRM10 // R y += height; rect = new Rect(position.x, y, position.width, height); - if (EditorGUI.PropertyField(rect, property.FindPropertyRelative(nameof(NodeTransformBinding.OffsetRotation)))) + EditorGUI.BeginChangeCheck(); + EditorGUI.PropertyField(rect, property.FindPropertyRelative(nameof(NodeTransformBinding.OffsetRotation))); + if (EditorGUI.EndChangeCheck()) { changed = true; } From c774a910d8c7c38b1976cc819e1a99c7328cce74 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 26 Feb 2026 21:38:39 +0900 Subject: [PATCH 10/15] Update Packages/VRM10/Runtime/IO/Vrm10Exporter.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- Packages/VRM10/Runtime/IO/Vrm10Exporter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Packages/VRM10/Runtime/IO/Vrm10Exporter.cs b/Packages/VRM10/Runtime/IO/Vrm10Exporter.cs index 32255cac1..6555d76d8 100644 --- a/Packages/VRM10/Runtime/IO/Vrm10Exporter.cs +++ b/Packages/VRM10/Runtime/IO/Vrm10Exporter.cs @@ -784,7 +784,7 @@ namespace UniVRM10 return new UniGLTF.Extensions.VRMC_vrm_expressions_node_transform.NodeTransformBind { Node = getIndex(binding.RelativePath), - Translation = new float[] { binding.OffsetTranslation.x, binding.OffsetRotation.y, binding.OffsetTranslation.z }, + Translation = new float[] { binding.OffsetTranslation.x, binding.OffsetTranslation.y, binding.OffsetTranslation.z }, Rotation = new float[] { binding.OffsetRotation.x, binding.OffsetRotation.y, binding.OffsetRotation.z, binding.OffsetRotation.w }, Scale = new float[] { binding.TargetScale.x, binding.TargetScale.y, binding.TargetScale.z }, }; From 62626d3eab5a9ede63e8cb43fb01cd8ce7e0b1d1 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 26 Feb 2026 21:38:51 +0900 Subject: [PATCH 11/15] Update Packages/VRM10/Runtime/IO/ExpressionExtensions.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- Packages/VRM10/Runtime/IO/ExpressionExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Packages/VRM10/Runtime/IO/ExpressionExtensions.cs b/Packages/VRM10/Runtime/IO/ExpressionExtensions.cs index 41729d9b3..8120c52d1 100644 --- a/Packages/VRM10/Runtime/IO/ExpressionExtensions.cs +++ b/Packages/VRM10/Runtime/IO/ExpressionExtensions.cs @@ -103,7 +103,7 @@ namespace UniVRM10 : Quaternion.identity; var s = bind.Scale != null && bind.Scale.Length >= 3 ? new Vector3(bind.Scale[0], bind.Scale[1], bind.Scale[2]) - : Vector3.zero; + : node.transform.localScale; return new NodeTransformBinding(relativePath, t, r, s); } else From 42824e5c155f418c03c705e2b82c2ff832250ec5 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 26 Feb 2026 21:39:04 +0900 Subject: [PATCH 12/15] Update Packages/VRM10/Runtime/IO/Vrm10Importer.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- Packages/VRM10/Runtime/IO/Vrm10Importer.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Packages/VRM10/Runtime/IO/Vrm10Importer.cs b/Packages/VRM10/Runtime/IO/Vrm10Importer.cs index ae51eb0ae..557b51b7d 100644 --- a/Packages/VRM10/Runtime/IO/Vrm10Importer.cs +++ b/Packages/VRM10/Runtime/IO/Vrm10Importer.cs @@ -6,7 +6,6 @@ using System.Threading.Tasks; using UniGLTF; using UniGLTF.Extensions.VRMC_springBone_limit; using UniGLTF.Utils; -using UnityEditor.Experimental.GraphView; using UnityEngine; namespace UniVRM10 From 8f8493f129e1aa15618b9a67cf3d0cc25a600add Mon Sep 17 00:00:00 2001 From: ousttrue Date: Tue, 24 Mar 2026 14:14:21 +0900 Subject: [PATCH 13/15] rename typo --- .../{NodeTransformtBinding.cs => NodeTransformBinding.cs} | 0 ...NodeTransformtBinding.cs.meta => NodeTransformBinding.cs.meta} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename Packages/VRM10/Runtime/Components/Expression/{NodeTransformtBinding.cs => NodeTransformBinding.cs} (100%) rename Packages/VRM10/Runtime/Components/Expression/{NodeTransformtBinding.cs.meta => NodeTransformBinding.cs.meta} (100%) diff --git a/Packages/VRM10/Runtime/Components/Expression/NodeTransformtBinding.cs b/Packages/VRM10/Runtime/Components/Expression/NodeTransformBinding.cs similarity index 100% rename from Packages/VRM10/Runtime/Components/Expression/NodeTransformtBinding.cs rename to Packages/VRM10/Runtime/Components/Expression/NodeTransformBinding.cs diff --git a/Packages/VRM10/Runtime/Components/Expression/NodeTransformtBinding.cs.meta b/Packages/VRM10/Runtime/Components/Expression/NodeTransformBinding.cs.meta similarity index 100% rename from Packages/VRM10/Runtime/Components/Expression/NodeTransformtBinding.cs.meta rename to Packages/VRM10/Runtime/Components/Expression/NodeTransformBinding.cs.meta From ff79bc93e88488931c24a714cabef4c29be054a6 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Tue, 24 Mar 2026 14:20:26 +0900 Subject: [PATCH 14/15] Update Packages/VRM10/Runtime/IO/Vrm10Exporter.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- Packages/VRM10/Runtime/IO/Vrm10Exporter.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Packages/VRM10/Runtime/IO/Vrm10Exporter.cs b/Packages/VRM10/Runtime/IO/Vrm10Exporter.cs index 6555d76d8..ae243a276 100644 --- a/Packages/VRM10/Runtime/IO/Vrm10Exporter.cs +++ b/Packages/VRM10/Runtime/IO/Vrm10Exporter.cs @@ -781,11 +781,13 @@ namespace UniVRM10 static UniGLTF.Extensions.VRMC_vrm_expressions_node_transform.NodeTransformBind ExportNodeTransformBinding(NodeTransformBinding binding, Func getIndex) { + var translation = ReverseX(binding.OffsetTranslation); + var rotation = ReverseX(binding.OffsetRotation); return new UniGLTF.Extensions.VRMC_vrm_expressions_node_transform.NodeTransformBind { Node = getIndex(binding.RelativePath), - Translation = new float[] { binding.OffsetTranslation.x, binding.OffsetTranslation.y, binding.OffsetTranslation.z }, - Rotation = new float[] { binding.OffsetRotation.x, binding.OffsetRotation.y, binding.OffsetRotation.z, binding.OffsetRotation.w }, + Translation = new float[] { translation.x, translation.y, translation.z }, + Rotation = new float[] { rotation.x, rotation.y, rotation.z, rotation.w }, Scale = new float[] { binding.TargetScale.x, binding.TargetScale.y, binding.TargetScale.z }, }; } From a2f69b857c7fb5ebf01fdd74fe40536adfa506d7 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 27 Oct 2025 09:44:21 +1000 Subject: [PATCH 15/15] Change RenderPipelineUtility to use GraphicsSettings.currentRenderPipeline --- .../UniGLTF/IO/MaterialIO/RenderPipelineUtility.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Packages/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/RenderPipelineUtility.cs b/Packages/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/RenderPipelineUtility.cs index 76ecc0547..d072bec45 100644 --- a/Packages/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/RenderPipelineUtility.cs +++ b/Packages/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/RenderPipelineUtility.cs @@ -1,4 +1,4 @@ -using UnityEngine.Rendering; +using UnityEngine.Rendering; namespace UniGLTF { @@ -6,19 +6,19 @@ namespace UniGLTF { public static RenderPipelineTypes GetRenderPipelineType() { - RenderPipeline currentPipeline = RenderPipelineManager.currentPipeline; + RenderPipelineAsset currentRenderPipelineAsset = GraphicsSettings.currentRenderPipeline; - if (currentPipeline == null) + if (currentRenderPipelineAsset == null) { return RenderPipelineTypes.BuiltinRenderPipeline; } - if (currentPipeline.GetType().Name.Contains("HDRenderPipeline")) + if (currentRenderPipelineAsset.GetType().Name.Contains("HDRenderPipeline")) { return RenderPipelineTypes.HighDefinitionRenderPipeline; } - if (currentPipeline.GetType().Name.Contains("UniversalRenderPipeline")) + if (currentRenderPipelineAsset.GetType().Name.Contains("UniversalRenderPipeline")) { return RenderPipelineTypes.UniversalRenderPipeline; } @@ -26,4 +26,4 @@ namespace UniGLTF return RenderPipelineTypes.Unknown; } } -} \ No newline at end of file +}