Merge pull request #823 from ousttrue/fix/non_float_weights

Implement WEIGHTS_0 accessor for byte and ushort.
This commit is contained in:
ousttrue
2021-03-29 16:49:47 +09:00
committed by GitHub
7 changed files with 240 additions and 67 deletions

View File

@@ -0,0 +1,43 @@
using System;
namespace UniGLTF
{
/// <summary>
/// JOINTS_0 の byte4 もしくは ushort4 に対するアクセスを提供する
/// </summary>
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<Byte4>(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<UShort4>(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}");
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c577e942203a0694dbd7dfdbd2b5b4e5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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<Byte4>(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<UShort4>(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;
}
/// <summary>
@@ -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<Float4>(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<Float4>(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);
}
}

View File

@@ -0,0 +1,56 @@
using System;
using UnityEngine;
namespace UniGLTF
{
public static class WeightsAccessor
{
/// <summary>
/// WEIGHTS_0 の byte4 もしくは ushort4 もしくは float4 に対するアクセスを提供する
/// </summary>
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<Byte4>(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<UShort4>(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<Vector4>(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}"); }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 606f2dd4678c3a84e874097526fdc6c7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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<byte>(bytes));
var gltf = new glTF
{
buffers=new List<glTFBuffer>
{
new glTFBuffer
{
}
},
bufferViews = new List<glTFBufferView>
{
new glTFBufferView{
buffer=0,
byteLength=32,
byteOffset=0,
}
},
accessors = new List<glTFAccessor>
{
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));
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 319f54b4f10c93a4d80670e424f4fe34
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: