diff --git a/Assets/VRM/Runtime/SpringBone/Logic/SphereCollider.cs b/Assets/VRM/Runtime/SpringBone/Logic/SphereCollider.cs
index a59c36e8c..880ebeb49 100644
--- a/Assets/VRM/Runtime/SpringBone/Logic/SphereCollider.cs
+++ b/Assets/VRM/Runtime/SpringBone/Logic/SphereCollider.cs
@@ -14,5 +14,20 @@ namespace VRM.SpringBone
var scale = Mathf.Max(Mathf.Max(ls.x, ls.y), ls.z);
Radius = scale * collider.Radius;
}
+
+ public Vector3 Collide(SpringBoneSettings settings, Transform m_transform, SpringBoneJointInit init, Vector3 nextTail)
+ {
+ var m_radius = settings.HitRadius * m_transform.UniformedLossyScale();
+ var r = m_radius + Radius;
+ if (Vector3.SqrMagnitude(nextTail - Position) <= (r * r))
+ {
+ // ヒット。Colliderの半径方向に押し出す
+ var normal = (nextTail - Position).normalized;
+ var posFromCollider = Position + normal * (m_radius + Radius);
+ // 長さをboneLengthに強制
+ nextTail = m_transform.position + (posFromCollider - m_transform.position).normalized * init.Length;
+ }
+ return nextTail;
+ }
}
}
\ No newline at end of file
diff --git a/Assets/VRM/Runtime/SpringBone/Logic/SpringBoneJointInit.cs b/Assets/VRM/Runtime/SpringBone/Logic/SpringBoneJointInit.cs
index d4cad9ab3..59f8ce7e3 100644
--- a/Assets/VRM/Runtime/SpringBone/Logic/SpringBoneJointInit.cs
+++ b/Assets/VRM/Runtime/SpringBone/Logic/SpringBoneJointInit.cs
@@ -1,49 +1,57 @@
+using System.Collections.Generic;
using UnityEngine;
namespace VRM.SpringBone
{
- struct JointState
+ ///
+ /// original from
+ /// http://rocketjump.skr.jp/unity3d/109/
+ ///
+ /// この型のフィールドはSpringBoneのライフサイクルを通じて不変。
+ ///
+ struct SpringBoneJointInit
{
- public Vector3 CurrentTail;
- public Vector3 PrevTail;
+ public Vector3 BoneAxis;
+ public float Length;
+ public Quaternion LocalRotation;
- public static JointState Init(Transform center, Transform transform, Vector3 localChildPosition)
+ public Quaternion CalcRotation(Transform m_transform, Vector3 nextTail)
{
- var worldChildPosition = transform.TransformPoint(localChildPosition);
- var tail = center != null
- ? center.InverseTransformPoint(worldChildPosition)
- : worldChildPosition;
- return new JointState
- {
- CurrentTail = tail,
- PrevTail = tail,
- };
+ var rotation = (m_transform.parent != null ? m_transform.parent.rotation : Quaternion.identity) * LocalRotation;
+ return Quaternion.FromToRotation(rotation * BoneAxis,
+ nextTail - m_transform.position) * rotation;
}
- public static JointState Make(Transform center, Vector3 currentTail, Vector3 nextTail)
+ public Vector3 CalcNextTail(float deltaTime, Transform center, Transform m_transform,
+ SpringBoneSettings settings, SpringBoneJointState _state)
{
- return new JointState
- {
- PrevTail = center != null
- ? center.InverseTransformPoint(currentTail)
- : currentTail,
- CurrentTail = center != null
- ? center.InverseTransformPoint(nextTail)
- : nextTail,
- };
+ var state = _state.ToWorld(center);
+
+ // verlet積分で次の位置を計算
+ var nextTail = state.CurrentTail
+ + (state.CurrentTail - state.PrevTail) * (1.0f - settings.DragForce) // 前フレームの移動を継続する(減衰もあるよ)
+ + (m_transform.parent != null ? m_transform.parent.rotation : Quaternion.identity) * LocalRotation * BoneAxis * settings.StiffnessForce * deltaTime // 親の回転による子ボーンの移動目標
+ + settings.GravityDir * (settings.GravityPower * deltaTime); // 外力による移動量
+
+ // 長さをboneLengthに強制
+ var position = m_transform.position;
+ nextTail = position + (nextTail - position).normalized * Length;
+ return nextTail;
}
- public JointState ToWorld(Transform center)
+ public void DrawGizmo(Transform center, Transform m_transform, SpringBoneSettings settings, Color color, SpringBoneJointState m_state)
{
- return new JointState
- {
- CurrentTail = center != null
- ? center.TransformPoint(CurrentTail)
- : CurrentTail,
- PrevTail = center != null
- ? center.TransformPoint(PrevTail)
- : PrevTail,
- };
+ var state = m_state.ToWorld(center);
+ var m_radius = settings.HitRadius * m_transform.UniformedLossyScale();
+
+ Gizmos.color = Color.gray;
+ Gizmos.DrawLine(state.CurrentTail, state.PrevTail);
+ Gizmos.DrawWireSphere(state.PrevTail, m_radius);
+
+ Gizmos.color = color;
+ Gizmos.DrawLine(state.CurrentTail, m_transform.position);
+ Gizmos.DrawWireSphere(state.CurrentTail, m_radius);
}
+
};
}
\ No newline at end of file
diff --git a/Assets/VRM/Runtime/SpringBone/Logic/SpringBoneJointInit.cs.meta b/Assets/VRM/Runtime/SpringBone/Logic/SpringBoneJointInit.cs.meta
index b68add524..70dd7502d 100644
--- a/Assets/VRM/Runtime/SpringBone/Logic/SpringBoneJointInit.cs.meta
+++ b/Assets/VRM/Runtime/SpringBone/Logic/SpringBoneJointInit.cs.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
-guid: 3bbcafd66c035184b8aa868b65c01c1d
+guid: 2602939771f9eb2428b140e10fa899f2
MonoImporter:
externalObjects: {}
serializedVersion: 2
diff --git a/Assets/VRM/Runtime/SpringBone/Logic/SpringBoneJointState.cs b/Assets/VRM/Runtime/SpringBone/Logic/SpringBoneJointState.cs
index 873bd7b22..c54b74a5a 100644
--- a/Assets/VRM/Runtime/SpringBone/Logic/SpringBoneJointState.cs
+++ b/Assets/VRM/Runtime/SpringBone/Logic/SpringBoneJointState.cs
@@ -1,80 +1,52 @@
-using System.Collections.Generic;
using UnityEngine;
namespace VRM.SpringBone
{
///
- /// original from
- /// http://rocketjump.skr.jp/unity3d/109/
- ///
- /// Joint 状態(初期・フレーム)を管理する
+ /// 毎フレーム更新される Verlet 積分の位置状態
///
- struct SpringBoneJointInit
+ struct SpringBoneJointState
{
- public Vector3 BoneAxis;
- public float Length;
- public Quaternion LocalRotation;
+ public Vector3 CurrentTail;
+ public Vector3 PrevTail;
- public Quaternion CalcRotation(Transform m_transform, Vector3 nextTail)
+ public static SpringBoneJointState Init(Transform center, Transform transform, Vector3 localChildPosition)
{
- var rotation = (m_transform.parent != null ? m_transform.parent.rotation : Quaternion.identity) * LocalRotation;
- return Quaternion.FromToRotation(rotation * BoneAxis,
- nextTail - m_transform.position) * rotation;
- }
-
- public JointState Update(float deltaTime, Transform center, Transform m_transform,
- SpringBoneSettings settings,
- List colliders, JointState _state)
- {
- var state = _state.ToWorld(center);
-
- // verlet積分で次の位置を計算
- var nextTail = state.CurrentTail
- + (state.CurrentTail - state.PrevTail) * (1.0f - settings.DragForce) // 前フレームの移動を継続する(減衰もあるよ)
- + (m_transform.parent != null ? m_transform.parent.rotation : Quaternion.identity) * LocalRotation * BoneAxis * settings.StiffnessForce * deltaTime // 親の回転による子ボーンの移動目標
- + settings.GravityDir * (settings.GravityPower * deltaTime); // 外力による移動量
-
- // 長さをboneLengthに強制
- var position = m_transform.position;
- nextTail = position + (nextTail - position).normalized * Length;
-
- // Collisionで移動
- nextTail = Collision(m_transform, settings, colliders, nextTail);
-
- return JointState.Make(center, currentTail: state.CurrentTail, nextTail: nextTail);
- }
-
- Vector3 Collision(Transform m_transform, SpringBoneSettings settings, List colliders, Vector3 nextTail)
- {
- foreach (var collider in colliders)
+ var worldChildPosition = transform.TransformPoint(localChildPosition);
+ var tail = center != null
+ ? center.InverseTransformPoint(worldChildPosition)
+ : worldChildPosition;
+ return new SpringBoneJointState
{
- var m_radius = settings.HitRadius * m_transform.UniformedLossyScale();
- var r = m_radius + collider.Radius;
- if (Vector3.SqrMagnitude(nextTail - collider.Position) <= (r * r))
- {
- // ヒット。Colliderの半径方向に押し出す
- var normal = (nextTail - collider.Position).normalized;
- var posFromCollider = collider.Position + normal * (m_radius + collider.Radius);
- // 長さをboneLengthに強制
- nextTail = m_transform.position + (posFromCollider - m_transform.position).normalized * Length;
- }
- }
- return nextTail;
+ CurrentTail = tail,
+ PrevTail = tail,
+ };
}
- public void DrawGizmo(Transform center, Transform m_transform, SpringBoneSettings settings, Color color, JointState m_state)
+ public static SpringBoneJointState Make(Transform center, Vector3 currentTail, Vector3 nextTail)
{
- var state = m_state.ToWorld(center);
- var m_radius = settings.HitRadius * m_transform.UniformedLossyScale();
-
- Gizmos.color = Color.gray;
- Gizmos.DrawLine(state.CurrentTail, state.PrevTail);
- Gizmos.DrawWireSphere(state.PrevTail, m_radius);
-
- Gizmos.color = color;
- Gizmos.DrawLine(state.CurrentTail, m_transform.position);
- Gizmos.DrawWireSphere(state.CurrentTail, m_radius);
+ return new SpringBoneJointState
+ {
+ PrevTail = center != null
+ ? center.InverseTransformPoint(currentTail)
+ : currentTail,
+ CurrentTail = center != null
+ ? center.InverseTransformPoint(nextTail)
+ : nextTail,
+ };
}
+ public SpringBoneJointState ToWorld(Transform center)
+ {
+ return new SpringBoneJointState
+ {
+ CurrentTail = center != null
+ ? center.TransformPoint(CurrentTail)
+ : CurrentTail,
+ PrevTail = center != null
+ ? center.TransformPoint(PrevTail)
+ : PrevTail,
+ };
+ }
};
}
\ No newline at end of file
diff --git a/Assets/VRM/Runtime/SpringBone/Logic/SpringBoneJointState.cs.meta b/Assets/VRM/Runtime/SpringBone/Logic/SpringBoneJointState.cs.meta
index 70dd7502d..b68add524 100644
--- a/Assets/VRM/Runtime/SpringBone/Logic/SpringBoneJointState.cs.meta
+++ b/Assets/VRM/Runtime/SpringBone/Logic/SpringBoneJointState.cs.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
-guid: 2602939771f9eb2428b140e10fa899f2
+guid: 3bbcafd66c035184b8aa868b65c01c1d
MonoImporter:
externalObjects: {}
serializedVersion: 2
diff --git a/Assets/VRM/Runtime/SpringBone/Logic/SpringBoneSystem.cs b/Assets/VRM/Runtime/SpringBone/Logic/SpringBoneSystem.cs
index d7c6e17fe..84154bd18 100644
--- a/Assets/VRM/Runtime/SpringBone/Logic/SpringBoneSystem.cs
+++ b/Assets/VRM/Runtime/SpringBone/Logic/SpringBoneSystem.cs
@@ -4,18 +4,10 @@ using UnityEngine;
namespace VRM.SpringBone
{
- ///
- /// 同じ設定のスプリングをまとめて処理する。
- ///
- /// root o-o-o-x tail
- ///
- /// [vrm0] tail は 7cm 遠にダミーの joint があるようにふるまう。
- ///
- ///
class SpringBoneSystem
{
Dictionary m_initialLocalRotationMap;
- List<(Transform, SpringBoneJointInit, JointState)> m_joints = new();
+ List<(Transform, SpringBoneJointInit, SpringBoneJointState)> m_joints = new();
List m_colliders = new();
public void Setup(SceneInfo scene, bool force)
@@ -79,7 +71,7 @@ namespace VRM.SpringBone
BoneAxis = localChildPosition.normalized,
Length = localChildPosition.magnitude,
},
- JointState.Init(center, parent, localChildPosition)));
+ SpringBoneJointState.Init(center, parent, localChildPosition)));
foreach (Transform child in parent) SetupRecursive(center, child);
}
@@ -95,6 +87,7 @@ namespace VRM.SpringBone
Setup(scene, false);
}
+ // collider の収集
m_colliders.Clear();
if (scene.ColliderGroups != null)
{
@@ -113,11 +106,21 @@ namespace VRM.SpringBone
for (int i = 0; i < m_joints.Count; ++i)
{
var (transform, init, state) = m_joints[i];
- var nextState = init.Update(deltaTime, scene.Center, transform, settings, m_colliders, state);
- m_joints[i] = (transform, init, nextState);
+
+ // Spring処理
+ var nextTail = init.CalcNextTail(deltaTime, scene.Center, transform, settings, state);
+
+ // Collision
+ foreach (var collider in m_colliders)
+ {
+ nextTail = collider.Collide(settings, transform, init, nextTail);
+ }
+
+ // 状態更新
+ m_joints[i] = (transform, init, SpringBoneJointState.Make(scene.Center, currentTail: state.CurrentTail, nextTail: nextTail));
//回転を適用
- var r = init.CalcRotation(transform, nextState.CurrentTail);
+ var r = init.CalcRotation(transform, nextTail);
transform.rotation = r;
}
}