From 1c3b8571e9a3d95dda8d6a949cb73da89c40244c Mon Sep 17 00:00:00 2001 From: ousttrue Date: Tue, 4 Jun 2024 17:31:53 +0900 Subject: [PATCH 1/8] pull vrm-specification --- vrm-specification | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vrm-specification b/vrm-specification index 0bcc3d4c5..7f5252a94 160000 --- a/vrm-specification +++ b/vrm-specification @@ -1 +1 @@ -Subproject commit 0bcc3d4c56311ea36905049b10908a4eb60aa327 +Subproject commit 7f5252a94208fc127b59eb4ce2fd699e6ae3ca6e From 11a605b50615106d54543df83d972c23b1aeae44 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Tue, 4 Jun 2024 17:44:38 +0900 Subject: [PATCH 2/8] Generate serializer for VRMC_springBone_extended_collider --- .../VRM10/Editor/Vrm10SerializerGenerator.cs | 6 + .../Format/Animation/Deserializer.g.cs | 144 ++--------- .../Runtime/Format/Animation/Format.g.cs | 15 +- .../Runtime/Format/Animation/Serializer.g.cs | 129 ++-------- .../Format/SpringBoneExtendedCollider.meta | 8 + .../Deserializer.g.cs | 238 ++++++++++++++++++ .../Deserializer.g.cs.meta | 11 + .../SpringBoneExtendedCollider/Format.g.cs | 76 ++++++ .../Format.g.cs.meta | 11 + .../Serializer.g.cs | 222 ++++++++++++++++ .../Serializer.g.cs.meta | 11 + .../VRM10/Runtime/IO/VrmAnimationImporter.cs | 4 - 12 files changed, 619 insertions(+), 256 deletions(-) create mode 100644 Assets/VRM10/Runtime/Format/SpringBoneExtendedCollider.meta create mode 100644 Assets/VRM10/Runtime/Format/SpringBoneExtendedCollider/Deserializer.g.cs create mode 100644 Assets/VRM10/Runtime/Format/SpringBoneExtendedCollider/Deserializer.g.cs.meta create mode 100644 Assets/VRM10/Runtime/Format/SpringBoneExtendedCollider/Format.g.cs create mode 100644 Assets/VRM10/Runtime/Format/SpringBoneExtendedCollider/Format.g.cs.meta create mode 100644 Assets/VRM10/Runtime/Format/SpringBoneExtendedCollider/Serializer.g.cs create mode 100644 Assets/VRM10/Runtime/Format/SpringBoneExtendedCollider/Serializer.g.cs.meta diff --git a/Assets/VRM10/Editor/Vrm10SerializerGenerator.cs b/Assets/VRM10/Editor/Vrm10SerializerGenerator.cs index f22a16105..184132e93 100644 --- a/Assets/VRM10/Editor/Vrm10SerializerGenerator.cs +++ b/Assets/VRM10/Editor/Vrm10SerializerGenerator.cs @@ -79,6 +79,12 @@ namespace UniVRM10 $"{SPEC_DIR}/VRMC_vrm_animation-1.0/schema/VRMC_vrm_animation.schema.json", "Assets/VRM10/Runtime/Format/Animation" ), + + // VRMC_animation + new GenerateInfo( + $"{SPEC_DIR}/VRMC_springBone_extended_collider-1.0/schema/VRMC_springBone_extended_collider.schema.json", + "Assets/VRM10/Runtime/Format/SpringBoneExtendedCollider" + ), }; foreach (var arg in args) diff --git a/Assets/VRM10/Runtime/Format/Animation/Deserializer.g.cs b/Assets/VRM10/Runtime/Format/Animation/Deserializer.g.cs index d74221b5b..7b8660150 100644 --- a/Assets/VRM10/Runtime/Format/Animation/Deserializer.g.cs +++ b/Assets/VRM10/Runtime/Format/Animation/Deserializer.g.cs @@ -1921,26 +1921,6 @@ public static Preset __expressions_Deserialize_Preset(JsonNode parsed) continue; } - if(key=="lookUp"){ - value.LookUp = __expressions__preset_Deserialize_LookUp(kv.Value); - continue; - } - - if(key=="lookDown"){ - value.LookDown = __expressions__preset_Deserialize_LookDown(kv.Value); - continue; - } - - if(key=="lookLeft"){ - value.LookLeft = __expressions__preset_Deserialize_LookLeft(kv.Value); - continue; - } - - if(key=="lookRight"){ - value.LookRight = __expressions__preset_Deserialize_LookRight(kv.Value); - continue; - } - if(key=="neutral"){ value.Neutral = __expressions__preset_Deserialize_Neutral(kv.Value); continue; @@ -2301,114 +2281,6 @@ public static Expression __expressions__preset_Deserialize_BlinkRight(JsonNode p return value; } -public static Expression __expressions__preset_Deserialize_LookUp(JsonNode parsed) -{ - var value = new Expression(); - - 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; - } - - } - return value; -} - -public static Expression __expressions__preset_Deserialize_LookDown(JsonNode parsed) -{ - var value = new Expression(); - - 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; - } - - } - return value; -} - -public static Expression __expressions__preset_Deserialize_LookLeft(JsonNode parsed) -{ - var value = new Expression(); - - 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; - } - - } - return value; -} - -public static Expression __expressions__preset_Deserialize_LookRight(JsonNode parsed) -{ - var value = new Expression(); - - 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; - } - - } - return value; -} - public static Expression __expressions__preset_Deserialize_Neutral(JsonNode parsed) { var value = new Expression(); @@ -2496,9 +2368,25 @@ public static LookAt Deserialize_LookAt(JsonNode parsed) continue; } + if(key=="offsetFromHeadBone"){ + value.OffsetFromHeadBone = __lookAt_Deserialize_OffsetFromHeadBone(kv.Value); + continue; + } + } return value; } +public static float[] __lookAt_Deserialize_OffsetFromHeadBone(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/Assets/VRM10/Runtime/Format/Animation/Format.g.cs b/Assets/VRM10/Runtime/Format/Animation/Format.g.cs index df697d818..f7a1d5f03 100644 --- a/Assets/VRM10/Runtime/Format/Animation/Format.g.cs +++ b/Assets/VRM10/Runtime/Format/Animation/Format.g.cs @@ -251,18 +251,6 @@ namespace UniGLTF.Extensions.VRMC_vrm_animation // Represents a single expression. public Expression BlinkRight; - // Represents a single expression. - public Expression LookUp; - - // Represents a single expression. - public Expression LookDown; - - // Represents a single expression. - public Expression LookLeft; - - // Represents a single expression. - public Expression LookRight; - // Represents a single expression. public Expression Neutral; } @@ -292,6 +280,9 @@ namespace UniGLTF.Extensions.VRMC_vrm_animation // Represents a single glTF node represents the eye gaze point. public int? Node; + + // The position offset of the origin of the LookAt from the humanoid head bone + public float[] OffsetFromHeadBone; } public class VRMC_vrm_animation diff --git a/Assets/VRM10/Runtime/Format/Animation/Serializer.g.cs b/Assets/VRM10/Runtime/Format/Animation/Serializer.g.cs index d27bd05a6..996c1ccb5 100644 --- a/Assets/VRM10/Runtime/Format/Animation/Serializer.g.cs +++ b/Assets/VRM10/Runtime/Format/Animation/Serializer.g.cs @@ -1689,26 +1689,6 @@ public static void __expressions_Serialize_Preset(JsonFormatter f, Preset value) __expressions__preset_Serialize_BlinkRight(f, value.BlinkRight); } - if(value.LookUp!=null){ - f.Key("lookUp"); - __expressions__preset_Serialize_LookUp(f, value.LookUp); - } - - if(value.LookDown!=null){ - f.Key("lookDown"); - __expressions__preset_Serialize_LookDown(f, value.LookDown); - } - - if(value.LookLeft!=null){ - f.Key("lookLeft"); - __expressions__preset_Serialize_LookLeft(f, value.LookLeft); - } - - if(value.LookRight!=null){ - f.Key("lookRight"); - __expressions__preset_Serialize_LookRight(f, value.LookRight); - } - if(value.Neutral!=null){ f.Key("neutral"); __expressions__preset_Serialize_Neutral(f, value.Neutral); @@ -2016,98 +1996,6 @@ public static void __expressions__preset_Serialize_BlinkRight(JsonFormatter f, E f.EndMap(); } -public static void __expressions__preset_Serialize_LookUp(JsonFormatter f, Expression 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()); - } - - f.EndMap(); -} - -public static void __expressions__preset_Serialize_LookDown(JsonFormatter f, Expression 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()); - } - - f.EndMap(); -} - -public static void __expressions__preset_Serialize_LookLeft(JsonFormatter f, Expression 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()); - } - - f.EndMap(); -} - -public static void __expressions__preset_Serialize_LookRight(JsonFormatter f, Expression 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()); - } - - f.EndMap(); -} - public static void __expressions__preset_Serialize_Neutral(JsonFormatter f, Expression value) { f.BeginMap(); @@ -2187,8 +2075,25 @@ public static void Serialize_LookAt(JsonFormatter f, LookAt value) f.Value(value.Node.GetValueOrDefault()); } + if(value.OffsetFromHeadBone!=null&&value.OffsetFromHeadBone.Count()>=3){ + f.Key("offsetFromHeadBone"); + __lookAt_Serialize_OffsetFromHeadBone(f, value.OffsetFromHeadBone); + } + f.EndMap(); } +public static void __lookAt_Serialize_OffsetFromHeadBone(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + } // class } // namespace diff --git a/Assets/VRM10/Runtime/Format/SpringBoneExtendedCollider.meta b/Assets/VRM10/Runtime/Format/SpringBoneExtendedCollider.meta new file mode 100644 index 000000000..6ea3f5ae0 --- /dev/null +++ b/Assets/VRM10/Runtime/Format/SpringBoneExtendedCollider.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4feacc5eab0e46e4b900d239ff3c6485 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VRM10/Runtime/Format/SpringBoneExtendedCollider/Deserializer.g.cs b/Assets/VRM10/Runtime/Format/SpringBoneExtendedCollider/Deserializer.g.cs new file mode 100644 index 000000000..2630d2a80 --- /dev/null +++ b/Assets/VRM10/Runtime/Format/SpringBoneExtendedCollider/Deserializer.g.cs @@ -0,0 +1,238 @@ +// 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_springBone_extended_collider { + +public static class GltfDeserializer +{ + public static readonly Utf8String ExtensionNameUtf8 = Utf8String.From(VRMC_springBone_extended_collider.ExtensionName); + +public static bool TryGet(UniGLTF.glTFExtension src, out VRMC_springBone_extended_collider 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_springBone_extended_collider Deserialize(JsonNode parsed) +{ + var value = new VRMC_springBone_extended_collider(); + + 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=="specVersion"){ + value.SpecVersion = kv.Value.GetString(); + continue; + } + + if(key=="shape"){ + value.Shape = Deserialize_Shape(kv.Value); + continue; + } + + } + return value; +} + +public static ExtendedColliderShape Deserialize_Shape(JsonNode parsed) +{ + var value = new ExtendedColliderShape(); + + 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=="sphere"){ + value.Sphere = __shape_Deserialize_Sphere(kv.Value); + continue; + } + + if(key=="capsule"){ + value.Capsule = __shape_Deserialize_Capsule(kv.Value); + continue; + } + + if(key=="plane"){ + value.Plane = __shape_Deserialize_Plane(kv.Value); + continue; + } + + } + return value; +} + +public static ExtendedColliderShapeSphere __shape_Deserialize_Sphere(JsonNode parsed) +{ + var value = new ExtendedColliderShapeSphere(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="offset"){ + value.Offset = __shape__sphere_Deserialize_Offset(kv.Value); + continue; + } + + if(key=="radius"){ + value.Radius = kv.Value.GetSingle(); + continue; + } + + if(key=="inside"){ + value.Inside = kv.Value.GetBoolean(); + continue; + } + + } + return value; +} + +public static float[] __shape__sphere_Deserialize_Offset(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 ExtendedColliderShapeCapsule __shape_Deserialize_Capsule(JsonNode parsed) +{ + var value = new ExtendedColliderShapeCapsule(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="offset"){ + value.Offset = __shape__capsule_Deserialize_Offset(kv.Value); + continue; + } + + if(key=="radius"){ + value.Radius = kv.Value.GetSingle(); + continue; + } + + if(key=="tail"){ + value.Tail = __shape__capsule_Deserialize_Tail(kv.Value); + continue; + } + + if(key=="inside"){ + value.Inside = kv.Value.GetBoolean(); + continue; + } + + } + return value; +} + +public static float[] __shape__capsule_Deserialize_Offset(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[] __shape__capsule_Deserialize_Tail(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 ExtendedColliderShapePlane __shape_Deserialize_Plane(JsonNode parsed) +{ + var value = new ExtendedColliderShapePlane(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="offset"){ + value.Offset = __shape__plane_Deserialize_Offset(kv.Value); + continue; + } + + if(key=="normal"){ + value.Normal = __shape__plane_Deserialize_Normal(kv.Value); + continue; + } + + } + return value; +} + +public static float[] __shape__plane_Deserialize_Offset(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[] __shape__plane_Deserialize_Normal(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/Assets/VRM10/Runtime/Format/SpringBoneExtendedCollider/Deserializer.g.cs.meta b/Assets/VRM10/Runtime/Format/SpringBoneExtendedCollider/Deserializer.g.cs.meta new file mode 100644 index 000000000..fdf943ac1 --- /dev/null +++ b/Assets/VRM10/Runtime/Format/SpringBoneExtendedCollider/Deserializer.g.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 03ad1a44a20bbc94db18a7ee01cd6d3e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VRM10/Runtime/Format/SpringBoneExtendedCollider/Format.g.cs b/Assets/VRM10/Runtime/Format/SpringBoneExtendedCollider/Format.g.cs new file mode 100644 index 000000000..8ce05a98f --- /dev/null +++ b/Assets/VRM10/Runtime/Format/SpringBoneExtendedCollider/Format.g.cs @@ -0,0 +1,76 @@ +// This file is generated from JsonSchema. Don't modify this source code. +using System; +using System.Collections.Generic; + + +namespace UniGLTF.Extensions.VRMC_springBone_extended_collider +{ + + public class ExtendedColliderShapeSphere + { + // The offset of the sphere from the origin in the local space. + public float[] Offset; + + // The radius of the sphere. + public float? Radius; + + // If true, the collider prevents spring bones from going outside of the sphere instead. + public bool? Inside; + } + + public class ExtendedColliderShapeCapsule + { + // The offset of the capsule head from the origin in the local space. + public float[] Offset; + + // The radius of the capsule. + public float? Radius; + + // The offset of the capsule tail from the origin in the local space. + public float[] Tail; + + // If true, the collider prevents spring bones from going outside of the capsule instead. + public bool? Inside; + } + + public class ExtendedColliderShapePlane + { + // The offset of the plane from the origin in the local space. + public float[] Offset; + + // The normal of the plane in the local space. Must be normalized. + public float[] Normal; + } + + public class ExtendedColliderShape + { + // Dictionary object with extension-specific objects. + public object Extensions; + + // Application-specific data. + public object Extras; + + public ExtendedColliderShapeSphere Sphere; + + public ExtendedColliderShapeCapsule Capsule; + + public ExtendedColliderShapePlane Plane; + } + + public class VRMC_springBone_extended_collider + { + public const string ExtensionName = "VRMC_springBone_extended_collider"; + + // Dictionary object with extension-specific objects. + public object Extensions; + + // Application-specific data. + public object Extras; + + // Specification version of VRMC_springBone_extended_collider. + public string SpecVersion; + + // The shape of the collider. + public ExtendedColliderShape Shape; + } +} diff --git a/Assets/VRM10/Runtime/Format/SpringBoneExtendedCollider/Format.g.cs.meta b/Assets/VRM10/Runtime/Format/SpringBoneExtendedCollider/Format.g.cs.meta new file mode 100644 index 000000000..960a93d31 --- /dev/null +++ b/Assets/VRM10/Runtime/Format/SpringBoneExtendedCollider/Format.g.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: afa332976c5ea28468f9a63b0b3ad344 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VRM10/Runtime/Format/SpringBoneExtendedCollider/Serializer.g.cs b/Assets/VRM10/Runtime/Format/SpringBoneExtendedCollider/Serializer.g.cs new file mode 100644 index 000000000..bfc86ffdd --- /dev/null +++ b/Assets/VRM10/Runtime/Format/SpringBoneExtendedCollider/Serializer.g.cs @@ -0,0 +1,222 @@ +// 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_springBone_extended_collider { + + static public class GltfSerializer + { + + public static void SerializeTo(ref UniGLTF.glTFExtension dst, VRMC_springBone_extended_collider 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_springBone_extended_collider.ExtensionName, f.GetStoreBytes()); + } + + +public static void Serialize(JsonFormatter f, VRMC_springBone_extended_collider 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(!string.IsNullOrEmpty(value.SpecVersion)){ + f.Key("specVersion"); + f.Value(value.SpecVersion); + } + + if(value.Shape!=null){ + f.Key("shape"); + Serialize_Shape(f, value.Shape); + } + + f.EndMap(); +} + +public static void Serialize_Shape(JsonFormatter f, ExtendedColliderShape 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.Sphere!=null){ + f.Key("sphere"); + __shape_Serialize_Sphere(f, value.Sphere); + } + + if(value.Capsule!=null){ + f.Key("capsule"); + __shape_Serialize_Capsule(f, value.Capsule); + } + + if(value.Plane!=null){ + f.Key("plane"); + __shape_Serialize_Plane(f, value.Plane); + } + + f.EndMap(); +} + +public static void __shape_Serialize_Sphere(JsonFormatter f, ExtendedColliderShapeSphere value) +{ + f.BeginMap(); + + + if(value.Offset!=null&&value.Offset.Count()>=3){ + f.Key("offset"); + __shape__sphere_Serialize_Offset(f, value.Offset); + } + + if(value.Radius.HasValue){ + f.Key("radius"); + f.Value(value.Radius.GetValueOrDefault()); + } + + if(value.Inside.HasValue){ + f.Key("inside"); + f.Value(value.Inside.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __shape__sphere_Serialize_Offset(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __shape_Serialize_Capsule(JsonFormatter f, ExtendedColliderShapeCapsule value) +{ + f.BeginMap(); + + + if(value.Offset!=null&&value.Offset.Count()>=3){ + f.Key("offset"); + __shape__capsule_Serialize_Offset(f, value.Offset); + } + + if(value.Radius.HasValue){ + f.Key("radius"); + f.Value(value.Radius.GetValueOrDefault()); + } + + if(value.Tail!=null&&value.Tail.Count()>=3){ + f.Key("tail"); + __shape__capsule_Serialize_Tail(f, value.Tail); + } + + if(value.Inside.HasValue){ + f.Key("inside"); + f.Value(value.Inside.GetValueOrDefault()); + } + + f.EndMap(); +} + +public static void __shape__capsule_Serialize_Offset(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __shape__capsule_Serialize_Tail(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __shape_Serialize_Plane(JsonFormatter f, ExtendedColliderShapePlane value) +{ + f.BeginMap(); + + + if(value.Offset!=null&&value.Offset.Count()>=3){ + f.Key("offset"); + __shape__plane_Serialize_Offset(f, value.Offset); + } + + if(value.Normal!=null&&value.Normal.Count()>=3){ + f.Key("normal"); + __shape__plane_Serialize_Normal(f, value.Normal); + } + + f.EndMap(); +} + +public static void __shape__plane_Serialize_Offset(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + +public static void __shape__plane_Serialize_Normal(JsonFormatter f, float[] value) +{ + f.BeginList(); + + foreach(var item in value) + { + f.Value(item); + + } + f.EndList(); +} + + } // class +} // namespace diff --git a/Assets/VRM10/Runtime/Format/SpringBoneExtendedCollider/Serializer.g.cs.meta b/Assets/VRM10/Runtime/Format/SpringBoneExtendedCollider/Serializer.g.cs.meta new file mode 100644 index 000000000..43d7c548c --- /dev/null +++ b/Assets/VRM10/Runtime/Format/SpringBoneExtendedCollider/Serializer.g.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a96731f2fb44d4d43a94e9c52d4361b5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VRM10/Runtime/IO/VrmAnimationImporter.cs b/Assets/VRM10/Runtime/IO/VrmAnimationImporter.cs index e52a898dc..7150476bf 100644 --- a/Assets/VRM10/Runtime/IO/VrmAnimationImporter.cs +++ b/Assets/VRM10/Runtime/IO/VrmAnimationImporter.cs @@ -181,10 +181,6 @@ namespace UniVRM10 { if (GetExpression(gltfAnimation, ExpressionKey.CreateFromPreset(ExpressionPreset.blink), nameof(Vrm10AnimationInstance.preset_blink), preset.Blink) is ExpressionInfo info) yield return info; } { if (GetExpression(gltfAnimation, ExpressionKey.CreateFromPreset(ExpressionPreset.blinkLeft), nameof(Vrm10AnimationInstance.preset_blinkleft), preset.BlinkLeft) is ExpressionInfo info) yield return info; } { if (GetExpression(gltfAnimation, ExpressionKey.CreateFromPreset(ExpressionPreset.blinkRight), nameof(Vrm10AnimationInstance.preset_blinkright), preset.BlinkRight) is ExpressionInfo info) yield return info; } - { if (GetExpression(gltfAnimation, ExpressionKey.CreateFromPreset(ExpressionPreset.lookUp), "preset_lookup", preset.LookUp) is ExpressionInfo info) yield return info; } - { if (GetExpression(gltfAnimation, ExpressionKey.CreateFromPreset(ExpressionPreset.lookDown), "preset_lookdown", preset.LookDown) is ExpressionInfo info) yield return info; } - { if (GetExpression(gltfAnimation, ExpressionKey.CreateFromPreset(ExpressionPreset.lookLeft), "preset_lookleft", preset.LookLeft) is ExpressionInfo info) yield return info; } - { if (GetExpression(gltfAnimation, ExpressionKey.CreateFromPreset(ExpressionPreset.lookRight), "preset_lookright", preset.LookRight) is ExpressionInfo info) yield return info; } { if (GetExpression(gltfAnimation, ExpressionKey.CreateFromPreset(ExpressionPreset.neutral), nameof(Vrm10AnimationInstance.preset_neutral), preset.Neutral) is ExpressionInfo info) yield return info; } } if (animation.Expressions.Custom != null) From 31fac6cad6353e48fda4207179e546aeb6a44497 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Wed, 5 Jun 2024 14:59:43 +0900 Subject: [PATCH 3/8] VRMC_springBone_extended_collider gizmo --- .../SpringBone/VRM10SpringBoneCollider.cs | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/Assets/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneCollider.cs b/Assets/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneCollider.cs index 60e3c45de..5cea5a9c7 100644 --- a/Assets/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneCollider.cs +++ b/Assets/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneCollider.cs @@ -7,6 +7,8 @@ namespace UniVRM10 { Sphere, Capsule, + Plane, + SphereIside, } [Serializable] @@ -23,6 +25,8 @@ namespace UniVRM10 /// bone local position public Vector3 Tail; + public Vector3 Normal = Vector3.up; + public static int SelectedGuid; public bool IsSelected => GetInstanceID() == SelectedGuid; @@ -43,6 +47,84 @@ namespace UniVRM10 Gizmos.DrawWireSphere(Tail, Radius); Gizmos.DrawLine(Offset, Tail); break; + + case VRM10SpringBoneColliderTypes.Plane: + Gizmos.color = new Color(1.0f, 0.5f, 0.0f); + // normal offset + DrawPlane(transform.localToWorldMatrix, Offset, Normal, Radius); + break; + + case VRM10SpringBoneColliderTypes.SphereIside: + Gizmos.color = Color.cyan; + Gizmos.DrawWireSphere(Offset, Radius); + break; + + default: + throw new NotImplementedException(); + } + } + + public static void DrawPlane(in Matrix4x4 m, in Vector3 offset, in Vector3 _n, float radius) + { + var n = _n.normalized; + Gizmos.matrix = m; + Gizmos.DrawLine(offset, offset + n * radius); + + // N Y-Axis として + // XZ 平面を描画する。 + var z = Vector3.Cross(Vector3.right, n); + if (z.magnitude > 1e-4) + { + var zr = z * radius; + var x = Vector3.Cross(n, z); + var xr = x * radius; + Gizmos.DrawLine(-xr, xr); + { + var o = offset + zr; + Gizmos.DrawLine(o - xr, o + xr); + } + { + var o = offset - zr; + Gizmos.DrawLine(o - xr, o + xr); + } + + Gizmos.DrawLine(-zr, zr); + { + var o = offset + xr; + Gizmos.DrawLine(o - zr, o + zr); + } + { + var o = offset - xr; + Gizmos.DrawLine(o - zr, o + zr); + } + } + else + { + // N と ローカル X-Axis が重なっていた場合 + var x = Vector3.Cross(n, Vector3.forward); + var xr = x * radius; + var _z = Vector3.Cross(x, n); + var zr = _z * radius; + + Gizmos.DrawLine(-xr, xr); + { + var o = offset + zr; + Gizmos.DrawLine(o - xr, o + xr); + } + { + var o = offset - zr; + Gizmos.DrawLine(o - xr, o + xr); + } + + Gizmos.DrawLine(-zr, zr); + { + var o = offset + xr; + Gizmos.DrawLine(o - zr, o + zr); + } + { + var o = offset - xr; + Gizmos.DrawLine(o - zr, o + zr); + } } } From a71aa9fd8fce9fc1d0764f2b255b23a790b8b4a8 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Wed, 5 Jun 2024 15:54:03 +0900 Subject: [PATCH 4/8] import --- .../SpringBone/VRM10SpringBoneCollider.cs | 2 + .../Components/Vrm10Runtime/Vrm10Runtime.cs | 2 +- .../Blittables/BlittableCollider.cs | 5 +- .../Blittables/BlittableColliderType.cs | 2 + .../System/UpdateFastSpringBoneJob.cs | 86 ++++++++++++++++++- Assets/VRM10/Runtime/IO/Vrm10Importer.cs | 35 ++++++++ 6 files changed, 125 insertions(+), 7 deletions(-) diff --git a/Assets/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneCollider.cs b/Assets/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneCollider.cs index 5cea5a9c7..c33c12dd0 100644 --- a/Assets/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneCollider.cs +++ b/Assets/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneCollider.cs @@ -27,6 +27,8 @@ namespace UniVRM10 public Vector3 Normal = Vector3.up; + public Vector3 TailOrNormal => ColliderType == VRM10SpringBoneColliderTypes.Plane ? Normal : Tail; + public static int SelectedGuid; public bool IsSelected => GetInstanceID() == SelectedGuid; diff --git a/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs index 8a40ad9e5..abaa213c4 100644 --- a/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs +++ b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs @@ -131,7 +131,7 @@ namespace UniVRM10 { offset = collider.Offset, radius = collider.Radius, - tail = collider.Tail, + tailOrNormal = collider.TailOrNormal, colliderType = TranslateColliderType(collider.ColliderType) } }).ToArray(), diff --git a/Assets/VRM10/Runtime/FastSpringBone/Blittables/BlittableCollider.cs b/Assets/VRM10/Runtime/FastSpringBone/Blittables/BlittableCollider.cs index 334887503..1f88e7fee 100644 --- a/Assets/VRM10/Runtime/FastSpringBone/Blittables/BlittableCollider.cs +++ b/Assets/VRM10/Runtime/FastSpringBone/Blittables/BlittableCollider.cs @@ -9,11 +9,12 @@ namespace UniVRM10.FastSpringBones.Blittables /// [Serializable] public struct BlittableCollider - { + { public BlittableColliderType colliderType; public Vector3 offset; public float radius; - public Vector3 tail; + // capsule tail or plane normal + public Vector3 tailOrNormal; public int transformIndex; } } \ No newline at end of file diff --git a/Assets/VRM10/Runtime/FastSpringBone/Blittables/BlittableColliderType.cs b/Assets/VRM10/Runtime/FastSpringBone/Blittables/BlittableColliderType.cs index 04f0b9f25..93ddef69a 100644 --- a/Assets/VRM10/Runtime/FastSpringBone/Blittables/BlittableColliderType.cs +++ b/Assets/VRM10/Runtime/FastSpringBone/Blittables/BlittableColliderType.cs @@ -4,5 +4,7 @@ namespace UniVRM10.FastSpringBones.Blittables { Sphere, Capsule, + Plane, + SphereInside, } } \ No newline at end of file diff --git a/Assets/VRM10/Runtime/FastSpringBone/System/UpdateFastSpringBoneJob.cs b/Assets/VRM10/Runtime/FastSpringBone/System/UpdateFastSpringBoneJob.cs index 87e5e16d4..495f7eecb 100644 --- a/Assets/VRM10/Runtime/FastSpringBone/System/UpdateFastSpringBoneJob.cs +++ b/Assets/VRM10/Runtime/FastSpringBone/System/UpdateFastSpringBoneJob.cs @@ -22,7 +22,7 @@ namespace UniVRM10.FastSpringBones.System [NativeDisableParallelForRestriction] public NativeArray Transforms; public float DeltaTime; - + public unsafe void Execute(int index) { var spring = Springs[index]; @@ -79,16 +79,28 @@ namespace UniVRM10.FastSpringBones.System var colliderScale = colliderTransform.localToWorldMatrix.lossyScale; var maxColliderScale = Mathf.Max(Mathf.Max(Mathf.Abs(colliderScale.x), Mathf.Abs(colliderScale.y)), Mathf.Abs(colliderScale.z)); var worldPosition = colliderTransform.localToWorldMatrix.MultiplyPoint3x4(collider.offset); - var worldTail = colliderTransform.localToWorldMatrix.MultiplyPoint3x4(collider.tail); - + var worldTail = colliderTransform.localToWorldMatrix.MultiplyPoint3x4(collider.tailOrNormal); + switch (collider.colliderType) { case BlittableColliderType.Sphere: - ResolveSphereCollision(joint, collider, worldPosition, headTransform, maxColliderScale, logic, ref nextTail); + ResolveSphereCollision(joint, collider, worldPosition, headTransform, maxColliderScale, logic, ref nextTail); break; + case BlittableColliderType.Capsule: ResolveCapsuleCollision(worldTail, worldPosition, headTransform, joint, collider, maxColliderScale, logic, ref nextTail); break; + + case BlittableColliderType.Plane: + ResolvePlaneCollision(joint, collider, worldPosition, headTransform, maxColliderScale, logic, ref nextTail); + break; + + case BlittableColliderType.SphereInside: + ResolveSphereCollisionInside(joint, collider, worldPosition, headTransform, maxColliderScale, logic, ref nextTail); + break; + + default: + throw new NotImplementedException(); } } @@ -203,5 +215,71 @@ namespace UniVRM10.FastSpringBones.System nextTail = headTransform.position + (posFromCollider - headTransform.position).normalized * logic.length; } } + + private static void ResolveSphereCollisionInside( + BlittableJoint joint, + BlittableCollider collider, + Vector3 worldPosition, + BlittableTransform headTransform, + float maxColliderScale, + BlittableLogic logic, + ref Vector3 nextTail) + { + var r = joint.radius + collider.radius * maxColliderScale; + if (Vector3.SqrMagnitude(nextTail - worldPosition) <= (r * r)) + { + // ヒット。Colliderの半径方向に押し出す + var normal = (nextTail - worldPosition).normalized; + var posFromCollider = worldPosition + normal * r; + // 長さをboneLengthに強制 + nextTail = headTransform.position + (posFromCollider - headTransform.position).normalized * logic.length; + } + + // let transformedOffset = colliderOffset * colliderTransform; + // let transformedTail = colliderTail * colliderTransform; + // let offsetToTail = transformedTail - transformedOffset; + // let lengthSqCapsule = lengthSq(offsetToTail); + + // let dot = dot(offsetToTail, delta); + + // var delta = jointPosition - transformedOffset; + + // if (dot < 0.0) { + // // ジョイントがカプセルの始点側にある場合 + // // なにもしない + // } else if (dot > lengthSqCapsule) { + // // ジョイントがカプセルの終点側にある場合 + // delta -= offsetToTail; + // } else { + // // ジョイントがカプセルの始点と終点の間にある場合 + // delta -= offsetToTail * (dot / lengthSqCapsule); + // } + + // // ジョイントとコライダーの距離。負の値は衝突していることを示す + // let distance = colliderRadius - jointRadius - length(delta); + + // // ジョイントとコライダーの距離の方向。衝突している場合、この方向にジョイントを押し出す + // let direction = -normalize(delta); + } + + private static void ResolvePlaneCollision( + BlittableJoint joint, + BlittableCollider collider, + Vector3 worldPosition, + BlittableTransform headTransform, + float maxColliderScale, + BlittableLogic logic, + ref Vector3 nextTail) + { + // let transformedOffset = colliderOffset * colliderTransform; + // let transformedNormal = normalize(colliderNormal * normalMatrixFrom(colliderTransform)); + // let delta = jointPosition - transformedOffset; + + // // ジョイントとコライダーの距離。負の値は衝突していることを示す + // let distance = dot(delta, transformedNormal) - jointRadius; + + // // ジョイントとコライダーの距離の方向。衝突している場合、この方向にジョイントを押し出す + // let direction = transformedNormal; + } } } \ No newline at end of file diff --git a/Assets/VRM10/Runtime/IO/Vrm10Importer.cs b/Assets/VRM10/Runtime/IO/Vrm10Importer.cs index 65b201ae4..8f66a9c37 100644 --- a/Assets/VRM10/Runtime/IO/Vrm10Importer.cs +++ b/Assets/VRM10/Runtime/IO/Vrm10Importer.cs @@ -538,6 +538,41 @@ namespace UniVRM10 { throw new Vrm10Exception("unknown shape"); } + + // https://github.com/vrm-c/vrm-specification/tree/master/specification/VRMC_springBone_extended_collider-1.0 + // VRMC_springBone_extended_collider + if (UniGLTF.Extensions.VRMC_springBone_extended_collider.GltfDeserializer.TryGet(c.Extensions as glTFExtension, + out UniGLTF.Extensions.VRMC_springBone_extended_collider.VRMC_springBone_extended_collider exCollider)) + { + if (exCollider.Shape.Sphere is UniGLTF.Extensions.VRMC_springBone_extended_collider.ExtendedColliderShapeSphere exSphere) + { + collider.ColliderType = VRM10SpringBoneColliderTypes.Sphere; + collider.Offset = Vector3InvertX(exSphere.Offset); + collider.Radius = exSphere.Radius.Value; + if (exSphere.Inside.HasValue && exSphere.Inside.Value) + { + collider.ColliderType = VRM10SpringBoneColliderTypes.SphereIside; + } + } + else if (exCollider.Shape.Capsule is UniGLTF.Extensions.VRMC_springBone_extended_collider.ExtendedColliderShapeCapsule exCapsule) + { + collider.ColliderType = VRM10SpringBoneColliderTypes.Capsule; + collider.Offset = Vector3InvertX(exCapsule.Offset); + collider.Tail = Vector3InvertX(exCapsule.Tail); + collider.Radius = exCapsule.Radius.Value; + } + else if (exCollider.Shape.Plane is UniGLTF.Extensions.VRMC_springBone_extended_collider.ExtendedColliderShapePlane exPlane) + { + collider.ColliderType = VRM10SpringBoneColliderTypes.Plane; + collider.Offset = Vector3InvertX(exPlane.Offset); + collider.Normal = Vector3InvertX(exPlane.Normal); + collider.Radius = 0.1f; // gizmo visualize. 10cm + } + else + { + throw new Vrm10Exception("VRMC_springBone_extended_collider: unknown shape"); + } + } } } From a3564ec85920c4fef6e65a377773ddfd2ba7ea19 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Wed, 5 Jun 2024 16:09:43 +0900 Subject: [PATCH 5/8] export --- .../SpringBone/VRM10SpringBoneCollider.cs | 4 +- Assets/VRM10/Runtime/IO/Vrm10Exporter.cs | 63 ++++++++++++++++++- Assets/VRM10/Runtime/IO/Vrm10Importer.cs | 2 +- 3 files changed, 64 insertions(+), 5 deletions(-) diff --git a/Assets/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneCollider.cs b/Assets/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneCollider.cs index c33c12dd0..5f3da4974 100644 --- a/Assets/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneCollider.cs +++ b/Assets/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneCollider.cs @@ -8,7 +8,7 @@ namespace UniVRM10 Sphere, Capsule, Plane, - SphereIside, + SphereInside, } [Serializable] @@ -56,7 +56,7 @@ namespace UniVRM10 DrawPlane(transform.localToWorldMatrix, Offset, Normal, Radius); break; - case VRM10SpringBoneColliderTypes.SphereIside: + case VRM10SpringBoneColliderTypes.SphereInside: Gizmos.color = Color.cyan; Gizmos.DrawWireSphere(Offset, Radius); break; diff --git a/Assets/VRM10/Runtime/IO/Vrm10Exporter.cs b/Assets/VRM10/Runtime/IO/Vrm10Exporter.cs index 62144854f..86b753389 100644 --- a/Assets/VRM10/Runtime/IO/Vrm10Exporter.cs +++ b/Assets/VRM10/Runtime/IO/Vrm10Exporter.cs @@ -324,6 +324,57 @@ namespace UniVRM10 return shape; } + static UniGLTF.Extensions.VRMC_springBone_extended_collider.ExtendedColliderShape ExportShapeExtended(VRM10SpringBoneCollider z) + { + var shape = new UniGLTF.Extensions.VRMC_springBone_extended_collider.ExtendedColliderShape(); + switch (z.ColliderType) + { + case VRM10SpringBoneColliderTypes.Sphere: + { + shape.Sphere = new UniGLTF.Extensions.VRMC_springBone_extended_collider.ExtendedColliderShapeSphere + { + Radius = z.Radius, + Offset = ReverseX(z.Offset), + }; + break; + } + + case VRM10SpringBoneColliderTypes.Capsule: + { + shape.Capsule = new UniGLTF.Extensions.VRMC_springBone_extended_collider.ExtendedColliderShapeCapsule + { + Radius = z.Radius, + Offset = ReverseX(z.Offset), + Tail = ReverseX(z.Tail), + }; + break; + } + + case VRM10SpringBoneColliderTypes.SphereInside: + { + shape.Sphere = new UniGLTF.Extensions.VRMC_springBone_extended_collider.ExtendedColliderShapeSphere + { + Radius = z.Radius, + Offset = ReverseX(z.Offset), + Inside = true, + }; + break; + } + + case VRM10SpringBoneColliderTypes.Plane: + { + shape.Plane = new UniGLTF.Extensions.VRMC_springBone_extended_collider.ExtendedColliderShapePlane + { + Offset = ReverseX(z.Offset), + Normal = ReverseX(z.Normal), + }; + break; + } + break; + } + return shape; + } + static UniGLTF.Extensions.VRMC_springBone.SpringBoneJoint ExportJoint(VRM10SpringBoneJoint y, Func getIndexFromTransform) { var joint = new UniGLTF.Extensions.VRMC_springBone.SpringBoneJoint @@ -369,11 +420,19 @@ namespace UniVRM10 foreach (var c in colliders) { - springBone.Colliders.Add(new UniGLTF.Extensions.VRMC_springBone.Collider + var exportCollider = new UniGLTF.Extensions.VRMC_springBone.Collider { Node = getNodeIndexFromTransform(c.transform), Shape = ExportShape(c), - }); + }; + if (c.ColliderType == VRM10SpringBoneColliderTypes.SphereInside || c.ColliderType == VRM10SpringBoneColliderTypes.Plane) + { + exportCollider.Extensions = new UniGLTF.Extensions.VRMC_springBone_extended_collider.VRMC_springBone_extended_collider + { + Shape = ExportShapeExtended(c), + }; + } + springBone.Colliders.Add(exportCollider); } // colliderGroups diff --git a/Assets/VRM10/Runtime/IO/Vrm10Importer.cs b/Assets/VRM10/Runtime/IO/Vrm10Importer.cs index 8f66a9c37..f200a7dd0 100644 --- a/Assets/VRM10/Runtime/IO/Vrm10Importer.cs +++ b/Assets/VRM10/Runtime/IO/Vrm10Importer.cs @@ -551,7 +551,7 @@ namespace UniVRM10 collider.Radius = exSphere.Radius.Value; if (exSphere.Inside.HasValue && exSphere.Inside.Value) { - collider.ColliderType = VRM10SpringBoneColliderTypes.SphereIside; + collider.ColliderType = VRM10SpringBoneColliderTypes.SphereInside; } } else if (exCollider.Shape.Capsule is UniGLTF.Extensions.VRMC_springBone_extended_collider.ExtendedColliderShapeCapsule exCapsule) From 94e732d83a67894e17f5bf616e883914db889694 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 6 Jun 2024 13:45:39 +0900 Subject: [PATCH 6/8] impl plane collider --- .../Components/Vrm10Runtime/Vrm10Runtime.cs | 4 +++ .../System/UpdateFastSpringBoneJob.cs | 35 +++++++++++++------ 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs index abaa213c4..bcf573c5c 100644 --- a/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs +++ b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs @@ -172,6 +172,10 @@ namespace UniVRM10 return BlittableColliderType.Sphere; case VRM10SpringBoneColliderTypes.Capsule: return BlittableColliderType.Capsule; + case VRM10SpringBoneColliderTypes.Plane: + return BlittableColliderType.Plane; + case VRM10SpringBoneColliderTypes.SphereInside: + return BlittableColliderType.SphereInside; default: throw new ArgumentOutOfRangeException(); } diff --git a/Assets/VRM10/Runtime/FastSpringBone/System/UpdateFastSpringBoneJob.cs b/Assets/VRM10/Runtime/FastSpringBone/System/UpdateFastSpringBoneJob.cs index 495f7eecb..5a442e35e 100644 --- a/Assets/VRM10/Runtime/FastSpringBone/System/UpdateFastSpringBoneJob.cs +++ b/Assets/VRM10/Runtime/FastSpringBone/System/UpdateFastSpringBoneJob.cs @@ -92,7 +92,7 @@ namespace UniVRM10.FastSpringBones.System break; case BlittableColliderType.Plane: - ResolvePlaneCollision(joint, collider, worldPosition, headTransform, maxColliderScale, logic, ref nextTail); + ResolvePlaneCollision(joint, collider, colliderTransform, logic, ref nextTail); break; case BlittableColliderType.SphereInside: @@ -262,24 +262,37 @@ namespace UniVRM10.FastSpringBones.System // let direction = -normalize(delta); } + /// + /// SpringのJoint(head-tail)のとColliderの衝突処理。 + /// nextTail が変化しうる。 + /// + /// joint + /// collier + /// colliderTransform.localToWorldMatrix.MultiplyPoint3x4(collider.offset); + /// jointのhead + /// Mathf.Max(Mathf.Max(Mathf.Abs(colliderScale.x), Mathf.Abs(colliderScale.y)), Mathf.Abs(colliderScale.z)); + /// joint + /// verlet 積分による tail の移動予定 private static void ResolvePlaneCollision( BlittableJoint joint, BlittableCollider collider, - Vector3 worldPosition, - BlittableTransform headTransform, - float maxColliderScale, + BlittableTransform colliderTransform, BlittableLogic logic, ref Vector3 nextTail) { - // let transformedOffset = colliderOffset * colliderTransform; - // let transformedNormal = normalize(colliderNormal * normalMatrixFrom(colliderTransform)); - // let delta = jointPosition - transformedOffset; + var transformedOffset = colliderTransform.localToWorldMatrix.MultiplyPoint(collider.offset); + var transformedNormal = colliderTransform.localToWorldMatrix.MultiplyVector(collider.tailOrNormal).normalized; + var delta = nextTail - transformedOffset; - // // ジョイントとコライダーの距離。負の値は衝突していることを示す - // let distance = dot(delta, transformedNormal) - jointRadius; + // ジョイントとコライダーの距離。負の値は衝突していることを示す + var distance = Vector3.Dot(delta, transformedNormal) - joint.radius; - // // ジョイントとコライダーの距離の方向。衝突している場合、この方向にジョイントを押し出す - // let direction = transformedNormal; + if (distance < 0) + { + // ジョイントとコライダーの距離の方向。衝突している場合、この方向にジョイントを押し出す + var direction = transformedNormal; + nextTail -= direction * distance; + } } } } \ No newline at end of file From 24985e21a733bcd86e80f3c6653c833a8abb31e1 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 6 Jun 2024 14:09:32 +0900 Subject: [PATCH 7/8] CapsuleInside gizmo, import, export --- .../SpringBone/VRM10SpringBoneCollider.cs | 31 ++++++++-- .../Blittables/BlittableColliderType.cs | 1 + .../System/UpdateFastSpringBoneJob.cs | 56 ++++--------------- Assets/VRM10/Runtime/IO/Vrm10Exporter.cs | 16 +++++- Assets/VRM10/Runtime/IO/Vrm10Importer.cs | 4 +- 5 files changed, 54 insertions(+), 54 deletions(-) diff --git a/Assets/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneCollider.cs b/Assets/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneCollider.cs index 5f3da4974..6c29a1270 100644 --- a/Assets/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneCollider.cs +++ b/Assets/VRM10/Runtime/Components/SpringBone/VRM10SpringBoneCollider.cs @@ -9,6 +9,7 @@ namespace UniVRM10 Capsule, Plane, SphereInside, + CapsuleInside, } [Serializable] @@ -44,28 +45,46 @@ namespace UniVRM10 break; case VRM10SpringBoneColliderTypes.Capsule: - Gizmos.color = new Color(1.0f, 0.1f, 0.1f); - Gizmos.DrawWireSphere(Offset, Radius); - Gizmos.DrawWireSphere(Tail, Radius); - Gizmos.DrawLine(Offset, Tail); + Gizmos.color = Color.magenta; + DrawCapsuleGizmo(transform.localToWorldMatrix.MultiplyPoint(Offset), transform.localToWorldMatrix.MultiplyPoint(Tail), Radius); break; case VRM10SpringBoneColliderTypes.Plane: Gizmos.color = new Color(1.0f, 0.5f, 0.0f); - // normal offset DrawPlane(transform.localToWorldMatrix, Offset, Normal, Radius); break; case VRM10SpringBoneColliderTypes.SphereInside: - Gizmos.color = Color.cyan; + Gizmos.color = new Color(0.5f, 0, 1.0f); Gizmos.DrawWireSphere(Offset, Radius); break; + case VRM10SpringBoneColliderTypes.CapsuleInside: + Gizmos.color = new Color(0.5f, 0, 1.0f); + DrawCapsuleGizmo(transform.localToWorldMatrix.MultiplyPoint(Offset), transform.localToWorldMatrix.MultiplyPoint(Tail), Radius); + break; + default: throw new NotImplementedException(); } } + public static void DrawCapsuleGizmo(Vector3 start, Vector3 end, float radius) + { + var tail = end - start; + var distance = (end - start).magnitude; + Gizmos.matrix = Matrix4x4.TRS(start, Quaternion.FromToRotation(Vector3.forward, tail), Vector3.one); + Gizmos.DrawWireSphere(Vector3.zero, radius); + Gizmos.DrawWireSphere(Vector3.forward * distance, radius); + var capsuleEnd = Vector3.forward * distance; + var offsets = new Vector3[] { new Vector3(-1.0f, 0.0f, 0.0f), new Vector3(0.0f, 1.0f, 0.0f), new Vector3(1.0f, 0.0f, 0.0f), new Vector3(0.0f, -1.0f, 0.0f) }; + for (int i = 0; i < offsets.Length; i++) + { + Gizmos.DrawLine(offsets[i] * radius, capsuleEnd + offsets[i] * radius); + } + Gizmos.matrix = Matrix4x4.identity; + } + public static void DrawPlane(in Matrix4x4 m, in Vector3 offset, in Vector3 _n, float radius) { var n = _n.normalized; diff --git a/Assets/VRM10/Runtime/FastSpringBone/Blittables/BlittableColliderType.cs b/Assets/VRM10/Runtime/FastSpringBone/Blittables/BlittableColliderType.cs index 93ddef69a..69ea0f91d 100644 --- a/Assets/VRM10/Runtime/FastSpringBone/Blittables/BlittableColliderType.cs +++ b/Assets/VRM10/Runtime/FastSpringBone/Blittables/BlittableColliderType.cs @@ -6,5 +6,6 @@ namespace UniVRM10.FastSpringBones.Blittables Capsule, Plane, SphereInside, + CapsuleInside, } } \ No newline at end of file diff --git a/Assets/VRM10/Runtime/FastSpringBone/System/UpdateFastSpringBoneJob.cs b/Assets/VRM10/Runtime/FastSpringBone/System/UpdateFastSpringBoneJob.cs index 5a442e35e..0dcd85281 100644 --- a/Assets/VRM10/Runtime/FastSpringBone/System/UpdateFastSpringBoneJob.cs +++ b/Assets/VRM10/Runtime/FastSpringBone/System/UpdateFastSpringBoneJob.cs @@ -92,11 +92,15 @@ namespace UniVRM10.FastSpringBones.System break; case BlittableColliderType.Plane: - ResolvePlaneCollision(joint, collider, colliderTransform, logic, ref nextTail); + ResolvePlaneCollision(joint, collider, colliderTransform, ref nextTail); break; case BlittableColliderType.SphereInside: - ResolveSphereCollisionInside(joint, collider, worldPosition, headTransform, maxColliderScale, logic, ref nextTail); + // ResolveSphereCollisionInside(joint, collider, worldPosition, headTransform, maxColliderScale, logic, ref nextTail); + break; + + case BlittableColliderType.CapsuleInside: + // ResolveCapsuleCollisionInside(joint, collider, worldPosition, headTransform, maxColliderScale, logic, ref nextTail); break; default: @@ -219,65 +223,27 @@ namespace UniVRM10.FastSpringBones.System private static void ResolveSphereCollisionInside( BlittableJoint joint, BlittableCollider collider, + BlittableTransform colliderTransform, Vector3 worldPosition, BlittableTransform headTransform, float maxColliderScale, BlittableLogic logic, ref Vector3 nextTail) { - var r = joint.radius + collider.radius * maxColliderScale; - if (Vector3.SqrMagnitude(nextTail - worldPosition) <= (r * r)) - { - // ヒット。Colliderの半径方向に押し出す - var normal = (nextTail - worldPosition).normalized; - var posFromCollider = worldPosition + normal * r; - // 長さをboneLengthに強制 - nextTail = headTransform.position + (posFromCollider - headTransform.position).normalized * logic.length; - } - - // let transformedOffset = colliderOffset * colliderTransform; - // let transformedTail = colliderTail * colliderTransform; - // let offsetToTail = transformedTail - transformedOffset; - // let lengthSqCapsule = lengthSq(offsetToTail); - - // let dot = dot(offsetToTail, delta); - - // var delta = jointPosition - transformedOffset; - - // if (dot < 0.0) { - // // ジョイントがカプセルの始点側にある場合 - // // なにもしない - // } else if (dot > lengthSqCapsule) { - // // ジョイントがカプセルの終点側にある場合 - // delta -= offsetToTail; - // } else { - // // ジョイントがカプセルの始点と終点の間にある場合 - // delta -= offsetToTail * (dot / lengthSqCapsule); - // } - - // // ジョイントとコライダーの距離。負の値は衝突していることを示す - // let distance = colliderRadius - jointRadius - length(delta); - - // // ジョイントとコライダーの距離の方向。衝突している場合、この方向にジョイントを押し出す - // let direction = -normalize(delta); } /// - /// SpringのJoint(head-tail)のとColliderの衝突処理。 - /// nextTail が変化しうる。 + /// Collision with SpringJoint and PlaneCollider. + /// If collide update nextTail. /// /// joint /// collier - /// colliderTransform.localToWorldMatrix.MultiplyPoint3x4(collider.offset); - /// jointのhead - /// Mathf.Max(Mathf.Max(Mathf.Abs(colliderScale.x), Mathf.Abs(colliderScale.y)), Mathf.Abs(colliderScale.z)); - /// joint - /// verlet 積分による tail の移動予定 + /// colliderTransform.localToWorldMatrix.MultiplyPoint3x4(collider.offset); + /// result of verlet integration private static void ResolvePlaneCollision( BlittableJoint joint, BlittableCollider collider, BlittableTransform colliderTransform, - BlittableLogic logic, ref Vector3 nextTail) { var transformedOffset = colliderTransform.localToWorldMatrix.MultiplyPoint(collider.offset); diff --git a/Assets/VRM10/Runtime/IO/Vrm10Exporter.cs b/Assets/VRM10/Runtime/IO/Vrm10Exporter.cs index 86b753389..7a26cd8d5 100644 --- a/Assets/VRM10/Runtime/IO/Vrm10Exporter.cs +++ b/Assets/VRM10/Runtime/IO/Vrm10Exporter.cs @@ -361,6 +361,17 @@ namespace UniVRM10 break; } + case VRM10SpringBoneColliderTypes.CapsuleInside: + { + shape.Capsule = new UniGLTF.Extensions.VRMC_springBone_extended_collider.ExtendedColliderShapeCapsule + { + Radius = z.Radius, + Offset = ReverseX(z.Offset), + Tail = ReverseX(z.Tail), + }; + break; + } + case VRM10SpringBoneColliderTypes.Plane: { shape.Plane = new UniGLTF.Extensions.VRMC_springBone_extended_collider.ExtendedColliderShapePlane @@ -425,7 +436,10 @@ namespace UniVRM10 Node = getNodeIndexFromTransform(c.transform), Shape = ExportShape(c), }; - if (c.ColliderType == VRM10SpringBoneColliderTypes.SphereInside || c.ColliderType == VRM10SpringBoneColliderTypes.Plane) + if (c.ColliderType == VRM10SpringBoneColliderTypes.SphereInside + || c.ColliderType == VRM10SpringBoneColliderTypes.CapsuleInside + || c.ColliderType == VRM10SpringBoneColliderTypes.Plane + ) { exportCollider.Extensions = new UniGLTF.Extensions.VRMC_springBone_extended_collider.VRMC_springBone_extended_collider { diff --git a/Assets/VRM10/Runtime/IO/Vrm10Importer.cs b/Assets/VRM10/Runtime/IO/Vrm10Importer.cs index f200a7dd0..98d7ac94b 100644 --- a/Assets/VRM10/Runtime/IO/Vrm10Importer.cs +++ b/Assets/VRM10/Runtime/IO/Vrm10Importer.cs @@ -546,7 +546,7 @@ namespace UniVRM10 { if (exCollider.Shape.Sphere is UniGLTF.Extensions.VRMC_springBone_extended_collider.ExtendedColliderShapeSphere exSphere) { - collider.ColliderType = VRM10SpringBoneColliderTypes.Sphere; + collider.ColliderType = exSphere.Inside.GetValueOrDefault() ? VRM10SpringBoneColliderTypes.SphereInside : VRM10SpringBoneColliderTypes.Sphere; collider.Offset = Vector3InvertX(exSphere.Offset); collider.Radius = exSphere.Radius.Value; if (exSphere.Inside.HasValue && exSphere.Inside.Value) @@ -556,7 +556,7 @@ namespace UniVRM10 } else if (exCollider.Shape.Capsule is UniGLTF.Extensions.VRMC_springBone_extended_collider.ExtendedColliderShapeCapsule exCapsule) { - collider.ColliderType = VRM10SpringBoneColliderTypes.Capsule; + collider.ColliderType = exCapsule.Inside.GetValueOrDefault() ? VRM10SpringBoneColliderTypes.CapsuleInside : VRM10SpringBoneColliderTypes.Capsule; collider.Offset = Vector3InvertX(exCapsule.Offset); collider.Tail = Vector3InvertX(exCapsule.Tail); collider.Radius = exCapsule.Radius.Value; From 4ffb65999289d7266bce265e901e836bc2ca4611 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Thu, 6 Jun 2024 14:24:43 +0900 Subject: [PATCH 8/8] impl capsule inside --- .../Components/Vrm10Runtime/Vrm10Runtime.cs | 2 + .../System/UpdateFastSpringBoneJob.cs | 61 +++++++++++++++++-- 2 files changed, 57 insertions(+), 6 deletions(-) diff --git a/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs index bcf573c5c..52eccc274 100644 --- a/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs +++ b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs @@ -176,6 +176,8 @@ namespace UniVRM10 return BlittableColliderType.Plane; case VRM10SpringBoneColliderTypes.SphereInside: return BlittableColliderType.SphereInside; + case VRM10SpringBoneColliderTypes.CapsuleInside: + return BlittableColliderType.CapsuleInside; default: throw new ArgumentOutOfRangeException(); } diff --git a/Assets/VRM10/Runtime/FastSpringBone/System/UpdateFastSpringBoneJob.cs b/Assets/VRM10/Runtime/FastSpringBone/System/UpdateFastSpringBoneJob.cs index 0dcd85281..4c7009d09 100644 --- a/Assets/VRM10/Runtime/FastSpringBone/System/UpdateFastSpringBoneJob.cs +++ b/Assets/VRM10/Runtime/FastSpringBone/System/UpdateFastSpringBoneJob.cs @@ -96,11 +96,11 @@ namespace UniVRM10.FastSpringBones.System break; case BlittableColliderType.SphereInside: - // ResolveSphereCollisionInside(joint, collider, worldPosition, headTransform, maxColliderScale, logic, ref nextTail); + ResolveSphereCollisionInside(joint, collider, colliderTransform, ref nextTail); break; case BlittableColliderType.CapsuleInside: - // ResolveCapsuleCollisionInside(joint, collider, worldPosition, headTransform, maxColliderScale, logic, ref nextTail); + ResolveCapsuleCollisionInside(joint, collider, colliderTransform, ref nextTail); break; default: @@ -224,12 +224,61 @@ namespace UniVRM10.FastSpringBones.System BlittableJoint joint, BlittableCollider collider, BlittableTransform colliderTransform, - Vector3 worldPosition, - BlittableTransform headTransform, - float maxColliderScale, - BlittableLogic logic, ref Vector3 nextTail) { + var transformedOffset = colliderTransform.localToWorldMatrix.MultiplyPoint(collider.offset); + var delta = nextTail - transformedOffset; + + // ジョイントとコライダーの距離。負の値は衝突していることを示す + var distance = collider.radius - joint.radius - delta.magnitude; + + // ジョイントとコライダーの距離の方向。衝突している場合、この方向にジョイントを押し出す + if (distance < 0) + { + var direction = -delta.normalized; + nextTail -= direction * distance; + } + } + + private static void ResolveCapsuleCollisionInside( + BlittableJoint joint, + BlittableCollider collider, + BlittableTransform colliderTransform, + ref Vector3 nextTail) + { + var transformedOffset = colliderTransform.localToWorldMatrix.MultiplyPoint(collider.offset); + var transformedTail = colliderTransform.localToWorldMatrix.MultiplyPoint(collider.tailOrNormal); + var offsetToTail = transformedTail - transformedOffset; + var lengthSqCapsule = offsetToTail.sqrMagnitude; + + var delta = nextTail - transformedOffset; + var dot = Vector3.Dot(offsetToTail, delta); + + if (dot < 0.0) + { + // ジョイントがカプセルの始点側にある場合 + // なにもしない + } + else if (dot > lengthSqCapsule) + { + // ジョイントがカプセルの終点側にある場合 + delta -= offsetToTail; + } + else + { + // ジョイントがカプセルの始点と終点の間にある場合 + delta -= offsetToTail * (dot / lengthSqCapsule); + } + + // ジョイントとコライダーの距離。負の値は衝突していることを示す + var distance = collider.radius - joint.radius - delta.magnitude; + + // ジョイントとコライダーの距離の方向。衝突している場合、この方向にジョイントを押し出す + if (distance < 0) + { + var direction = -delta.normalized; + nextTail -= direction * distance; + } } ///