diff --git a/Assets/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneJoint.cs b/Assets/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneJoint.cs new file mode 100644 index 000000000..9ad55c194 --- /dev/null +++ b/Assets/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneJoint.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +#if UNITY_EDITOR +using UnityEditor; +#endif + +namespace UniVRM10 +{ + [Serializable] + public class VRM10SpringBoneJoint : MonoBehaviour + { + [SerializeField, Range(0, 4), Header("Settings")] + public float m_stiffnessForce = 1.0f; + + [SerializeField, Range(0, 2)] + public float m_gravityPower = 0; + + [SerializeField] + public Vector3 m_gravityDir = new Vector3(0, -1.0f, 0); + + [SerializeField, Range(0, 1)] + public float m_dragForce = 0.4f; + + [SerializeField] + public bool m_exclude; + + [SerializeField, Range(0, 0.5f), Header("Collision")] + public float m_jointRadius = 0.02f; + + SpringBoneLogic m_logic; + + public void DrawGizmo(Transform center, Color color) + { + if (m_logic != null) + { + m_logic.DrawGizmo(center, m_jointRadius, color); + } + else + { +#if UNITY_EDITOR + // Gizmos.matrix = Transform.localToWorldMatrix; + Gizmos.color = color; + Gizmos.DrawSphere(transform.position, m_jointRadius); +#endif + } + } + } +} diff --git a/Assets/VRM10/Runtime/Components/SpringBone/VRM10SpringJoint.cs.meta b/Assets/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneJoint.cs.meta similarity index 83% rename from Assets/VRM10/Runtime/Components/SpringBone/VRM10SpringJoint.cs.meta rename to Assets/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneJoint.cs.meta index 0fab6c6f8..1f0db6050 100644 --- a/Assets/VRM10/Runtime/Components/SpringBone/VRM10SpringJoint.cs.meta +++ b/Assets/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneJoint.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 5a7fc353e202e4f44a1025ba6e806262 +guid: 0a942e03b39600e41a1b161e958048f7 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/VRM10/Runtime/Components/SpringBone/VRM10SpringJoint.cs b/Assets/VRM10/Runtime/Components/SpringBone/VRM10SpringJoint.cs deleted file mode 100644 index d9889c509..000000000 --- a/Assets/VRM10/Runtime/Components/SpringBone/VRM10SpringJoint.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System; -using System.Collections.Generic; -using UnityEngine; -#if UNITY_EDITOR -using UnityEditor; -#endif - -namespace UniVRM10 -{ - [Serializable] - public class VRM10SpringJoint : MonoBehaviour - { - [SerializeField, Range(0, 4), Header("Settings")] - public float m_stiffnessForce = 1.0f; - - [SerializeField, Range(0, 2)] - public float m_gravityPower = 0; - - [SerializeField] - public Vector3 m_gravityDir = new Vector3(0, -1.0f, 0); - - [SerializeField, Range(0, 1)] - public float m_dragForce = 0.4f; - - [SerializeField] - public bool m_exclude; - - [SerializeField, Range(0, 0.5f), Header("Collision")] - public float m_jointRadius = 0.02f; - - SpringBoneLogic m_logic; - - public void DrawGizmo(Transform center, Color color) - { - if (m_logic != null) - { - m_logic.DrawGizmo(center, m_jointRadius, color); - } - else - { -#if UNITY_EDITOR - // Gizmos.matrix = Transform.localToWorldMatrix; - Gizmos.color = color; - Gizmos.DrawSphere(transform.position, m_jointRadius); -#endif - } - } - - public void Process(Transform center, float deltaTime, List colliders, VRM10SpringJoint tail) - { - if (m_logic == null) - { - // 初期化 - if (tail != null) - { - var localPosition = tail.transform.localPosition; - var scale = tail.transform.lossyScale; - m_logic = new SpringBoneLogic(center, transform, - new Vector3( - localPosition.x * scale.x, - localPosition.y * scale.y, - localPosition.z * scale.z - )); - } - else - { - // 親からまっすぐの位置に tail を作成 - var delta = transform.position - transform.parent.position; - var childPosition = transform.position + delta.normalized * 0.07f; - m_logic = new SpringBoneLogic(center, transform, transform.worldToLocalMatrix.MultiplyPoint(childPosition)); - } - } - - m_logic.Update(center, m_stiffnessForce * deltaTime, m_dragForce, m_gravityDir * (m_gravityPower * deltaTime), colliders, m_jointRadius); - } - } -} diff --git a/Assets/VRM10/Runtime/Components/VRM10ControllerSpringBone.cs b/Assets/VRM10/Runtime/Components/VRM10ControllerSpringBone.cs index 55861be9a..e664d0239 100644 --- a/Assets/VRM10/Runtime/Components/VRM10ControllerSpringBone.cs +++ b/Assets/VRM10/Runtime/Components/VRM10ControllerSpringBone.cs @@ -32,10 +32,11 @@ namespace UniVRM10 public List ColliderGroups = new List(); [SerializeField] - public List Joints = new List(); + public List Joints = new List(); Transform m_center; List m_colliderList; + List<(VRM10SpringBoneJoint, SpringBoneLogic)> m_logics; public Spring(string name) { @@ -88,18 +89,32 @@ namespace UniVRM10 } } + if (m_logics == null) { - // udpate joints - VRM10SpringJoint lastJoint = Joints.FirstOrDefault(x => x != null); - foreach (var joint in Joints.Where(x => x != null).Skip(1)) + m_logics = Enumerable.Zip(Joints, Joints.Skip(1), (head, tail) => { - lastJoint.Process(center, Time.deltaTime, m_colliderList, joint); - lastJoint = joint; - } - lastJoint.Process(center, Time.deltaTime, m_colliderList, null); + var localPosition = tail.transform.localPosition; + var scale = tail.transform.lossyScale; + var logic = new SpringBoneLogic(center, head.transform, + new Vector3( + localPosition.x * scale.x, + localPosition.y * scale.y, + localPosition.z * scale.z + )); + return (head, logic); + }).ToList(); + } + foreach (var (head, logic) in m_logics) + { + logic.Update(center, + head.m_stiffnessForce * Time.deltaTime, + head.m_dragForce, + head.m_gravityDir * (head.m_gravityPower * Time.deltaTime), + m_colliderList, head.m_jointRadius); } } } + [SerializeField] public List Springs = new List(); diff --git a/Assets/VRM10/Runtime/IO/Vrm10Exporter.cs b/Assets/VRM10/Runtime/IO/Vrm10Exporter.cs index 10121ce1a..a0032e254 100644 --- a/Assets/VRM10/Runtime/IO/Vrm10Exporter.cs +++ b/Assets/VRM10/Runtime/IO/Vrm10Exporter.cs @@ -299,7 +299,7 @@ namespace UniVRM10 return shape; } - UniGLTF.Extensions.VRMC_springBone.SpringBoneJoint ExportJoint(VRM10SpringJoint y, Func getIndexFromTransform) + UniGLTF.Extensions.VRMC_springBone.SpringBoneJoint ExportJoint(VRM10SpringBoneJoint y, Func getIndexFromTransform) { var joint = new UniGLTF.Extensions.VRMC_springBone.SpringBoneJoint { diff --git a/Assets/VRM10/Runtime/IO/Vrm10Importer.cs b/Assets/VRM10/Runtime/IO/Vrm10Importer.cs index 2e860ddde..c8b2fd5e8 100644 --- a/Assets/VRM10/Runtime/IO/Vrm10Importer.cs +++ b/Assets/VRM10/Runtime/IO/Vrm10Importer.cs @@ -429,7 +429,7 @@ namespace UniVRM10 { throw new IndexOutOfRangeException($"{index} > {Nodes.Count}"); } - var joint = Nodes[gltfJoint.Node.Value].gameObject.AddComponent(); + var joint = Nodes[gltfJoint.Node.Value].gameObject.AddComponent(); joint.m_jointRadius = gltfJoint.HitRadius.Value; joint.m_dragForce = gltfJoint.DragForce.Value; joint.m_gravityDir = Vector3InvertX(gltfJoint.GravityDir); diff --git a/Assets/VRM10/Runtime/Migration/MigrationVrmSpringBone.cs b/Assets/VRM10/Runtime/Migration/MigrationVrmSpringBone.cs index bb8deeb59..47e02e07b 100644 --- a/Assets/VRM10/Runtime/Migration/MigrationVrmSpringBone.cs +++ b/Assets/VRM10/Runtime/Migration/MigrationVrmSpringBone.cs @@ -6,19 +6,49 @@ namespace UniVRM10 { public static class MigrationVrmSpringBone { - static IEnumerable EnumJoint(List nodes, UniGLTF.glTFNode node) + static IEnumerable TraverseFirstChild(List nodes, UniGLTF.glTFNode node) { yield return node; if (node.children != null && node.children.Length > 0) { - foreach (var x in EnumJoint(nodes, nodes[node.children[0]])) + foreach (var x in TraverseFirstChild(nodes, nodes[node.children[0]])) { yield return x; } } } + static void AddTail7cm(UniGLTF.glTF gltf, UniGLTF.glTFNode[] joints) + { + if (joints.Length < 2) + { + return; + } + var last = joints.Last(); + var name = last.name ?? ""; + var v1 = new UnityEngine.Vector3(last.translation[0], last.translation[1], last.translation[2]); + // var last2 = joints[joints.Length - 2]; + // var v2 = new UnityEngine.Vector3(last2.translation[0], last2.translation[1], last2.translation[2]); + var delta = v1.normalized * 0.07f; // 7cm + var tail = new UniGLTF.glTFNode + { + name = name + "_end", + translation = new float[] { + delta.x, + delta.y, + delta.z + }, + }; + var tail_index = gltf.nodes.Count; + gltf.nodes.Add(tail); + if (last.children != null && last.children.Length > 0) + { + throw new System.Exception(); + } + last.children = new[] { tail_index }; + } + public static UniGLTF.Extensions.VRMC_springBone.VRMC_springBone Migrate(UniGLTF.glTF gltf, JsonNode sa) { var colliderNodes = new List(); @@ -86,6 +116,18 @@ namespace UniVRM10 } } + // https://github.com/vrm-c/vrm-specification/pull/255 + // 1.0 では末端に7cmの遠さに joint を追加する動作をしなくなった。 + // その差異に対応して、7cmの遠さに node を追加する。 + foreach (var x in sa["boneGroups"].ArrayItems()) + { + foreach (var y in x["bones"].ArrayItems()) + { + var joints = TraverseFirstChild(gltf.nodes, gltf.nodes[y.GetInt32()]).ToArray(); + AddTail7cm(gltf, joints); + } + } + foreach (var x in sa["boneGroups"].ArrayItems()) { // { @@ -123,7 +165,7 @@ namespace UniVRM10 Joints = new List(), }; - foreach (var z in EnumJoint(gltf.nodes, gltf.nodes[y.GetInt32()])) + foreach (var z in TraverseFirstChild(gltf.nodes, gltf.nodes[y.GetInt32()])) { spring.Joints.Add(new UniGLTF.Extensions.VRMC_springBone.SpringBoneJoint {