WIP SpringBone

* JsonSchema更新
* シリアライザ修正

#635
This commit is contained in:
ousttrue 2021-01-18 19:38:09 +09:00
parent 2e067a92f5
commit e05daa1524
13 changed files with 262 additions and 283 deletions

View File

@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using UnityEngine;
@ -22,26 +23,30 @@ namespace UniVRM10
[SerializeField]
Color m_gizmoColor = Color.yellow;
[SerializeField, Range(0, 4), Header("Settings")]
public float m_stiffnessForce = 1.0f;
[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, Range(0, 2)]
public float m_gravityPower = 0;
[SerializeField]
public Vector3 m_gravityDir = new Vector3(0, -1.0f, 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, 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;
[SerializeField]
public List<Transform> RootBones = new List<Transform>();
[SerializeField, Range(0, 0.5f), Header("Collision")]
public float m_hitRadius = 0.02f;
public List<VRM10SpringJoint> Joints = new List<VRM10SpringJoint>();
[SerializeField]
public VRM10SpringBoneColliderGroup[] ColliderGroups;
@ -57,7 +62,7 @@ namespace UniVRM10
List<SpringBoneLogic.InternalCollider> m_colliderList = new List<SpringBoneLogic.InternalCollider>();
public void Process()
{
if (RootBones == null)
if (Joints == null)
{
return;
}
@ -99,20 +104,20 @@ namespace UniVRM10
}
}
var stiffness = m_stiffnessForce * Time.deltaTime;
var external = m_gravityDir * (m_gravityPower * Time.deltaTime);
// 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);
// m_processor.Update(RootBones, m_colliderList,
// stiffness, m_dragForce, external,
// m_hitRadius, m_center);
}
private void OnDrawGizmos()
{
if (m_drawGizmo)
{
m_processor.DrawGizmos(m_center, m_hitRadius, m_gizmoColor);
}
// if (m_drawGizmo)
// {
// m_processor.DrawGizmos(m_center, m_hitRadius, m_gizmoColor);
// }
}
}
}

View File

@ -6,6 +6,7 @@ namespace UniVRM10
/// <summary>
/// VRMC_node_collider
/// </summary>
[DisallowMultipleComponent]
[AddComponentMenu("VRM10/VRM10SpringBoneColliderGroup")]
public class VRM10SpringBoneColliderGroup : MonoBehaviour
{

View File

@ -36,11 +36,6 @@ public static VRMC_springBone Deserialize(ListTreeNode<JsonValue> parsed)
{
var key = kv.Key.GetString();
if(key=="settings"){
value.Settings = Deserialize_Settings(kv.Value);
continue;
}
if(key=="springs"){
value.Springs = Deserialize_Springs(kv.Value);
continue;
@ -50,24 +45,66 @@ public static VRMC_springBone Deserialize(ListTreeNode<JsonValue> parsed)
return value;
}
public static List<SpringSetting> Deserialize_Settings(ListTreeNode<JsonValue> parsed)
public static List<Spring> Deserialize_Springs(ListTreeNode<JsonValue> parsed)
{
var value = new List<SpringSetting>();
var value = new List<Spring>();
foreach(var x in parsed.ArrayItems())
{
value.Add(Deserialize_Settings_ITEM(x));
value.Add(Deserialize_Springs_ITEM(x));
}
return value;
}
public static SpringSetting Deserialize_Settings_ITEM(ListTreeNode<JsonValue> parsed)
public static Spring Deserialize_Springs_ITEM(ListTreeNode<JsonValue> parsed)
{
var value = new SpringSetting();
var value = new Spring();
foreach(var kv in parsed.ObjectItems())
{
var key = kv.Key.GetString();
if(key=="name"){
value.Name = kv.Value.GetString();
continue;
}
if(key=="joints"){
value.Joints = Deserialize_Joints(kv.Value);
continue;
}
if(key=="colliders"){
value.Colliders = Deserialize_Colliders(kv.Value);
continue;
}
}
return value;
}
public static List<SpringBoneJoint> Deserialize_Joints(ListTreeNode<JsonValue> parsed)
{
var value = new List<SpringBoneJoint>();
foreach(var x in parsed.ArrayItems())
{
value.Add(Deserialize_Joints_ITEM(x));
}
return value;
}
public static SpringBoneJoint Deserialize_Joints_ITEM(ListTreeNode<JsonValue> parsed)
{
var value = new SpringBoneJoint();
foreach(var kv in parsed.ObjectItems())
{
var key = kv.Key.GetString();
if(key=="hitRadius"){
value.HitRadius = kv.Value.GetSingle();
continue;
}
if(key=="stiffness"){
value.Stiffness = kv.Value.GetSingle();
continue;
@ -103,53 +140,6 @@ public static float[] Deserialize_GravityDir(ListTreeNode<JsonValue> parsed)
return value;
}
public static List<Spring> Deserialize_Springs(ListTreeNode<JsonValue> parsed)
{
var value = new List<Spring>();
foreach(var x in parsed.ArrayItems())
{
value.Add(Deserialize_Springs_ITEM(x));
}
return value;
}
public static Spring Deserialize_Springs_ITEM(ListTreeNode<JsonValue> parsed)
{
var value = new Spring();
foreach(var kv in parsed.ObjectItems())
{
var key = kv.Key.GetString();
if(key=="name"){
value.Name = kv.Value.GetString();
continue;
}
if(key=="setting"){
value.Setting = kv.Value.GetInt32();
continue;
}
if(key=="springRoot"){
value.SpringRoot = kv.Value.GetInt32();
continue;
}
if(key=="hitRadius"){
value.HitRadius = kv.Value.GetSingle();
continue;
}
if(key=="colliders"){
value.Colliders = Deserialize_Colliders(kv.Value);
continue;
}
}
return value;
}
public static int[] Deserialize_Colliders(ListTreeNode<JsonValue> parsed)
{
var value = new int[parsed.GetArrayCount()];

View File

@ -7,8 +7,11 @@ using UniJSON;
namespace UniGLTF.Extensions.VRMC_springBone
{
public class SpringSetting
public class SpringBoneJoint
{
// The radius of spring sphere
public float? HitRadius;
// The force to return to the initial pose
public float? Stiffness;
@ -27,14 +30,8 @@ namespace UniGLTF.Extensions.VRMC_springBone
// Name of the Spring
public string Name;
// The index of spring settings
public int? Setting;
// The node index of spring root
public int? SpringRoot;
// The radius of spring sphere
public float? HitRadius;
// Joints in this spring. Except for the first element, the parent of the element must be the previous element of the array
public List<SpringBoneJoint> Joints;
// Colliders that detect collision with nodes start from springRoot
public int[] Colliders;
@ -45,9 +42,6 @@ namespace UniGLTF.Extensions.VRMC_springBone
public const string ExtensionName = "VRMC_springBone";
public static readonly Utf8String ExtensionNameUtf8 = Utf8String.From(ExtensionName);
// An array of settings.
public List<SpringSetting> Settings;
// An array of springs.
public List<Spring> Springs;
}

View File

@ -33,11 +33,6 @@ public static void Serialize(JsonFormatter f, VRMC_springBone value)
f.BeginMap();
if(value.Settings!=null&&value.Settings.Count()>=0){
f.Key("settings");
Serialize_Settings(f, value.Settings);
}
if(value.Springs!=null&&value.Springs.Count()>=0){
f.Key("springs");
Serialize_Springs(f, value.Springs);
@ -46,23 +41,63 @@ public static void Serialize(JsonFormatter f, VRMC_springBone value)
f.EndMap();
}
public static void Serialize_Settings(JsonFormatter f, List<SpringSetting> value)
public static void Serialize_Springs(JsonFormatter f, List<Spring> value)
{
f.BeginList();
foreach(var item in value)
{
Serialize_Settings_ITEM(f, item);
Serialize_Springs_ITEM(f, item);
}
f.EndList();
}
public static void Serialize_Settings_ITEM(JsonFormatter f, SpringSetting value)
public static void Serialize_Springs_ITEM(JsonFormatter f, Spring value)
{
f.BeginMap();
if(!string.IsNullOrEmpty(value.Name)){
f.Key("name");
f.Value(value.Name);
}
if(value.Joints!=null&&value.Joints.Count()>=0){
f.Key("joints");
Serialize_Joints(f, value.Joints);
}
if(value.Colliders!=null&&value.Colliders.Count()>=0){
f.Key("colliders");
Serialize_Colliders(f, value.Colliders);
}
f.EndMap();
}
public static void Serialize_Joints(JsonFormatter f, List<SpringBoneJoint> value)
{
f.BeginList();
foreach(var item in value)
{
Serialize_Joints_ITEM(f, item);
}
f.EndList();
}
public static void Serialize_Joints_ITEM(JsonFormatter f, SpringBoneJoint value)
{
f.BeginMap();
if(value.HitRadius.HasValue){
f.Key("hitRadius");
f.Value(value.HitRadius.GetValueOrDefault());
}
if(value.Stiffness.HasValue){
f.Key("stiffness");
f.Value(value.Stiffness.GetValueOrDefault());
@ -98,51 +133,6 @@ public static void Serialize_GravityDir(JsonFormatter f, float[] value)
f.EndList();
}
public static void Serialize_Springs(JsonFormatter f, List<Spring> value)
{
f.BeginList();
foreach(var item in value)
{
Serialize_Springs_ITEM(f, item);
}
f.EndList();
}
public static void Serialize_Springs_ITEM(JsonFormatter f, Spring value)
{
f.BeginMap();
if(!string.IsNullOrEmpty(value.Name)){
f.Key("name");
f.Value(value.Name);
}
if(value.Setting.HasValue){
f.Key("setting");
f.Value(value.Setting.GetValueOrDefault());
}
if(value.SpringRoot.HasValue){
f.Key("springRoot");
f.Value(value.SpringRoot.GetValueOrDefault());
}
if(value.HitRadius.HasValue){
f.Key("hitRadius");
f.Value(value.HitRadius.GetValueOrDefault());
}
if(value.Colliders!=null&&value.Colliders.Count()>=0){
f.Key("colliders");
Serialize_Colliders(f, value.Colliders);
}
f.EndMap();
}
public static void Serialize_Colliders(JsonFormatter f, int[] value)
{
f.BeginList();

View File

@ -710,66 +710,62 @@ namespace UniVRM10
return null;
}
var springBone = new SpringBoneManager();
var springBoneManager = new SpringBoneManager();
// springs
if (gltfVrmSpringBone.Springs != null)
{
foreach (var group in gltfVrmSpringBone.Springs.GroupBy(x => x.Setting.Value))
foreach (var gltfSpring in gltfVrmSpringBone.Springs)
{
var sb = new SpringBone();
sb.Comment = group.First().Name;
sb.HitRadius = group.First().HitRadius.Value;
var setting = gltfVrmSpringBone.Settings[group.Key];
sb.DragForce = setting.DragForce.Value;
sb.GravityDir = setting.GravityDir.ToVector3();
sb.GravityPower = setting.GravityPower.Value;
sb.Stiffness = setting.Stiffness.Value;
var springBone = new SpringBone();
springBone.Comment = gltfSpring.Name;
foreach (var spring in group)
// joint
foreach (var gltfJoint in gltfSpring.Joints)
{
// root
sb.Bones.Add(nodes[spring.SpringRoot.Value]);
// collider
foreach (var colliderNode in spring.Colliders)
var joint = new SpringJoint();
joint.HitRadius = gltfJoint.HitRadius.Value;
joint.DragForce = gltfJoint.DragForce.Value;
joint.GravityDir = gltfJoint.GravityDir.ToVector3();
joint.GravityPower = gltfJoint.GravityPower.Value;
joint.Stiffness = gltfJoint.Stiffness.Value;
springBone.Joints.Add(joint);
}
// collider
springBone.Colliders.AddRange(gltfSpring.Colliders.Select(colliderNode =>
{
if (UniGLTF.Extensions.VRMC_node_collider.GltfDeserializer.TryGet(Gltf.nodes[colliderNode].extensions,
out UniGLTF.Extensions.VRMC_node_collider.VRMC_node_collider extension))
{
var collider = springBone.Colliders.FirstOrDefault(x => x.Node == nodes[colliderNode]);
if (collider == null)
var collider = new SpringBoneColliderGroup(nodes[colliderNode], extension.Shapes.Select(x =>
{
if (UniGLTF.Extensions.VRMC_node_collider.GltfDeserializer.TryGet(Gltf.nodes[colliderNode].extensions,
out UniGLTF.Extensions.VRMC_node_collider.VRMC_node_collider extension))
if (x.Sphere != null)
{
collider = new SpringBoneColliderGroup(nodes[colliderNode], extension.Shapes.Select(x =>
{
if (x.Sphere != null)
{
return VrmSpringBoneCollider.CreateSphere(x.Sphere.Offset.ToVector3(), x.Sphere.Radius.Value);
}
else if (x.Capsule != null)
{
return VrmSpringBoneCollider.CreateCapsule(x.Capsule.Offset.ToVector3(), x.Capsule.Radius.Value, x.Capsule.Tail.ToVector3());
}
else
{
throw new NotImplementedException();
}
}));
springBone.Colliders.Add(collider);
return VrmSpringBoneCollider.CreateSphere(x.Sphere.Offset.ToVector3(), x.Sphere.Radius.Value);
}
else if (x.Capsule != null)
{
return VrmSpringBoneCollider.CreateCapsule(x.Capsule.Offset.ToVector3(), x.Capsule.Radius.Value, x.Capsule.Tail.ToVector3());
}
else
{
throw new Exception("collider not found");
throw new NotImplementedException();
}
}
sb.Colliders.Add(collider);
}));
return collider;
}
}
else
{
return null;
}
}).Where(x => x != null));
springBone.Springs.Add(sb);
springBoneManager.Springs.Add(springBone);
}
}
return springBone;
return springBoneManager;
}
public FirstPerson CreateVrmFirstPerson(List<Node> nodes, List<MeshGroup> meshGroups)

View File

@ -10,18 +10,6 @@ namespace UniVRM10
{
public static class SpringBoneAdapter
{
public static SpringSetting ToGltf(this SpringBone self, List<Node> nodes)
{
var setting = new SpringSetting
{
DragForce = self.DragForce,
GravityPower = self.GravityPower,
Stiffness = self.Stiffness,
GravityDir = self.GravityDir.ToFloat3(),
};
return setting;
}
public static VRMC_springBone ToGltf(this SpringBoneManager self, List<Node> nodes,
List<glTFNode> gltfNodes)
{
@ -35,11 +23,11 @@ namespace UniVRM10
//
// VRMC_node_collider
//
foreach (var x in self.Colliders)
foreach (var nodeCollider in self.Springs.SelectMany(x => x.Colliders))
{
var index = nodes.IndexOfThrow(x.Node);
var collider = new VRMC_node_collider();
foreach (var y in x.Colliders)
var index = nodes.IndexOfThrow(nodeCollider.Node);
var gltfCollider = new VRMC_node_collider();
foreach (var y in nodeCollider.Colliders)
{
switch (y.ColliderType)
{
@ -50,7 +38,7 @@ namespace UniVRM10
Radius = y.Radius,
Offset = y.Offset.ToFloat3(),
};
collider.Shapes.Add(new ColliderShape
gltfCollider.Shapes.Add(new ColliderShape
{
Sphere = sphere,
});
@ -65,7 +53,7 @@ namespace UniVRM10
Offset = y.Offset.ToFloat3(),
Tail = y.CapsuleTail.ToFloat3(),
};
collider.Shapes.Add(new ColliderShape
gltfCollider.Shapes.Add(new ColliderShape
{
Capsule = capsule,
});
@ -80,7 +68,7 @@ namespace UniVRM10
//
// add to node.extensions
//
UniGLTF.Extensions.VRMC_node_collider.GltfSerializer.SerializeTo(ref gltfNodes[index].extensions, collider);
UniGLTF.Extensions.VRMC_node_collider.GltfSerializer.SerializeTo(ref gltfNodes[index].extensions, gltfCollider);
}
//
@ -88,20 +76,25 @@ namespace UniVRM10
//
foreach (var x in self.Springs)
{
var settingIndex = springBone.Settings.Count;
springBone.Settings.Add(x.ToGltf(nodes));
foreach (var bone in x.Bones)
var spring = new Spring
{
var spring = new Spring
Name = x.Comment,
Colliders = x.Colliders.Select(y => nodes.IndexOfThrow(y.Node)).ToArray(),
};
foreach (var y in x.Joints)
{
spring.Joints.Add(new SpringBoneJoint
{
Name = x.Comment,
HitRadius = x.HitRadius,
SpringRoot = nodes.IndexOfThrow(bone),
Setting = settingIndex,
Colliders = x.Colliders.Select(y => nodes.IndexOfThrow(y.Node)).ToArray(),
};
springBone.Springs.Add(spring);
HitRadius = y.HitRadius,
DragForce = y.DragForce,
GravityDir = y.GravityDir.ToFloat3(),
GravityPower = y.GravityPower,
Stiffness = y.Stiffness,
});
}
springBone.Springs.Add(spring);
}
return springBone;

View File

@ -235,7 +235,7 @@ namespace UniVRM10
var colliders = new Dictionary<VrmLib.SpringBoneColliderGroup, UniVRM10.VRM10SpringBoneColliderGroup>();
if (model.Vrm.SpringBone != null)
{
foreach (var colliderGroup in model.Vrm.SpringBone.Colliders)
foreach (var colliderGroup in model.Vrm.SpringBone.Springs.SelectMany(x => x.Colliders))
{
var go = asset.Map.Nodes[colliderGroup.Node];
var springBoneColliderGroup = go.AddComponent<UniVRM10.VRM10SpringBoneColliderGroup>();
@ -284,21 +284,29 @@ namespace UniVRM10
springBoneObject.transform.SetParent(asset.Root.transform);
if (model.Vrm.SpringBone != null)
{
foreach (var spring in model.Vrm.SpringBone.Springs)
foreach (var vrmSpring in model.Vrm.SpringBone.Springs)
{
var springBoneComponent = springBoneObject.AddComponent<UniVRM10.VRM10SpringBone>();
springBoneComponent.m_comment = spring.Comment;
springBoneComponent.m_stiffnessForce = spring.Stiffness;
springBoneComponent.m_gravityPower = spring.GravityPower;
springBoneComponent.m_gravityDir = spring.GravityDir.ToUnityVector3();
springBoneComponent.m_dragForce = spring.DragForce;
if (spring.Origin != null && asset.Map.Nodes.TryGetValue(spring.Origin, out GameObject origin))
var springBone = springBoneObject.AddComponent<UniVRM10.VRM10SpringBone>();
springBone.m_comment = vrmSpring.Comment;
if (vrmSpring.Origin != null && asset.Map.Nodes.TryGetValue(vrmSpring.Origin, out GameObject origin))
{
springBoneComponent.m_center = origin.transform;
springBone.m_center = origin.transform;
}
springBoneComponent.RootBones = spring.Bones.Select(x => asset.Map.Nodes[x].transform).ToList();
springBoneComponent.m_hitRadius = spring.HitRadius;
springBoneComponent.ColliderGroups = spring.Colliders.Select(x => colliders[x]).ToArray();
foreach (var vrmJoint in vrmSpring.Joints)
{
var joint = new VRM10SpringBone.VRM10SpringJoint();
joint.m_stiffnessForce = vrmJoint.Stiffness;
joint.m_gravityPower = vrmJoint.GravityPower;
joint.m_gravityDir = vrmJoint.GravityDir.ToUnityVector3();
joint.m_dragForce = vrmJoint.DragForce;
joint.m_hitRadius = vrmJoint.HitRadius;
springBone.Joints.Add(joint);
}
springBone.ColliderGroups = vrmSpring.Colliders.Select(x => colliders[x]).ToArray();
}
}
}

View File

@ -343,12 +343,28 @@ namespace UniVRM10
// springBone
{
var springBoneColliderGroups = root.GetComponentsInChildren<UniVRM10.VRM10SpringBoneColliderGroup>();
if (springBoneColliderGroups != null)
var springBones = root.GetComponentsInChildren<UniVRM10.VRM10SpringBone>();
foreach (var springBone in springBones)
{
Model.Vrm.SpringBone = new VrmLib.SpringBoneManager();
var colliders = new Dictionary<UniVRM10.VRM10SpringBoneColliderGroup, VrmLib.SpringBoneColliderGroup>();
foreach (var colliderGroup in springBoneColliderGroups)
var vrmSpringBone = new VrmLib.SpringBone()
{
Comment = springBone.m_comment,
Origin = (springBone.m_center != null) ? Nodes[springBone.m_center.gameObject] : null,
};
foreach (var joint in springBone.Joints)
{
vrmSpringBone.Joints.Add(new VrmLib.SpringJoint
{
Stiffness = joint.m_stiffnessForce,
GravityPower = joint.m_gravityPower,
GravityDir = joint.m_gravityDir.ToNumericsVector3(),
DragForce = joint.m_dragForce,
HitRadius = joint.m_hitRadius,
});
}
foreach (var colliderGroup in springBone.ColliderGroups)
{
var colliderGroups = colliderGroup.Colliders.Select(x =>
{
@ -365,37 +381,10 @@ namespace UniVRM10
}
});
var vrmColliderGroup = new VrmLib.SpringBoneColliderGroup(Nodes[colliderGroup.gameObject], colliderGroups);
Model.Vrm.SpringBone.Colliders.Add(vrmColliderGroup);
colliders.Add(colliderGroup, vrmColliderGroup);
vrmSpringBone.Colliders.Add(vrmColliderGroup);
}
var springBones = root.GetComponentsInChildren<UniVRM10.VRM10SpringBone>();
foreach (var springBone in springBones)
{
var vrmSpringBone = new VrmLib.SpringBone()
{
Comment = springBone.m_comment,
Stiffness = springBone.m_stiffnessForce,
GravityPower = springBone.m_gravityPower,
GravityDir = springBone.m_gravityDir.ToNumericsVector3(),
DragForce = springBone.m_dragForce,
Origin = (springBone.m_center != null) ? Nodes[springBone.m_center.gameObject] : null,
HitRadius = springBone.m_hitRadius,
};
foreach (var rootBone in springBone.RootBones)
{
vrmSpringBone.Bones.Add(Nodes[rootBone.gameObject]);
}
foreach (var collider in springBone.ColliderGroups)
{
vrmSpringBone.Colliders.Add(colliders[collider]);
}
Model.Vrm.SpringBone.Springs.Add(vrmSpringBone);
}
Model.Vrm.SpringBone.Springs.Add(vrmSpringBone);
}
}

View File

@ -384,7 +384,6 @@ namespace VrmLib.Diff
VrmFirstPerson(context.Enter(nameof(lhs.Vrm.FirstPerson)), lhs.Vrm.FirstPerson, rhs.Vrm.FirstPerson);
VrmLookAt(context.Enter(nameof(lhs.Vrm.LookAt)), lhs.Vrm.LookAt, rhs.Vrm.LookAt);
ListDiff(context.Enter("SpringBone.Springs"), lhs.Vrm.SpringBone.Springs, rhs.Vrm.SpringBone.Springs, VrmSpringBoneEquals);
ListDiff(context.Enter("SpringBone.Colliders"), lhs.Vrm.SpringBone.Colliders, rhs.Vrm.SpringBone.Colliders, VrmSpringBoneColliderEquals);
}
static void VrmMeta(ModelDiffContext context, Meta lhs, Meta rhs)
@ -501,19 +500,26 @@ namespace VrmLib.Diff
context.Enter("Curve").Push(lhs.Curve, rhs.Curve);
}
static bool VrmSpringBoneEquals(ModelDiffContext context, SpringBone lhs, SpringBone rhs)
static bool VrmSpringBoneJointEquals(ModelDiffContext context, SpringJoint lhs, SpringJoint rhs)
{
var equals = true;
if (!context.Enter("Comment").Push(lhs.Comment, rhs.Comment)) equals = false;
if (!context.Enter("DragForce").Push(lhs.DragForce, rhs.DragForce)) equals = false;
if (!context.Enter("GravityDir").Push(lhs.GravityDir, rhs.GravityDir)) equals = false;
if (!context.Enter("GravityPower").Push(lhs.GravityPower, rhs.GravityPower)) equals = false;
if (!context.Enter("HitRadius").Push(lhs.HitRadius, rhs.HitRadius)) equals = false;
if (!context.Enter("Origin").Push(lhs.Origin, rhs.Origin)) equals = false;
if (!context.Enter("Stiffness").Push(lhs.Stiffness, rhs.Stiffness)) equals = false;
return equals;
}
static bool VrmSpringBoneEquals(ModelDiffContext context, SpringBone lhs, SpringBone rhs)
{
var equals = true;
if (!context.Enter("Comment").Push(lhs.Comment, rhs.Comment)) equals = false;
if (!context.Enter("Origin").Push(lhs.Origin, rhs.Origin)) equals = false;
if (!ListDiff(context.Enter("Joint"), lhs.Joints, rhs.Joints, VrmSpringBoneJointEquals)) equals = false;
return equals;
}
static bool VrmSpringBoneColliderEquals(ModelDiffContext context, VrmSpringBoneCollider lhs, VrmSpringBoneCollider rhs)
{
var equals = true;

View File

@ -167,7 +167,10 @@ namespace VrmLib
}
}
b.GravityDir = b.GravityDir.ReverseZ();
foreach (var j in b.Joints)
{
j.GravityDir = j.GravityDir.ReverseZ();
}
}
}
}

View File

@ -105,14 +105,14 @@ namespace VrmLib
{
foreach (var x in spring.Springs)
{
foreach (var y in x.Bones)
foreach (var y in x.Joints)
{
nodeUsage[model.Nodes.IndexOf(y)].SpringUse = true;
nodeUsage[model.Nodes.IndexOf(y.Node)].SpringUse = true;
}
foreach (var y in x.Colliders)
{
nodeUsage[model.Nodes.IndexOf(y.Node)].SpringUse = true;
}
}
foreach (var x in spring.Colliders)
{
nodeUsage[model.Nodes.IndexOf(x.Node)].SpringUse = true;
}
}

View File

@ -49,15 +49,9 @@ namespace VrmLib
}
}
public class SpringBone
public class SpringJoint
{
public const string ExtensionName = "VRMC_springBone";
public readonly List<Node> Bones = new List<Node>();
public Node Origin;
public readonly List<SpringBoneColliderGroup> Colliders = new List<SpringBoneColliderGroup>();
public string Comment = "";
public readonly Node Node;
public float DragForce;
@ -70,9 +64,19 @@ namespace VrmLib
public float Stiffness;
}
public class SpringBone
{
public const string ExtensionName = "VRMC_springBone";
public readonly List<SpringJoint> Joints = new List<SpringJoint>();
public Node Origin;
public readonly List<SpringBoneColliderGroup> Colliders = new List<SpringBoneColliderGroup>();
public string Comment = "";
}
public class SpringBoneManager
{
public readonly List<SpringBone> Springs = new List<SpringBone>();
public readonly List<SpringBoneColliderGroup> Colliders = new List<SpringBoneColliderGroup>();
}
}
}