diff --git a/Assets/VRM10/Runtime/Components/SpringBone/SpringBoneLogic.cs b/Assets/VRM10/Runtime/Components/SpringBone/SpringBoneLogic.cs index 6a72f1f5a..0543c0d9c 100644 --- a/Assets/VRM10/Runtime/Components/SpringBone/SpringBoneLogic.cs +++ b/Assets/VRM10/Runtime/Components/SpringBone/SpringBoneLogic.cs @@ -36,8 +36,6 @@ namespace UniVRM10 } public Vector3 m_boneAxis; - public float Radius { get; set; } - public SpringBoneLogic(Transform center, Transform transform, Vector3 localChildPosition) { m_transform = transform; @@ -73,7 +71,7 @@ namespace UniVRM10 public void Update(Transform center, float stiffnessForce, float dragForce, Vector3 external, - List colliders) + List colliders, float jointRadius) { var currentTail = center != null ? center.TransformPoint(m_currentTail) @@ -95,7 +93,7 @@ namespace UniVRM10 nextTail = m_transform.position + (nextTail - m_transform.position).normalized * m_length; // Collisionで移動 - nextTail = Collision(colliders, nextTail); + nextTail = Collision(colliders, nextTail, jointRadius); m_prevTail = center != null ? center.InverseTransformPoint(currentTail) @@ -117,14 +115,14 @@ namespace UniVRM10 nextTail - m_transform.position) * rotation; } - bool TrySphereCollision(Vector3 worldPosition, float radius, ref Vector3 nextTail) + bool TrySphereCollision(Vector3 worldPosition, float radius, ref Vector3 nextTail, float jointRadius) { - var r = Radius + radius; + var r = jointRadius + radius; if (Vector3.SqrMagnitude(nextTail - worldPosition) <= (r * r)) { // ヒット。Colliderの半径方向に押し出す var normal = (nextTail - worldPosition).normalized; - var posFromCollider = worldPosition + normal * (Radius + radius); + var posFromCollider = worldPosition + normal * (jointRadius + radius); // 長さをboneLengthに強制 nextTail = m_transform.position + (posFromCollider - m_transform.position).normalized * m_length; return true; @@ -135,7 +133,7 @@ namespace UniVRM10 } } - bool TryCapsuleCollision(in InternalCollider collider, ref Vector3 nextTail) + bool TryCapsuleCollision(in InternalCollider collider, ref Vector3 nextTail, float jointRadius) { var P = collider.WorldTail - collider.WorldPosition; var Q = m_transform.position - collider.WorldPosition; @@ -143,22 +141,22 @@ namespace UniVRM10 if (dot <= 0) { // head側半球の球判定 - return TrySphereCollision(collider.WorldPosition, collider.Radius, ref nextTail); + return TrySphereCollision(collider.WorldPosition, collider.Radius, ref nextTail, jointRadius); } var t = dot / P.magnitude; if (t >= 1.0f) { // tail側半球の球判定 - return TrySphereCollision(collider.WorldTail, collider.Radius, ref nextTail); + return TrySphereCollision(collider.WorldTail, collider.Radius, ref nextTail, jointRadius); } // head-tail上の m_transform.position との最近点 var p = collider.WorldPosition + P * t; - return TrySphereCollision(p, collider.Radius, ref nextTail); + return TrySphereCollision(p, collider.Radius, ref nextTail, jointRadius); } - protected virtual Vector3 Collision(List colliders, Vector3 nextTail) + protected virtual Vector3 Collision(List colliders, Vector3 nextTail, float jointRadius) { foreach (var collider in colliders) { @@ -166,11 +164,11 @@ namespace UniVRM10 switch (collider.ColliderTypes) { case VRM10SpringBoneColliderTypes.Sphere: - TrySphereCollision(collider.WorldPosition, collider.Radius, ref nextTail); + TrySphereCollision(collider.WorldPosition, collider.Radius, ref nextTail, jointRadius); break; case VRM10SpringBoneColliderTypes.Capsule: - TryCapsuleCollision(in collider, ref nextTail); + TryCapsuleCollision(in collider, ref nextTail, jointRadius); break; default: diff --git a/Assets/VRM10/Runtime/Components/SpringBone/SpringBoneProcessor.cs b/Assets/VRM10/Runtime/Components/SpringBone/SpringBoneProcessor.cs deleted file mode 100644 index 3d4add914..000000000 --- a/Assets/VRM10/Runtime/Components/SpringBone/SpringBoneProcessor.cs +++ /dev/null @@ -1,111 +0,0 @@ -using System.Collections.Generic; -using UnityEngine; - -namespace UniVRM10 -{ - public class SpringBoneProcessor - { - List m_logics = new List(); - Dictionary m_initialLocalRotationMap; - - - public void ResetSpringBone() - { - foreach (var verlet in m_logics) - { - verlet.Head.localRotation = Quaternion.identity; - } - } - - public void SetupRecursive(Transform parent, Transform center) - { - if (parent.childCount == 0) - { - // 末端に追加のスプリングを付加する - var delta = parent.position - parent.parent.position; - var childPosition = parent.position + delta.normalized * 0.07f; - m_logics.Add(new SpringBoneLogic(center, parent, parent.worldToLocalMatrix.MultiplyPoint(childPosition))); - } - else - { - // 最初の子ボーンを尻尾としてスプリングを付加する - var firstChild = parent.GetChild(0); - var localPosition = firstChild.localPosition; - var scale = firstChild.lossyScale; - m_logics.Add(new SpringBoneLogic(center, parent, - new Vector3( - localPosition.x * scale.x, - localPosition.y * scale.y, - localPosition.z * scale.z - ))) - ; - } - - foreach (Transform child in parent) - { - SetupRecursive(child, center); - } - } - - void Setup(List RootBones, Transform m_center, bool force = false) - { - if (force || m_initialLocalRotationMap == null) - { - m_initialLocalRotationMap = new Dictionary(); - } - else - { - // restore initial rotation - foreach (var kv in m_initialLocalRotationMap) - { - kv.Key.localRotation = kv.Value; - } - m_initialLocalRotationMap.Clear(); - } - m_logics.Clear(); - - foreach (var transform in RootBones) - { - if (transform != null) - { - foreach (var x in transform.Traverse()) - { - // backup initial rotation - m_initialLocalRotationMap[x] = x.localRotation; - } - - SetupRecursive(transform, m_center); - } - } - } - - public void Update(List RootBones, List m_colliderList, - float stiffness, float m_dragForce, Vector3 external, - float m_hitRadius, Transform m_center) - { - if (m_logics == null || m_logics.Count == 0) - { - Setup(RootBones, m_center); - } - - foreach (var verlet in m_logics) - { - verlet.Radius = m_hitRadius; - verlet.Update(m_center, - stiffness, - m_dragForce, - external, - m_colliderList - ); - } - } - - public void DrawGizmos(Transform m_center, float m_hitRadius, Color m_gizmoColor) - { - foreach (var verlet in m_logics) - { - verlet.DrawGizmo(m_center, m_hitRadius, m_gizmoColor); - } - } - } -} diff --git a/Assets/VRM10/Runtime/Components/SpringBone/VRM10SpringBone.cs b/Assets/VRM10/Runtime/Components/SpringBone/VRM10SpringBone.cs index 736532148..561ca4f2a 100644 --- a/Assets/VRM10/Runtime/Components/SpringBone/VRM10SpringBone.cs +++ b/Assets/VRM10/Runtime/Components/SpringBone/VRM10SpringBone.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using UnityEngine; namespace UniVRM10 @@ -20,25 +21,6 @@ namespace UniVRM10 [SerializeField] Color m_gizmoColor = Color.yellow; - [Serializable] - public class VRM10SpringJoint - { - [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, Range(0, 0.5f), Header("Collision")] - public float m_hitRadius = 0.02f; - } - [SerializeField] public Transform m_center; @@ -48,12 +30,17 @@ namespace UniVRM10 [SerializeField] public List ColliderGroups = new List(); - SpringBoneProcessor m_processor = new SpringBoneProcessor(); [ContextMenu("Reset bones")] - public void ResetSpringBone() + public void ResetJoints() { - m_processor.ResetSpringBone(); + foreach (var joint in Joints) + { + if (joint != null) + { + joint.Transform.localRotation = Quaternion.identity; + } + } } List m_colliderList = new List(); @@ -101,20 +88,30 @@ namespace UniVRM10 } } - // var stiffness = m_stiffnessForce * Time.deltaTime; - // var external = m_gravityDir * (m_gravityPower * Time.deltaTime); - - // m_processor.Update(RootBones, m_colliderList, - // stiffness, m_dragForce, external, - // m_hitRadius, m_center); + { + // udpate joints + VRM10SpringJoint lastJoint = Joints.FirstOrDefault(x => x != null); + foreach (var joint in Joints.Where(x => x != null).Skip(1)) + { + lastJoint.Update(m_center, Time.deltaTime, m_colliderList, joint); + lastJoint = joint; + } + lastJoint.Update(m_center, Time.deltaTime, m_colliderList, null); + } } private void OnDrawGizmos() { - // if (m_drawGizmo) - // { - // m_processor.DrawGizmos(m_center, m_hitRadius, m_gizmoColor); - // } + if (m_drawGizmo) + { + foreach (var joint in Joints) + { + if (joint != null) + { + joint.DrawGizmo(m_center, m_gizmoColor); + } + } + } } } } diff --git a/Assets/VRM10/Runtime/Components/SpringBone/VRM10SpringJoint.cs b/Assets/VRM10/Runtime/Components/SpringBone/VRM10SpringJoint.cs new file mode 100644 index 000000000..4f44cf97a --- /dev/null +++ b/Assets/VRM10/Runtime/Components/SpringBone/VRM10SpringJoint.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace UniVRM10 +{ + [Serializable] + public class VRM10SpringJoint + { + [SerializeField] + public Transform Transform; + + public VRM10SpringJoint(Transform t) + { + Transform = t; + } + + [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, Range(0, 0.5f), Header("Collision")] + public float m_hitRadius = 0.02f; + + SpringBoneLogic m_logic; + + public void DrawGizmo(Transform center, Color color) + { + if (m_logic != null) + { + m_logic.DrawGizmo(center, m_hitRadius, color); + } + else + { + // TODO + } + } + + public void Update(Transform center, float deltaTime, List colliders, VRM10SpringJoint tail) + { + if (m_logic == null) + { + // Setup(joints, m_center); + // SetupRecursive(joint, m_center); + if (tail == null) + { + // 末端に追加のスプリングを付加する + 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)); + } + else + { + // 最初の子ボーンを尻尾としてスプリングを付加する + 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 + )); + } + } + + m_logic.Update(center, m_stiffnessForce * deltaTime, m_dragForce, m_gravityDir * (m_gravityPower * deltaTime), colliders, m_hitRadius); + } + } +} diff --git a/Assets/VRM10/Runtime/Components/SpringBone/SpringBoneProcessor.cs.meta b/Assets/VRM10/Runtime/Components/SpringBone/VRM10SpringJoint.cs.meta similarity index 83% rename from Assets/VRM10/Runtime/Components/SpringBone/SpringBoneProcessor.cs.meta rename to Assets/VRM10/Runtime/Components/SpringBone/VRM10SpringJoint.cs.meta index 51b9ea6c2..0fab6c6f8 100644 --- a/Assets/VRM10/Runtime/Components/SpringBone/SpringBoneProcessor.cs.meta +++ b/Assets/VRM10/Runtime/Components/SpringBone/VRM10SpringJoint.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: fb0714842bac26b44b774260bbef58c3 +guid: 5a7fc353e202e4f44a1025ba6e806262 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/VRM10/Runtime/IO/Vrm10Storage.cs b/Assets/VRM10/Runtime/IO/Vrm10Storage.cs index bcd3204fd..d9eee6f4d 100644 --- a/Assets/VRM10/Runtime/IO/Vrm10Storage.cs +++ b/Assets/VRM10/Runtime/IO/Vrm10Storage.cs @@ -606,7 +606,7 @@ namespace UniVRM10 static void AssignHumanoid(List nodes, UniGLTF.Extensions.VRMC_vrm.HumanBone humanBone, VrmLib.HumanoidBones key) { - if (humanBone!=null && humanBone.Node.HasValue) + if (humanBone != null && humanBone.Node.HasValue) { nodes[humanBone.Node.Value].HumanoidBone = key; } @@ -722,7 +722,7 @@ namespace UniVRM10 // joint foreach (var gltfJoint in gltfSpring.Joints) { - var joint = new SpringJoint(); + var joint = new SpringJoint(nodes[gltfJoint.Node.Value]); joint.HitRadius = gltfJoint.HitRadius.Value; joint.DragForce = gltfJoint.DragForce.Value; joint.GravityDir = gltfJoint.GravityDir.ToVector3(); diff --git a/Assets/VRM10/Runtime/Migration/Migration.cs b/Assets/VRM10/Runtime/Migration/Migration.cs index 04cc8b097..720776d14 100644 --- a/Assets/VRM10/Runtime/Migration/Migration.cs +++ b/Assets/VRM10/Runtime/Migration/Migration.cs @@ -606,7 +606,6 @@ namespace UniVRM10 public static void Check(ListTreeNode vrm0, UniGLTF.Extensions.VRMC_springBone.VRMC_springBone vrm1, List nodes) { - var a = 0; // Migration.CheckSpringBone(vrm0["secondaryAnimation"], vrm1.sp) } #endregion diff --git a/Assets/VRM10/Runtime/UnityBuilder/ComponentBuilder.cs b/Assets/VRM10/Runtime/UnityBuilder/ComponentBuilder.cs index 33ca9cb1b..45ed6c4e9 100644 --- a/Assets/VRM10/Runtime/UnityBuilder/ComponentBuilder.cs +++ b/Assets/VRM10/Runtime/UnityBuilder/ComponentBuilder.cs @@ -300,7 +300,8 @@ namespace UniVRM10 // create joint for the spring foreach (var vrmJoint in vrmSpring.Joints) { - var joint = new VRM10SpringBone.VRM10SpringJoint(); + var go = asset.Map.Nodes[vrmJoint.Node]; + var joint = new VRM10SpringJoint(go.transform); joint.m_stiffnessForce = vrmJoint.Stiffness; joint.m_gravityPower = vrmJoint.GravityPower; diff --git a/Assets/VRM10/Runtime/VRMConverter/RuntimeVrmConverter.cs b/Assets/VRM10/Runtime/VRMConverter/RuntimeVrmConverter.cs index d3518c5f1..8b1f3c94e 100644 --- a/Assets/VRM10/Runtime/VRMConverter/RuntimeVrmConverter.cs +++ b/Assets/VRM10/Runtime/VRMConverter/RuntimeVrmConverter.cs @@ -356,7 +356,7 @@ namespace UniVRM10 foreach (var joint in springBone.Joints) { - vrmSpringBone.Joints.Add(new VrmLib.SpringJoint + vrmSpringBone.Joints.Add(new VrmLib.SpringJoint(Nodes[joint.Transform.gameObject]) { Stiffness = joint.m_stiffnessForce, GravityPower = joint.m_gravityPower, diff --git a/Assets/VRM10/vrmlib/Runtime/Vrm/SpringBoneManager.cs b/Assets/VRM10/vrmlib/Runtime/Vrm/SpringBoneManager.cs index 0edd20ec8..270a940e7 100644 --- a/Assets/VRM10/vrmlib/Runtime/Vrm/SpringBoneManager.cs +++ b/Assets/VRM10/vrmlib/Runtime/Vrm/SpringBoneManager.cs @@ -53,6 +53,11 @@ namespace VrmLib { public readonly Node Node; + public SpringJoint(Node node) + { + Node = node; + } + public float DragForce; public Vector3 GravityDir;