mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-08-27 21:34:38 -05:00
Merge pull request #823 from ousttrue/fix/non_float_weights
Implement WEIGHTS_0 accessor for byte and ushort.
This commit is contained in:
43
Assets/UniGLTF/Runtime/UniGLTF/IO/JointsAccessor.cs
Normal file
43
Assets/UniGLTF/Runtime/UniGLTF/IO/JointsAccessor.cs
Normal 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}");
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/UniGLTF/Runtime/UniGLTF/IO/JointsAccessor.cs.meta
Normal file
11
Assets/UniGLTF/Runtime/UniGLTF/IO/JointsAccessor.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c577e942203a0694dbd7dfdbd2b5b4e5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
56
Assets/UniGLTF/Runtime/UniGLTF/IO/WeightsAccessor.cs
Normal file
56
Assets/UniGLTF/Runtime/UniGLTF/IO/WeightsAccessor.cs
Normal 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}"); }
|
||||
}
|
||||
}
|
||||
11
Assets/UniGLTF/Runtime/UniGLTF/IO/WeightsAccessor.cs.meta
Normal file
11
Assets/UniGLTF/Runtime/UniGLTF/IO/WeightsAccessor.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 606f2dd4678c3a84e874097526fdc6c7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
63
Assets/UniGLTF/Tests/UniGLTF/MeshTests.cs
Normal file
63
Assets/UniGLTF/Tests/UniGLTF/MeshTests.cs
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/UniGLTF/Tests/UniGLTF/MeshTests.cs.meta
Normal file
11
Assets/UniGLTF/Tests/UniGLTF/MeshTests.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 319f54b4f10c93a4d80670e424f4fe34
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user