From 65ee54543a177bb1aafce3295218bc42b6a2ef04 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Mon, 8 Feb 2021 22:51:39 +0900 Subject: [PATCH] update --- .../VRM10/Runtime/Migration/MigrationVrm.cs | 8 +- Assets/VRM10/Runtime/Migration/RotateY180.cs | 94 +++++++++++++++++++ ...ceneRotator.cs.meta => RotateY180.cs.meta} | 0 .../VRM10/Runtime/Migration/SceneRotator.cs | 14 --- Assets/VRM10/Runtime/UnityExtensions.cs | 18 ++++ Assets/VRM10/Tests/MigrationTests.cs | 40 ++++++++ 6 files changed, 159 insertions(+), 15 deletions(-) create mode 100644 Assets/VRM10/Runtime/Migration/RotateY180.cs rename Assets/VRM10/Runtime/Migration/{SceneRotator.cs.meta => RotateY180.cs.meta} (100%) delete mode 100644 Assets/VRM10/Runtime/Migration/SceneRotator.cs diff --git a/Assets/VRM10/Runtime/Migration/MigrationVrm.cs b/Assets/VRM10/Runtime/Migration/MigrationVrm.cs index a86a0c8ae..93cb6d3e6 100644 --- a/Assets/VRM10/Runtime/Migration/MigrationVrm.cs +++ b/Assets/VRM10/Runtime/Migration/MigrationVrm.cs @@ -16,8 +16,14 @@ namespace UniVRM10 var json = glb.Json.Bytes.ParseAsJson(); var gltf = UniGLTF.GltfDeserializer.Deserialize(json); + // attach glb bin to buffer + foreach (var buffer in gltf.buffers) + { + buffer.OpenStorage(new UniGLTF.SimpleStorage(glb.Binary.Bytes)); + } + // https://github.com/vrm-c/vrm-specification/issues/205 - SceneRotator.Rotate(gltf); + RotateY180.Rotate(gltf); var extensions = new UniGLTF.glTFExtensionExport(); { diff --git a/Assets/VRM10/Runtime/Migration/RotateY180.cs b/Assets/VRM10/Runtime/Migration/RotateY180.cs new file mode 100644 index 000000000..7d2eb6974 --- /dev/null +++ b/Assets/VRM10/Runtime/Migration/RotateY180.cs @@ -0,0 +1,94 @@ +using System; +using System.Collections.Generic; +using UniGLTF; + +namespace UniVRM10 +{ + /// + /// x, y, z => -x, y, -z + /// + public static class RotateY180 + { + public static void Rotate(glTFNode node) + { + if (node.matrix != null && node.matrix.Length == 16) + { + throw new NotImplementedException("matrix not implemented !"); + } + else + { + if (node.translation != null && node.translation.Length == 3) + { + var t = node.translation; + t[0] = -t[0]; + t[2] = -t[2]; + } + if (node.rotation != null && node.rotation.Length == 4) + { + // throw new NotImplementedException("not normlaized !"); + } + if (node.scale != null && node.rotation.Length == 3) + { + // do nothing + } + } + } + + static void ReverseVector3Array(glTF gltf, int accessorIndex, HashSet used) + { + if (!used.Add(accessorIndex)) + { + return; + } + + var accessor = gltf.accessors[accessorIndex]; + var buffer = gltf.GetViewBytes(accessor.bufferView); + var span = VrmLib.SpanLike.Wrap(buffer); + for (int i = 0; i < span.Length; ++i) + { + span[i] = span[i].RotateY180(); + } + } + + /// + /// シーンをY軸で180度回転する + /// + /// + public static void Rotate(glTF gltf) + { + foreach (var node in gltf.nodes) + { + Rotate(node); + } + + var used = new HashSet(); + foreach (var mesh in gltf.meshes) + { + foreach (var prim in mesh.primitives) + { + ReverseVector3Array(gltf, prim.attributes.POSITION, used); + ReverseVector3Array(gltf, prim.attributes.NORMAL, used); + foreach (var target in prim.targets) + { + ReverseVector3Array(gltf, target.POSITION, used); + ReverseVector3Array(gltf, target.NORMAL, used); + } + } + } + + foreach (var skin in gltf.skins) + { + if (!used.Add(skin.inverseBindMatrices)) + { + var accessor = gltf.accessors[skin.inverseBindMatrices]; + var buffer = gltf.GetViewBytes(accessor.bufferView); + var span = VrmLib.SpanLike.Wrap(buffer); + for (int i = 0; i < span.Length; ++i) + { + // span[i] = span[i].RotateY180(); + } + } + } + } + } +} diff --git a/Assets/VRM10/Runtime/Migration/SceneRotator.cs.meta b/Assets/VRM10/Runtime/Migration/RotateY180.cs.meta similarity index 100% rename from Assets/VRM10/Runtime/Migration/SceneRotator.cs.meta rename to Assets/VRM10/Runtime/Migration/RotateY180.cs.meta diff --git a/Assets/VRM10/Runtime/Migration/SceneRotator.cs b/Assets/VRM10/Runtime/Migration/SceneRotator.cs deleted file mode 100644 index 46acf133c..000000000 --- a/Assets/VRM10/Runtime/Migration/SceneRotator.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace UniVRM10 -{ - public static class SceneRotator - { - /// - /// シーンをY軸で180度回転する - /// - /// - public static void Rotate(UniGLTF.glTF gltf) - { - - } - } -} diff --git a/Assets/VRM10/Runtime/UnityExtensions.cs b/Assets/VRM10/Runtime/UnityExtensions.cs index 2e9e0796a..69a3da22a 100644 --- a/Assets/VRM10/Runtime/UnityExtensions.cs +++ b/Assets/VRM10/Runtime/UnityExtensions.cs @@ -40,11 +40,21 @@ namespace UniVRM10 public static class UnityExtensions { + public static Vector4 RotateY180(this Vector4 v) + { + return new Vector4(-v.x, v.y, -v.z, v.w); + } + public static Vector4 ReverseZ(this Vector4 v) { return new Vector4(v.x, v.y, -v.z, v.w); } + public static Vector3 RotateY180(this Vector3 v) + { + return new Vector3(-v.x, v.y, -v.z); + } + public static Vector3 ReverseZ(this Vector3 v) { return new Vector3(v.x, v.y, -v.z); @@ -94,6 +104,14 @@ namespace UniVRM10 #endif } + public static Matrix4x4 RotateY180(this Matrix4x4 m) + { + var t = m.GetColumn(3); + var tt = RotateY180(t); + m.SetColumn(3, tt); + return m; + } + public static Matrix4x4 ReverseZ(this Matrix4x4 m) { m.SetTRS(m.ExtractPosition().ReverseZ(), m.ExtractRotation().ReverseZ(), m.ExtractScale()); diff --git a/Assets/VRM10/Tests/MigrationTests.cs b/Assets/VRM10/Tests/MigrationTests.cs index 7256f6ffa..905313536 100644 --- a/Assets/VRM10/Tests/MigrationTests.cs +++ b/Assets/VRM10/Tests/MigrationTests.cs @@ -3,6 +3,7 @@ using NUnit.Framework; using UnityEngine; using UniJSON; using System; +using UniGLTF; namespace UniVRM10 { @@ -56,5 +57,44 @@ namespace UniVRM10 MigrationVrm.Check(vrm0Json, GetExtension(gltf.extensions, UniGLTF.Extensions.VRMC_springBone.VRMC_springBone.ExtensionNameUtf8, UniGLTF.Extensions.VRMC_springBone.GltfDeserializer.Deserialize), gltf.nodes); } + + const float EPS = 1e-4f; + + static bool Nearly(float l, float r) + { + return Mathf.Abs(l - r) <= EPS; + } + + static bool Nearly(Vector3 l, Vector3 r) + { + if (!Nearly(l.x, r.x)) return false; + if (!Nearly(l.y, r.y)) return false; + if (!Nearly(l.z, r.z)) return false; + return true; + } + + [Test] + public void RotateTest() + { + var euler = new Vector3(0, 10, 20); + var r = Quaternion.Euler(euler); + var node = new glTFNode + { + translation = new float[] { 1, 2, 3 }, + rotation = new float[] { r.x, r.y, r.z, r.w }, + scale = new float[] { 1, 2, 3 }, + }; + RotateY180.Rotate(node); + + Assert.AreEqual(new Vector3(-1, 2, 3), node.translation.ToVector3().ToUnityVector3()); + Assert.AreEqual(new Vector3(1, 2, 3), node.scale.ToVector3().ToUnityVector3()); + + var result = node.rotation.ToQuaternion().ToUnityQuaternion().eulerAngles; + Debug.LogFormat($"{result}"); + + Assert.True(Nearly(0, result.x)); + Assert.True(Nearly(360 - 10, result.y)); + Assert.True(Nearly(360 - 20, result.z)); + } } }