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));
+ }
}
}