diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/JointsAccessor.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/JointsAccessor.cs new file mode 100644 index 000000000..b20a94a21 --- /dev/null +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/JointsAccessor.cs @@ -0,0 +1,43 @@ +using System; + +namespace UniGLTF +{ + /// + /// JOINTS_0 の byte4 もしくは ushort4 に対するアクセスを提供する + /// + public static class JointsAccessor + { + public delegate (ushort x, ushort y, ushort z, ushort w) Getter(int index); + + public static (Getter, int) GetAccessor(glTF gltf, int accessorIndex) + { + var gltfAccessor = gltf.accessors[accessorIndex]; + switch (gltfAccessor.componentType) + { + case glComponentType.UNSIGNED_BYTE: + { + var array = gltf.GetArrayFromAccessor(accessorIndex); + Getter getter = (i) => + { + var value = array[i]; + return (value.x, value.y, value.z, value.w); + }; + return (getter, array.Length); + } + + case glComponentType.UNSIGNED_SHORT: + { + var array = gltf.GetArrayFromAccessor(accessorIndex); + Getter getter = (i) => + { + var value = array[i]; + return (value.x, value.y, value.z, value.w); + }; + return (getter, array.Length); + } + } + + throw new NotImplementedException($"JOINTS_0 not support {gltfAccessor.componentType}"); + } + } +} diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/JointsAccessor.cs.meta b/Assets/UniGLTF/Runtime/UniGLTF/IO/JointsAccessor.cs.meta new file mode 100644 index 000000000..be1ea71aa --- /dev/null +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/JointsAccessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c577e942203a0694dbd7dfdbd2b5b4e5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshImporter.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshImporter.cs index 248798737..8d6a762c5 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshImporter.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshImporter.cs @@ -98,49 +98,21 @@ namespace UniGLTF } } - delegate ushort Getter(int index, int component); - static (Getter, int) GetAccessor(glTF gltf, int accessorIndex) + + public static BoneWeight NormalizeBoneWeight(BoneWeight src) { - var gltfAccessor = gltf.accessors[accessorIndex]; - switch (gltfAccessor.componentType) + var sum = src.weight0 + src.weight1 + src.weight2 + src.weight3; + if (sum == 0) { - case glComponentType.UNSIGNED_BYTE: - { - var array = gltf.GetArrayFromAccessor(accessorIndex); - Getter getter = (i, j) => - { - switch (j) - { - case 0: return array[i].x; - case 1: return array[i].y; - case 2: return array[i].z; - case 3: return array[i].w; - default: throw new Exception(); - } - }; - return (getter, array.Length); - } - - case glComponentType.UNSIGNED_SHORT: - { - var array = gltf.GetArrayFromAccessor(accessorIndex); - Getter getter = (i, j) => - { - switch (j) - { - case 0: return array[i].x; - case 1: return array[i].y; - case 2: return array[i].z; - case 3: return array[i].w; - default: throw new Exception(); - } - }; - return (getter, array.Length); - } + return src; } - - throw new Exception(); + var f = 1.0f / sum; + src.weight0 *= f; + src.weight1 *= f; + src.weight2 *= f; + src.weight3 *= f; + return src; } /// @@ -239,32 +211,37 @@ namespace UniGLTF // skin if (prim.attributes.JOINTS_0 != -1 && prim.attributes.WEIGHTS_0 != -1) { - var (joints0, length) = GetAccessor(ctx.GLTF, prim.attributes.JOINTS_0); - var weights0 = ctx.GLTF.GetArrayFromAccessor(prim.attributes.WEIGHTS_0).Select(x => x.One()).ToArray(); - if (length != positions.Length) + var (joints0, jointsLength) = JointsAccessor.GetAccessor(ctx.GLTF, prim.attributes.JOINTS_0); + var (weights0, weightsLength) = WeightsAccessor.GetAccessor(ctx.GLTF, prim.attributes.WEIGHTS_0); + if (jointsLength != positions.Length) { throw new Exception("different length"); } - if (weights0.Length != positions.Length) + if (weightsLength != positions.Length) { throw new Exception("different length"); } FillZero(m_boneWeights, fillLength); - for (int j = 0; j < length; ++j) + for (int j = 0; j < jointsLength; ++j) { var bw = new BoneWeight(); + + var joints = joints0(j); + var weights = weights0(j); - bw.boneIndex0 = joints0(j, 0); - bw.weight0 = weights0[j].x; + bw.boneIndex0 = joints.x; + bw.weight0 = weights.x; - bw.boneIndex1 = joints0(j, 1); - bw.weight1 = weights0[j].y; + bw.boneIndex1 = joints.y; + bw.weight1 = weights.y; - bw.boneIndex2 = joints0(j, 2); - bw.weight2 = weights0[j].z; + bw.boneIndex2 = joints.z; + bw.weight2 = weights.z; - bw.boneIndex3 = joints0(j, 3); - bw.weight3 = weights0[j].w; + bw.boneIndex3 = joints.w; + bw.weight3 = weights.w; + + bw = NormalizeBoneWeight(bw); m_boneWeights.Add(bw); } @@ -406,29 +383,30 @@ namespace UniGLTF // skin if (prim.attributes.JOINTS_0 != -1 && prim.attributes.WEIGHTS_0 != -1) { - var (joints0, length) = GetAccessor(ctx.GLTF, prim.attributes.JOINTS_0); - var weights0 = ctx.GLTF.GetArrayFromAccessor(prim.attributes.WEIGHTS_0); - for (int i = 0; i < weights0.Length; ++i) - { - weights0[i] = weights0[i].One(); - } + var (joints0, jointsLength) = JointsAccessor.GetAccessor(ctx.GLTF, prim.attributes.JOINTS_0); + var (weights0, weightsLength) = WeightsAccessor.GetAccessor(ctx.GLTF, prim.attributes.WEIGHTS_0); - for (int j = 0; j < length; ++j) + for (int j = 0; j < jointsLength; ++j) { var bw = new BoneWeight(); + + var joints = joints0(j); + var weights = weights0(j); - bw.boneIndex0 = joints0(j, 0); - bw.weight0 = weights0[j].x; + bw.boneIndex0 = joints.x; + bw.weight0 = weights.x; - bw.boneIndex1 = joints0(j, 1); - bw.weight1 = weights0[j].y; + bw.boneIndex1 = joints.y; + bw.weight1 = weights.y; - bw.boneIndex2 = joints0(j, 2); - bw.weight2 = weights0[j].z; + bw.boneIndex2 = joints.z; + bw.weight2 = weights.z; - bw.boneIndex3 = joints0(j, 3); - bw.weight3 = weights0[j].w; + bw.boneIndex3 = joints.w; + bw.weight3 = weights.w; + bw = NormalizeBoneWeight(bw); + m_boneWeights.Add(bw); } } diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/WeightsAccessor.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/WeightsAccessor.cs new file mode 100644 index 000000000..7a264b070 --- /dev/null +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/WeightsAccessor.cs @@ -0,0 +1,56 @@ +using System; +using UnityEngine; + +namespace UniGLTF +{ + public static class WeightsAccessor + { + /// + /// WEIGHTS_0 の byte4 もしくは ushort4 もしくは float4 に対するアクセスを提供する + /// + public delegate (float x, float y, float z, float w) Getter(int index); + + public static (Getter, int) GetAccessor(glTF gltf, int accessorIndex) + { + var gltfAccessor = gltf.accessors[accessorIndex]; + switch (gltfAccessor.componentType) + { + case glComponentType.UNSIGNED_BYTE: + { + var array = gltf.GetArrayFromAccessor(accessorIndex); + Getter getter = (i) => + { + var value = array[i]; + var inv = 1.0f / byte.MaxValue; + return (value.x*inv, value.y*inv, value.z*inv, value.w*inv); + }; + return (getter, array.Length); + } + + case glComponentType.UNSIGNED_SHORT: + { + var array = gltf.GetArrayFromAccessor(accessorIndex); + Getter getter = (i) => + { + var value = array[i]; + var inv = 1.0f / ushort.MaxValue; + return (value.x*inv, value.y*inv, value.z*inv, value.w*inv); + }; + return (getter, array.Length); + } + + case glComponentType.FLOAT: + { + var array = gltf.GetArrayFromAccessor(accessorIndex); + Getter getter = (i) => + { + var value = array[i]; + return (value.x, value.y, value.z, value.w); + }; + return (getter, array.Length); + } + } + + throw new NotImplementedException($"WEIGHTS_0 not support {gltfAccessor.componentType}"); } + } +} diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/WeightsAccessor.cs.meta b/Assets/UniGLTF/Runtime/UniGLTF/IO/WeightsAccessor.cs.meta new file mode 100644 index 000000000..0af30984a --- /dev/null +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/WeightsAccessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 606f2dd4678c3a84e874097526fdc6c7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UniGLTF/Tests/UniGLTF/MeshTests.cs b/Assets/UniGLTF/Tests/UniGLTF/MeshTests.cs new file mode 100644 index 000000000..840fd67f7 --- /dev/null +++ b/Assets/UniGLTF/Tests/UniGLTF/MeshTests.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.IO; +using NUnit.Framework; + +namespace UniGLTF +{ + public class MeshTests + { + [Test] + public void AccessorTest() + { + byte[] bytes = default; + using(var ms = new MemoryStream()) + using(var w = new BinaryWriter(ms)) + { + w.Write(1.0f); + w.Write(2.0f); + w.Write(3.0f); + w.Write(4.0f); + w.Write(5.0f); + w.Write(6.0f); + w.Write(7.0f); + w.Write(8.0f); + bytes = ms.ToArray(); + } + var storage = new SimpleStorage(new ArraySegment(bytes)); + + var gltf = new glTF + { + buffers=new List + { + new glTFBuffer + { + } + }, + bufferViews = new List + { + new glTFBufferView{ + buffer=0, + byteLength=32, + byteOffset=0, + } + }, + accessors = new List + { + new glTFAccessor{ + bufferView = 0, + componentType=glComponentType.FLOAT, + count=2, + byteOffset=0, + type="VEC4", + } + } + }; + gltf.buffers[0].OpenStorage(storage); + + var (getter, len) = WeightsAccessor.GetAccessor(gltf, 0); + Assert.AreEqual((1.0f, 2.0f, 3.0f, 4.0f), getter(0)); + Assert.AreEqual((5.0f, 6.0f, 7.0f, 8.0f), getter(1)); + } + } +} diff --git a/Assets/UniGLTF/Tests/UniGLTF/MeshTests.cs.meta b/Assets/UniGLTF/Tests/UniGLTF/MeshTests.cs.meta new file mode 100644 index 000000000..4f4af94e9 --- /dev/null +++ b/Assets/UniGLTF/Tests/UniGLTF/MeshTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 319f54b4f10c93a4d80670e424f4fe34 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: