Merge pull request #1523 from ousttrue/fix10/spanlike_to_nativearray

SpanLike を NativeArray で置き換える
This commit is contained in:
ousttrue
2022-02-14 20:14:47 +09:00
committed by GitHub
45 changed files with 484 additions and 1614 deletions

View File

@@ -1,36 +0,0 @@
using System;
namespace UniGLTF
{
/// <summary>
/// for glb chunk buffer read
/// </summary>
public class ArraySegmentByteBuffer : IBytesBuffer
{
ArraySegment<Byte> m_bytes;
public ArraySegmentByteBuffer(ArraySegment<Byte> bytes)
{
m_bytes = bytes;
}
public string Uri
{
get;
private set;
}
public glTFBufferView Extend<T>(ArraySegment<T> array, glBufferTarget target) where T : struct
{
throw new NotImplementedException();
}
public void ExtendCapacity(int capacity)
{
throw new NotImplementedException();
}
public ArraySegment<byte> Bytes => m_bytes;
}
}

View File

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

View File

@@ -1,12 +0,0 @@
using System;
namespace UniGLTF
{
public interface IBytesBuffer
{
string Uri { get; }
ArraySegment<Byte> Bytes { get; }
glTFBufferView Extend<T>(ArraySegment<T> array, glBufferTarget target = glBufferTarget.NONE) where T : struct;
void ExtendCapacity(int capacity);
}
}

View File

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

View File

@@ -1,14 +1,15 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
namespace UniGLTF
{
/// <summary>
/// for exporter
/// </summary>
public class ArrayByteBuffer : IBytesBuffer
public class ArrayByteBuffer
{
public string Uri
{
@@ -25,6 +26,11 @@ namespace UniGLTF
m_bytes = bytes;
}
public glTFBufferView Extend<T>(NativeArray<T> array, glBufferTarget target = default) where T : struct
{
return Extend(new ArraySegment<T>(array.ToArray()), target);
}
public glTFBufferView Extend<T>(ArraySegment<T> array, glBufferTarget target = default) where T : struct
{
using (var pin = Pin.Create(array))

View File

@@ -2,14 +2,15 @@ using System;
using System.Collections.Generic;
using System.IO;
using UniJSON;
using Unity.Collections;
namespace UniGLTF
{
public class ExportingGltfData
{
public glTF GLTF { get; } = new glTF();
public glTF Gltf { get; } = new glTF();
protected IBytesBuffer _buffer;
protected ArrayByteBuffer _buffer;
/// <summary>
/// bin chunk
/// </summary>
@@ -23,7 +24,7 @@ namespace UniGLTF
}
// buffers[0] is export target
GLTF.buffers.Add(new glTFBuffer());
Gltf.buffers.Add(new glTFBuffer());
_buffer = new ArrayByteBuffer(new byte[reserved]);
}
@@ -31,7 +32,7 @@ namespace UniGLTF
public glTFBufferView ExtendBufferAndGetView<T>(ArraySegment<T> segment, glBufferTarget target) where T : struct
{
var view = _buffer.Extend(segment, target);
GLTF.buffers[0].byteLength = _buffer.Bytes.Count;
Gltf.buffers[0].byteLength = _buffer.Bytes.Count;
return view;
}
@@ -44,8 +45,8 @@ namespace UniGLTF
return -1;
}
var view = ExtendBufferAndGetView(array, target);
var viewIndex = GLTF.bufferViews.Count;
GLTF.bufferViews.Add(view);
var viewIndex = Gltf.bufferViews.Count;
Gltf.bufferViews.Add(view);
return viewIndex;
}
@@ -67,10 +68,10 @@ namespace UniGLTF
var viewIndex = ExtendBufferAndGetViewIndex(array, target);
// index buffer's byteStride is unnecessary
GLTF.bufferViews[viewIndex].byteStride = 0;
Gltf.bufferViews[viewIndex].byteStride = 0;
var accessorIndex = GLTF.accessors.Count;
GLTF.accessors.Add(new glTFAccessor
var accessorIndex = Gltf.accessors.Count;
Gltf.accessors.Add(new glTFAccessor
{
bufferView = viewIndex,
byteOffset = 0,
@@ -111,8 +112,8 @@ namespace UniGLTF
return -1;
}
var sparseValuesViewIndex = ExtendBufferAndGetViewIndex(sparseValues, target);
var accessorIndex = GLTF.accessors.Count;
GLTF.accessors.Add(new glTFAccessor
var accessorIndex = Gltf.accessors.Count;
Gltf.accessors.Add(new glTFAccessor
{
byteOffset = 0,
componentType = glTFExtensions.GetComponentType<T>(),
@@ -135,6 +136,20 @@ namespace UniGLTF
});
return accessorIndex;
}
public void Reserve(int bytesLength)
{
_buffer.ExtendCapacity(bytesLength);
}
public int AppendToBuffer(NativeArray<byte> segment)
{
var gltfBufferView = _buffer.Extend(segment);
var viewIndex = Gltf.bufferViews.Count;
Gltf.bufferViews.Add(gltfBufferView);
return viewIndex;
}
#endregion
#region ToGltf & ToGlb
@@ -145,7 +160,7 @@ namespace UniGLTF
public byte[] ToGlbBytes()
{
var f = new JsonFormatter();
GltfSerializer.Serialize(f, GLTF);
GltfSerializer.Serialize(f, Gltf);
var json = f.ToString().ParseAsJson().ToString(" ");
@@ -162,10 +177,10 @@ namespace UniGLTF
public (string, glTFBuffer) ToGltf(string gltfPath)
{
// fix buffer path
if (GLTF.buffers.Count == 1)
if (Gltf.buffers.Count == 1)
{
var withoutExt = Path.GetFileNameWithoutExtension(gltfPath);
GLTF.buffers[0].uri = $"{withoutExt}.bin";
Gltf.buffers[0].uri = $"{withoutExt}.bin";
}
else
{
@@ -173,12 +188,12 @@ namespace UniGLTF
}
var f = new JsonFormatter();
GltfSerializer.Serialize(f, GLTF);
GltfSerializer.Serialize(f, Gltf);
var json = f.ToString().ParseAsJson().ToString(" ");
json = GltfJsonUtil.FindUsedExtensionsAndUpdateJson(json);
return (json, GLTF.buffers[0]);
return (json, Gltf.buffers[0]);
}
#endregion
}

View File

@@ -92,7 +92,7 @@ namespace UniGLTF
public static GltfData CreateFromExportForTest(ExportingGltfData data)
{
return CreateFromGltfDataForTest(data.GLTF, data.BinBytes);
return CreateFromGltfDataForTest(data.Gltf, data.BinBytes);
}
public static GltfData CreateFromGltfDataForTest(glTF gltf, ArraySegment<byte> bytes)

View File

@@ -74,8 +74,8 @@ namespace UniGLTF
{
// position
var positionAccessorIndex = data.ExtendBufferAndGetAccessorIndex(positions, glBufferTarget.ARRAY_BUFFER);
data.GLTF.accessors[positionAccessorIndex].min = positions.Aggregate(positions[0], (a, b) => new Vector3(Mathf.Min(a.x, b.x), Math.Min(a.y, b.y), Mathf.Min(a.z, b.z))).ToArray();
data.GLTF.accessors[positionAccessorIndex].max = positions.Aggregate(positions[0], (a, b) => new Vector3(Mathf.Max(a.x, b.x), Math.Max(a.y, b.y), Mathf.Max(a.z, b.z))).ToArray();
data.Gltf.accessors[positionAccessorIndex].min = positions.Aggregate(positions[0], (a, b) => new Vector3(Mathf.Min(a.x, b.x), Math.Min(a.y, b.y), Mathf.Min(a.z, b.z))).ToArray();
data.Gltf.accessors[positionAccessorIndex].max = positions.Aggregate(positions[0], (a, b) => new Vector3(Mathf.Max(a.x, b.x), Math.Max(a.y, b.y), Mathf.Max(a.z, b.z))).ToArray();
// normal
var normalAccessorIndex = -1;

View File

@@ -115,7 +115,7 @@ namespace UniGLTF
var indicesAccessorIndex = data.ExtendBufferAndGetAccessorIndex(indices.Select(x => (uint)m_vertexIndexMap[x]).ToArray(), glBufferTarget.ELEMENT_ARRAY_BUFFER);
var positions = m_positions.ToArray();
var positionAccessorIndex = data.ExtendBufferAndGetAccessorIndex(positions, glBufferTarget.ARRAY_BUFFER);
AccessorsBounds.UpdatePositionAccessorsBounds(data.GLTF.accessors[positionAccessorIndex], positions);
AccessorsBounds.UpdatePositionAccessorsBounds(data.Gltf.accessors[positionAccessorIndex], positions);
var normals = m_normals.ToArray();
var normalAccessorIndex = data.ExtendBufferAndGetAccessorIndex(normals, glBufferTarget.ARRAY_BUFFER);

View File

@@ -32,7 +32,7 @@ namespace UniGLTF
var materials = unityMesh.Materials;
var positions = mesh.vertices.Select(axisInverter.InvertVector3).ToArray();
var positionAccessorIndex = data.ExtendBufferAndGetAccessorIndex(positions, glBufferTarget.ARRAY_BUFFER);
AccessorsBounds.UpdatePositionAccessorsBounds(data.GLTF.accessors[positionAccessorIndex], positions);
AccessorsBounds.UpdatePositionAccessorsBounds(data.Gltf.accessors[positionAccessorIndex], positions);
var normalAccessorIndex = data.ExtendBufferAndGetAccessorIndex(mesh.normals.Select(y => axisInverter.InvertVector3(y.normalized)).ToArray(), glBufferTarget.ARRAY_BUFFER);

View File

@@ -6,6 +6,25 @@ using System.Runtime.InteropServices;
namespace UniGLTF
{
/// <summary>
/// NativeArrayManager を Dispose する責務を負わない使用者は、こっちを使う。
/// </summary>
public interface INativeArrayManager
{
NativeArray<T> CreateNativeArray<T>(int size)
where T : struct;
NativeArray<T> CreateNativeArray<T>(ArraySegment<T> data)
where T : struct;
NativeArray<T> CreateNativeArray<T>(T[] data)
where T : struct;
NativeArray<U> Convert<T, U>(NativeArray<T> src, Func<T, U> convert)
where T : struct
where U : struct;
}
/// <summary>
/// 特定のコンテキスト(GltfDataなど)に関連する、NativeArrayの作成を代行し、
/// まとめてDisposeできるようにする。
@@ -15,7 +34,7 @@ namespace UniGLTF
/// また、Sparse や base64 encoding など単純なバイト列のスライスで済まない場合も同様である。
///
/// </summary>
public class NativeArrayManager : IDisposable
public class NativeArrayManager : INativeArrayManager, IDisposable
{
List<IDisposable> m_disposables = new List<IDisposable>();
@@ -28,6 +47,10 @@ namespace UniGLTF
m_disposables.Clear();
}
public NativeArrayManager()
{
}
/// <summary>
/// NativeArrayを新規作成し、Dispose管理する。

View File

@@ -1,492 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace UniGLTF
{
static class BitWriter
{
public static void Write(byte[] bytes, int i, Int32 value)
{
var tmp = BitConverter.GetBytes(value);
bytes[i++] = tmp[0];
bytes[i++] = tmp[1];
bytes[i++] = tmp[2];
bytes[i++] = tmp[3];
}
#region UINT
public static void Write(byte[] bytes, int i, Byte value)
{
bytes[i++] = value;
}
public static void Write(byte[] bytes, int i, UInt16 value)
{
var tmp = BitConverter.GetBytes(value);
bytes[i++] = tmp[0];
bytes[i++] = tmp[1];
}
public static void Write(byte[] bytes, int i, UInt32 value)
{
var tmp = BitConverter.GetBytes(value);
bytes[i++] = tmp[0];
bytes[i++] = tmp[1];
bytes[i++] = tmp[2];
bytes[i++] = tmp[3];
}
#endregion
public static void Write(byte[] bytes, int i, Single value)
{
var tmp = BitConverter.GetBytes(value);
bytes[i++] = tmp[0];
bytes[i++] = tmp[1];
bytes[i++] = tmp[2];
bytes[i++] = tmp[3];
}
public static void Write(byte[] bytes, int i, System.Numerics.Vector2 value)
{
Write(bytes, i, value.X);
Write(bytes, i + 4, value.Y);
}
public static void Write(byte[] bytes, int i, System.Numerics.Vector3 value)
{
Write(bytes, i, value.X);
Write(bytes, i + 4, value.Y);
Write(bytes, i + 8, value.Z);
}
public static void Write(byte[] bytes, int i, System.Numerics.Vector4 value)
{
Write(bytes, i, value.X);
Write(bytes, i + 4, value.Y);
Write(bytes, i + 8, value.Z);
Write(bytes, i + 12, value.W);
}
public static void Write(byte[] bytes, int i, System.Numerics.Quaternion value)
{
Write(bytes, i, value.X);
Write(bytes, i + 4, value.Y);
Write(bytes, i + 8, value.Z);
Write(bytes, i + 12, value.W);
}
public static void Write(byte[] bytes, int i, System.Numerics.Matrix4x4 value)
{
Write(bytes, i, value.M11);
Write(bytes, i + 4, value.M12);
Write(bytes, i + 8, value.M13);
Write(bytes, i + 12, value.M14);
Write(bytes, i + 16, value.M21);
Write(bytes, i + 20, value.M22);
Write(bytes, i + 24, value.M23);
Write(bytes, i + 28, value.M24);
Write(bytes, i + 32, value.M31);
Write(bytes, i + 36, value.M32);
Write(bytes, i + 40, value.M33);
Write(bytes, i + 44, value.M34);
Write(bytes, i + 48, value.M41);
Write(bytes, i + 52, value.M42);
Write(bytes, i + 56, value.M43);
Write(bytes, i + 60, value.M44);
}
public static void Write(byte[] bytes, int i, UShort4 value)
{
Write(bytes, i, value.x);
Write(bytes, i + 2, value.y);
Write(bytes, i + 4, value.z);
Write(bytes, i + 6, value.w);
}
public static void Write(byte[] bytes, int i, SkinJoints value)
{
Write(bytes, i, value.Joint0);
Write(bytes, i + 2, value.Joint1);
Write(bytes, i + 4, value.Joint2);
Write(bytes, i + 6, value.Joint3);
}
public static void Write(byte[] bytes, int i, Byte4 value)
{
bytes[i++] = value.x;
bytes[i++] = value.y;
bytes[i++] = value.z;
bytes[i++] = value.w;
}
public static void Write(byte[] bytes, int i, UnityEngine.Vector2 value)
{
Write(bytes, i, value.x);
Write(bytes, i + 4, value.y);
}
public static void Write(byte[] bytes, int i, UnityEngine.Vector3 value)
{
Write(bytes, i, value.x);
Write(bytes, i + 4, value.y);
Write(bytes, i + 8, value.z);
}
public static void Write(byte[] bytes, int i, UnityEngine.Vector4 value)
{
Write(bytes, i, value.x);
Write(bytes, i + 4, value.y);
Write(bytes, i + 8, value.z);
Write(bytes, i + 12, value.w);
}
public static void Write(byte[] bytes, int i, UnityEngine.Color value)
{
Write(bytes, i, value.r);
Write(bytes, i + 4, value.g);
Write(bytes, i + 8, value.b);
Write(bytes, i + 12, value.a);
}
public static void Write(byte[] bytes, int i, UnityEngine.Matrix4x4 value)
{
Write(bytes, i, value.m00);
Write(bytes, i + 4, value.m01);
Write(bytes, i + 8, value.m02);
Write(bytes, i + 12, value.m03);
Write(bytes, i + 16, value.m10);
Write(bytes, i + 20, value.m11);
Write(bytes, i + 24, value.m12);
Write(bytes, i + 28, value.m13);
Write(bytes, i + 32, value.m20);
Write(bytes, i + 36, value.m21);
Write(bytes, i + 40, value.m22);
Write(bytes, i + 44, value.m23);
Write(bytes, i + 48, value.m30);
Write(bytes, i + 52, value.m31);
Write(bytes, i + 56, value.m32);
Write(bytes, i + 60, value.m33);
}
}
public static class KeyValuePariExtensions
{
public static void Deconstruct<T, U>(this KeyValuePair<T, U> pair, out T key, out U value)
{
key = pair.Key;
value = pair.Value;
}
}
public struct SpanLike<T> : IEquatable<SpanLike<T>>, IEnumerable<T>
where T : struct
{
public readonly ArraySegment<byte> Bytes;
readonly int m_itemSize;
public readonly int Length;
public delegate T Getter(byte[] bytes, int start);
readonly Getter m_getter;
public delegate void Setter(byte[] bytes, int i, T value);
readonly Setter m_setter;
public T this[int i]
{
set
{
m_setter(Bytes.Array, Bytes.Offset + i * m_itemSize, value);
}
get
{
return m_getter(Bytes.Array, Bytes.Offset + i * m_itemSize);
}
}
public SpanLike(ArraySegment<byte> bytes, int itemSize, Getter getter, Setter setter)
{
Bytes = bytes;
m_itemSize = itemSize;
Length = Bytes.Count / m_itemSize;
m_getter = getter;
m_setter = setter;
}
public SpanLike<T> Slice(int offset, int count)
{
var bytesOffset = offset * m_itemSize;
var bytesLength = count * m_itemSize;
if (bytesOffset + bytesLength > Bytes.Count)
{
throw new ArgumentOutOfRangeException();
}
return new SpanLike<T>(new ArraySegment<byte>(
Bytes.Array,
Bytes.Offset + bytesOffset,
bytesLength
), m_itemSize, m_getter, m_setter);
}
public SpanLike<T> Slice(int offset)
{
var bytesOffset = offset * m_itemSize;
if (bytesOffset > Bytes.Count)
{
throw new ArgumentOutOfRangeException();
}
var bytesLength = Bytes.Count - bytesOffset;
return new SpanLike<T>(new ArraySegment<byte>(
Bytes.Array,
Bytes.Offset + bytesOffset,
bytesLength
), m_itemSize, m_getter, m_setter);
}
public T[] ToArray()
{
var array = new T[Length];
Bytes.FromBytes(array);
return array;
}
public bool Equals(SpanLike<T> other)
{
if (Length != other.Length)
{
return false;
}
var end = Length;
for (int i = 0; i < end; ++i)
{
if (!this[i].Equals(other[i]))
{
return false;
}
}
return true;
}
public IEnumerator<T> GetEnumerator()
{
for (int i = 0; i < Length; ++i)
{
yield return this[i];
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return (IEnumerator)GetEnumerator();
}
}
public static class SpanLike
{
struct GetSet<T> where T : struct
{
public SpanLike<T>.Getter Getter;
public SpanLike<T>.Setter Setter;
}
public static readonly Dictionary<Type, object> Map = new Dictionary<Type, object>()
{
{typeof(Byte), new GetSet<byte>{
Getter = (array, start) => array[start],
Setter = BitWriter.Write}},
{typeof(UInt16), new GetSet<UInt16>{
Getter = BitConverter.ToUInt16,
Setter = BitWriter.Write}},
{typeof(UInt32), new GetSet<UInt32>{
Getter = BitConverter.ToUInt32,
Setter = BitWriter.Write}},
{typeof(Int32), new GetSet<Int32>{
Getter = BitConverter.ToInt32,
Setter = BitWriter.Write}},
{typeof(Single), new GetSet<Single>{
Getter = BitConverter.ToSingle,
Setter = BitWriter.Write}},
{typeof(System.Numerics.Vector2), new GetSet<System.Numerics.Vector2>{
Getter = (array, start) =>
new System.Numerics.Vector2(
BitConverter.ToSingle(array, start),
BitConverter.ToSingle(array, start + 4)
),
Setter = BitWriter.Write
}},
{typeof(System.Numerics.Vector3), new GetSet<System.Numerics.Vector3>{
Getter = (array, start) =>
new System.Numerics.Vector3(
BitConverter.ToSingle(array, start),
BitConverter.ToSingle(array, start + 4),
BitConverter.ToSingle(array, start + 8)
),
Setter = BitWriter.Write
}},
{typeof(System.Numerics.Vector4), new GetSet<System.Numerics.Vector4>{
Getter = (array, start) =>
new System.Numerics.Vector4(
BitConverter.ToSingle(array, start),
BitConverter.ToSingle(array, start + 4),
BitConverter.ToSingle(array, start + 8),
BitConverter.ToSingle(array, start + 12)
),
Setter = BitWriter.Write
}},
{typeof(System.Numerics.Quaternion), new GetSet<System.Numerics.Quaternion>{
Getter = (array, start) =>
new System.Numerics.Quaternion(
BitConverter.ToSingle(array, start),
BitConverter.ToSingle(array, start + 4),
BitConverter.ToSingle(array, start + 8),
BitConverter.ToSingle(array, start + 12)
),
Setter = BitWriter.Write
}},
{typeof(System.Numerics.Matrix4x4), new GetSet<System.Numerics.Matrix4x4>{
Getter = (array, start) =>
new System.Numerics.Matrix4x4(
BitConverter.ToSingle(array, start),
BitConverter.ToSingle(array, start + 4),
BitConverter.ToSingle(array, start + 8),
BitConverter.ToSingle(array, start + 12),
BitConverter.ToSingle(array, start + 16),
BitConverter.ToSingle(array, start + 20),
BitConverter.ToSingle(array, start + 24),
BitConverter.ToSingle(array, start + 28),
BitConverter.ToSingle(array, start + 32),
BitConverter.ToSingle(array, start + 36),
BitConverter.ToSingle(array, start + 40),
BitConverter.ToSingle(array, start + 44),
BitConverter.ToSingle(array, start + 48),
BitConverter.ToSingle(array, start + 52),
BitConverter.ToSingle(array, start + 56),
BitConverter.ToSingle(array, start + 60)
),
Setter = BitWriter.Write
}},
{typeof(Byte4), new GetSet<Byte4>{
Getter = (array, start) =>
new Byte4(
array[start],
array[start + 1],
array[start + 2],
array[start + 3]
),
Setter = BitWriter.Write
}},
{typeof(UShort4), new GetSet<UShort4>{
Getter = (array, start) =>
new UShort4(
BitConverter.ToUInt16(array, start),
BitConverter.ToUInt16(array, start + 2),
BitConverter.ToUInt16(array, start + 4),
BitConverter.ToUInt16(array, start + 6)
),
Setter = BitWriter.Write
}},
{typeof(SkinJoints), new GetSet<SkinJoints>{
Getter = (array, start) =>
new SkinJoints
{
Joint0 = BitConverter.ToUInt16(array, start),
Joint1 = BitConverter.ToUInt16(array, start + 2),
Joint2 = BitConverter.ToUInt16(array, start + 4),
Joint3 = BitConverter.ToUInt16(array, start + 6),
},
Setter = BitWriter.Write
}},
{typeof(UnityEngine.Vector2), new GetSet<UnityEngine.Vector2>{
Getter = (array, start) =>
new UnityEngine.Vector2(
BitConverter.ToSingle(array, start),
BitConverter.ToSingle(array, start + 4)
),
Setter = BitWriter.Write
}},
{typeof(UnityEngine.Vector3), new GetSet<UnityEngine.Vector3>{
Getter = (array, start) =>
new UnityEngine.Vector3(
BitConverter.ToSingle(array, start),
BitConverter.ToSingle(array, start + 4),
BitConverter.ToSingle(array, start + 8)
),
Setter = BitWriter.Write
}},
{typeof(UnityEngine.Vector4), new GetSet<UnityEngine.Vector4>{
Getter = (array, start) =>
new UnityEngine.Vector4(
BitConverter.ToSingle(array, start),
BitConverter.ToSingle(array, start + 4),
BitConverter.ToSingle(array, start + 8),
BitConverter.ToSingle(array, start + 12)
),
Setter = BitWriter.Write
}},
{typeof(UnityEngine.Color), new GetSet<UnityEngine.Color>{
Getter = (array, start) =>
new UnityEngine.Color(
BitConverter.ToSingle(array, start),
BitConverter.ToSingle(array, start + 4),
BitConverter.ToSingle(array, start + 8),
BitConverter.ToSingle(array, start + 12)
),
Setter = BitWriter.Write
}},
{typeof(UnityEngine.Matrix4x4), new GetSet<UnityEngine.Matrix4x4>{
Getter = (array, start) =>
// UnityEngine.Matrix4x4
// * 列優先メモリレイアウト(col0, col1, col2, col3)
// * Constructor 引き数が行優先 new Matrix4x4(row0, row1, row2, row3);
new UnityEngine.Matrix4x4(
new UnityEngine.Vector4(BitConverter.ToSingle(array, start),
BitConverter.ToSingle(array, start + 16),
BitConverter.ToSingle(array, start + 32),
BitConverter.ToSingle(array, start + 48)),
new UnityEngine.Vector4(BitConverter.ToSingle(array, start+4),
BitConverter.ToSingle(array, start + 16+4),
BitConverter.ToSingle(array, start + 32+4),
BitConverter.ToSingle(array, start + 48+4)),
new UnityEngine.Vector4(BitConverter.ToSingle(array, start+8),
BitConverter.ToSingle(array, start + 16+8),
BitConverter.ToSingle(array, start + 32+8),
BitConverter.ToSingle(array, start + 48+8)),
new UnityEngine.Vector4(BitConverter.ToSingle(array, start+12),
BitConverter.ToSingle(array, start + 16+12),
BitConverter.ToSingle(array, start + 32+12),
BitConverter.ToSingle(array, start + 48+12))
),
Setter = BitWriter.Write
}},
};
public static SpanLike<T> Wrap<T>(ArraySegment<byte> bytes) where T : struct
{
if (!Map.TryGetValue(typeof(T), out object value))
{
throw new KeyNotFoundException($"{typeof(T)}");
}
var getset = (GetSet<T>)value;
return new SpanLike<T>(bytes, Marshal.SizeOf<T>(), getset.Getter, getset.Setter);
}
public static SpanLike<T> Create<T>(int itemCount) where T : struct
{
var itemSize = Marshal.SizeOf<T>();
var array = new byte[itemCount * itemSize];
return Wrap<T>(new ArraySegment<byte>(array));
}
public static SpanLike<T> CopyFrom<T>(T[] src) where T : struct
{
var buffer = new byte[src.Length * Marshal.SizeOf<T>()];
src.ToBytes(new ArraySegment<byte>(buffer));
return Wrap<T>(new ArraySegment<byte>(buffer));
}
}
}

View File

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

View File

@@ -30,8 +30,8 @@ namespace UniGLTF
var viewIndex = data.ExtendBufferAndGetViewIndex(bytesWithMime.bytes);
// add image
var imageIndex = data.GLTF.images.Count;
data.GLTF.images.Add(new glTFImage
var imageIndex = data.Gltf.images.Count;
data.Gltf.images.Add(new glTFImage
{
name = TextureImportName.RemoveSuffix(texture.name),
bufferView = viewIndex,
@@ -39,13 +39,13 @@ namespace UniGLTF
});
// add sampler
var samplerIndex = data.GLTF.samplers.Count;
var samplerIndex = data.Gltf.samplers.Count;
var sampler = TextureSamplerUtil.Export(texture);
data.GLTF.samplers.Add(sampler);
data.Gltf.samplers.Add(sampler);
// add texture
var textureIndex = data.GLTF.textures.Count;
data.GLTF.textures.Add(new glTFTexture
var textureIndex = data.Gltf.textures.Count;
data.Gltf.textures.Add(new glTFTexture
{
sampler = samplerIndex,
source = imageIndex,

View File

@@ -12,7 +12,7 @@ namespace UniGLTF
{
protected ExportingGltfData _data;
protected glTF _gltf => _data.GLTF;
protected glTF _gltf => _data.Gltf;
public GameObject Copy
{

View File

@@ -134,7 +134,7 @@ namespace UniGLTF
exporter.Prepare(root);
exporter.Export(new EditorTextureSerializer());
}
var gltf = data.GLTF;
var gltf = data.Gltf;
Assert.AreEqual(1, gltf.images.Count);
var exportedImage = gltf.images[0];
Assert.AreEqual("image/png", exportedImage.mimeType);

View File

@@ -11,7 +11,7 @@ namespace UniGLTF
public void TextureNameUniqueness()
{
var data = new ExportingGltfData();
var gltf = data.GLTF;
var gltf = data.Gltf;
gltf.asset.version = "2.0";
gltf.textures.Add(new glTFTexture
{

View File

@@ -139,7 +139,7 @@ namespace UniGLTF
: MeshExporter_SharedVertexBuffer.Export(data, unityMesh, Materials, axisInverter, meshExportSettings)
;
using (var parsed = GltfData.CreateFromGltfDataForTest(data.GLTF, data.BinBytes))
using (var parsed = GltfData.CreateFromGltfDataForTest(data.Gltf, data.BinBytes))
{
{
@@ -190,7 +190,7 @@ namespace UniGLTF
: MeshExporter_SharedVertexBuffer.Export(data, unityMesh, Materials, axisInverter, meshExportSettings)
;
using (var parsed = GltfData.CreateFromGltfDataForTest(data.GLTF, data.BinBytes))
using (var parsed = GltfData.CreateFromGltfDataForTest(data.Gltf, data.BinBytes))
{
{
var indices = parsed.GetIndices(gltfMesh.primitives[0].indices);

View File

@@ -19,27 +19,6 @@ namespace UniGLTF
Assert.AreEqual(orgAngle, angle);
}
[Test]
[Category("Numerics")]
public void Vector4Test()
{
var bytes = new byte[4 * 4];
{
var span = SpanLike.Wrap<Single>(new ArraySegment<byte>(bytes));
span[0] = 1.0f;
}
{
var span = SpanLike.Wrap<Vector4>(new ArraySegment<byte>(bytes));
Assert.AreEqual(1.0f, span[0].X);
}
{
var span = SpanLike.Wrap<Quaternion>(new ArraySegment<byte>(bytes));
Assert.AreEqual(1.0f, span[0].X);
}
}
[Test]
[Category("Numerics")]
public void Vector3Test()

View File

@@ -1,41 +0,0 @@
using System;
using NUnit.Framework;
namespace UniGLTF
{
public class SpanLikeTests
{
[Test]
[Category("SpanLike")]
public void CopyTest()
{
var src = new int[] { 255 };
var dst = new byte[4];
src.ToBytes(new ArraySegment<byte>(dst));
Assert.AreEqual(0xFF, dst[0]);
Assert.AreEqual(0, dst[1]);
Assert.AreEqual(0, dst[2]);
Assert.AreEqual(0, dst[3]);
}
[Test]
[Category("SpanLike")]
public void SpanLikeTest()
{
var v0 = new UnityEngine.Vector3(1, 2, 3);
var v1 = new UnityEngine.Vector3(4, 5, 6);
var positions = new UnityEngine.Vector3[]
{
v0,
v1,
};
var span = SpanLike.CopyFrom(positions);
Assert.AreEqual(2, span.Length);
Assert.AreEqual(v0, span[0]);
Assert.AreEqual(v1, span[1]);
}
}
}

View File

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

View File

@@ -109,9 +109,9 @@ namespace UniGLTF
exporter.Export(new EditorTextureSerializer());
// remove empty buffer
data.GLTF.buffers.Clear();
data.Gltf.buffers.Clear();
json = data.GLTF.ToJson();
json = data.Gltf.ToJson();
}
// parse
@@ -141,7 +141,7 @@ namespace UniGLTF
data.ExtendBufferAndGetView(bytes, glBufferTarget.NONE);
}
Assert.AreEqual(values.Count, data.GLTF.buffers[0].byteLength);
Assert.AreEqual(values.Count, data.Gltf.buffers[0].byteLength);
Assert.True(Enumerable.SequenceEqual(values, data.BinBytes.ToArray()));
}
@@ -299,7 +299,7 @@ namespace UniGLTF
exporter.Export(new EditorTextureSerializer());
}
var expected = data.GLTF.ToJson().ParseAsJson();
var expected = data.Gltf.ToJson().ParseAsJson();
expected.AddKey(Utf8String.From("meshes"));
expected.AddValue(default(ArraySegment<byte>), ValueNodeType.Array);
expected["meshes"].AddValue(default(ArraySegment<byte>), ValueNodeType.Object);
@@ -333,7 +333,7 @@ namespace UniGLTF
primitive["targets"][1].AddKey(Utf8String.From("TANGENT"));
primitive["targets"][1].AddValue(Utf8String.From("0").Bytes, ValueNodeType.Integer);
data.GLTF.meshes.Add(new glTFMesh("test")
data.Gltf.meshes.Add(new glTFMesh("test")
{
primitives = new List<glTFPrimitives>
{
@@ -361,7 +361,7 @@ namespace UniGLTF
}
}
});
var actual = data.GLTF.ToJson().ParseAsJson();
var actual = data.Gltf.ToJson().ParseAsJson();
Assert.AreEqual(expected, actual);
}
@@ -528,7 +528,7 @@ namespace UniGLTF
// export
var data = new ExportingGltfData();
var gltf = data.GLTF;
var gltf = data.Gltf;
var json = default(string);
using (var exporter = new gltfExporter(data, new GltfExportSettings()))
{
@@ -606,7 +606,7 @@ namespace UniGLTF
// export
var data = new ExportingGltfData();
var gltf = data.GLTF;
var gltf = data.Gltf;
string json;
using (var exporter = new gltfExporter(data, new GltfExportSettings()))
{
@@ -669,7 +669,7 @@ namespace UniGLTF
// export
var data = new ExportingGltfData();
var gltf = data.GLTF;
var gltf = data.Gltf;
string json;
using (var exporter = new gltfExporter(data, new GltfExportSettings()))
{

View File

@@ -169,7 +169,7 @@ namespace VRM.Samples
// TODO: Check contents in JSON
/*var exportJson = */
JsonParser.Parse(vrm.GLTF.ToJson());
JsonParser.Parse(vrm.Gltf.ToJson());
// TODO: Check contents in JSON
/*var newExportedJson = */

View File

@@ -266,29 +266,32 @@ namespace UniVRM10
try
{
var converter = new UniVRM10.ModelExporter();
var model = converter.Export(root);
// 右手系に変換
m_logLabel += $"convert to right handed coordinate...\n";
model.ConvertCoordinate(VrmLib.Coordinates.Vrm1, ignoreVrm: false);
// export vrm-1.0
var exporter = new UniVRM10.Vrm10Exporter(new EditorTextureSerializer(), new GltfExportSettings());
var option = new VrmLib.ExportArgs();
exporter.Export(root, model, converter, option, Vrm ? Vrm.Meta : m_tmpObject.Meta);
var exportedBytes = exporter.Storage.ToBytes();
m_logLabel += $"write to {path}...\n";
File.WriteAllBytes(path, exportedBytes);
Debug.Log("exportedBytes: " + exportedBytes.Length);
var assetPath = UniGLTF.UnityPath.FromFullpath(path);
if (assetPath.IsUnderAssetsFolder)
using (var arrayManager = new NativeArrayManager())
{
// asset folder 内。import を発動
assetPath.ImportAsset();
var converter = new UniVRM10.ModelExporter();
var model = converter.Export(arrayManager, root);
// 右手系に変換
m_logLabel += $"convert to right handed coordinate...\n";
model.ConvertCoordinate(VrmLib.Coordinates.Vrm1, ignoreVrm: false);
// export vrm-1.0
var exporter = new UniVRM10.Vrm10Exporter(new EditorTextureSerializer(), new GltfExportSettings());
var option = new VrmLib.ExportArgs();
exporter.Export(root, model, converter, option, Vrm ? Vrm.Meta : m_tmpObject.Meta);
var exportedBytes = exporter.Storage.ToGlbBytes();
m_logLabel += $"write to {path}...\n";
File.WriteAllBytes(path, exportedBytes);
Debug.Log("exportedBytes: " + exportedBytes.Length);
var assetPath = UniGLTF.UnityPath.FromFullpath(path);
if (assetPath.IsUnderAssetsFolder)
{
// asset folder 内。import を発動
assetPath.ImportAsset();
}
}
}
catch (Exception ex)

View File

@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Numerics;
using UniGLTF;
using Unity.Collections;
namespace UniVRM10
{
@@ -30,7 +31,7 @@ namespace UniVRM10
}
public static int AddViewTo(this VrmLib.BufferAccessor self,
Vrm10ExportData storage, int bufferIndex,
ExportingGltfData data, int bufferIndex,
int offset = 0, int count = 0)
{
var stride = self.Stride;
@@ -38,8 +39,8 @@ namespace UniVRM10
{
count = self.Count;
}
var slice = self.Bytes.Slice(offset * stride, count * stride);
return storage.AppendToBuffer(slice);
var slice = self.Bytes.GetSubArray(offset * stride, count * stride);
return data.AppendToBuffer(slice);
}
static glTFAccessor CreateGltfAccessor(this VrmLib.BufferAccessor self,
@@ -60,11 +61,11 @@ namespace UniVRM10
}
public static int AddAccessorTo(this VrmLib.BufferAccessor self,
Vrm10ExportData storage, int viewIndex,
Action<ArraySegment<byte>, glTFAccessor> minMax = null,
ExportingGltfData data, int viewIndex,
Action<NativeArray<byte>, glTFAccessor> minMax = null,
int offset = 0, int count = 0)
{
var gltf = storage.GLTF;
var gltf = data.Gltf;
var accessorIndex = gltf.accessors.Count;
var accessor = self.CreateGltfAccessor(viewIndex, count, offset * self.Stride);
if (minMax != null)
@@ -76,10 +77,10 @@ namespace UniVRM10
}
public static int AddAccessorTo(this VrmLib.BufferAccessor self,
Vrm10ExportData storage, int bufferIndex,
ExportingGltfData data, int bufferIndex,
// GltfBufferTargetType targetType,
bool useSparse,
Action<ArraySegment<byte>, glTFAccessor> minMax = null,
Action<NativeArray<byte>, glTFAccessor> minMax = null,
int offset = 0, int count = 0)
{
if (self.ComponentType == VrmLib.AccessorValueType.FLOAT
@@ -104,53 +105,55 @@ namespace UniVRM10
&& sparseValuesWithIndex.Count * 16 < values.Length * 12)
{
// use sparse
var sparseIndexBin = new ArraySegment<byte>(new byte[sparseValuesWithIndex.Count * 4]);
var sparseIndexSpan = SpanLike.Wrap<Int32>(sparseIndexBin);
var sparseValueBin = new ArraySegment<byte>(new byte[sparseValuesWithIndex.Count * 12]);
var sparseValueSpan = SpanLike.Wrap<Vector3>(sparseValueBin);
for (int i = 0; i < sparseValuesWithIndex.Count; ++i)
using (var sparseIndexBin = new NativeArray<byte>(sparseValuesWithIndex.Count * 4, Allocator.Persistent))
using (var sparseValueBin = new NativeArray<byte>(sparseValuesWithIndex.Count * 12, Allocator.Persistent))
{
var (index, value) = sparseValuesWithIndex[i];
sparseIndexSpan[i] = index;
sparseValueSpan[i] = value;
}
var sparseIndexSpan = sparseIndexBin.Reinterpret<Int32>(1);
var sparseValueSpan = sparseValueBin.Reinterpret<Vector3>(1);
var sparseIndexView = storage.AppendToBuffer(sparseIndexBin);
var sparseValueView = storage.AppendToBuffer(sparseValueBin);
var accessorIndex = storage.GLTF.accessors.Count;
var accessor = new glTFAccessor
{
componentType = (glComponentType)self.ComponentType,
type = self.AccessorType.ToString(),
count = self.Count,
byteOffset = -1,
sparse = new glTFSparse
for (int i = 0; i < sparseValuesWithIndex.Count; ++i)
{
count = sparseValuesWithIndex.Count,
indices = new glTFSparseIndices
{
componentType = (glComponentType)VrmLib.AccessorValueType.UNSIGNED_INT,
bufferView = sparseIndexView,
},
values = new glTFSparseValues
{
bufferView = sparseValueView,
},
var (index, value) = sparseValuesWithIndex[i];
sparseIndexSpan[i] = index;
sparseValueSpan[i] = value;
}
};
if (minMax != null)
{
minMax(sparseValueBin, accessor);
var sparseIndexView = data.AppendToBuffer(sparseIndexBin);
var sparseValueView = data.AppendToBuffer(sparseValueBin);
var accessorIndex = data.Gltf.accessors.Count;
var accessor = new glTFAccessor
{
componentType = (glComponentType)self.ComponentType,
type = self.AccessorType.ToString(),
count = self.Count,
byteOffset = -1,
sparse = new glTFSparse
{
count = sparseValuesWithIndex.Count,
indices = new glTFSparseIndices
{
componentType = (glComponentType)VrmLib.AccessorValueType.UNSIGNED_INT,
bufferView = sparseIndexView,
},
values = new glTFSparseValues
{
bufferView = sparseValueView,
},
}
};
if (minMax != null)
{
minMax(sparseValueBin, accessor);
}
data.Gltf.accessors.Add(accessor);
return accessorIndex;
}
storage.GLTF.accessors.Add(accessor);
return accessorIndex;
}
}
var viewIndex = self.AddViewTo(storage, bufferIndex, offset, count);
return self.AddAccessorTo(storage, viewIndex, minMax, 0, count);
var viewIndex = self.AddViewTo(data, bufferIndex, offset, count);
return self.AddAccessorTo(data, viewIndex, minMax, 0, count);
}
}
}

View File

@@ -23,12 +23,12 @@ namespace UniVRM10
Profiler.BeginSample("MeshImporter.LoadSharedMesh");
var mesh = new Mesh();
var positions = src.VertexBuffer.Positions.AsNativeArray<Vector3>(Allocator.TempJob);
var normals = src.VertexBuffer.Normals?.AsNativeArray<Vector3>(Allocator.TempJob) ?? default;
var texCoords = src.VertexBuffer.TexCoords?.AsNativeArray<Vector2>(Allocator.TempJob) ?? default;
var colors = src.VertexBuffer.Colors?.AsNativeArray<Color>(Allocator.TempJob) ?? default;
var weights = src.VertexBuffer.Weights?.AsNativeArray<Vector4>(Allocator.TempJob) ?? default;
var joints = src.VertexBuffer.Joints?.AsNativeArray<SkinJoints>(Allocator.TempJob) ?? default;
var positions = src.VertexBuffer.Positions.Bytes.Reinterpret<Vector3>(1);
var normals = src.VertexBuffer.Normals?.Bytes.Reinterpret<Vector3>(1) ?? default;
var texCoords = src.VertexBuffer.TexCoords?.Bytes.Reinterpret<Vector2>(1) ?? default;
var colors = src.VertexBuffer.Colors?.Bytes.Reinterpret<Color>(1) ?? default;
var weights = src.VertexBuffer.Weights?.Bytes.Reinterpret<Vector4>(1) ?? default;
var joints = src.VertexBuffer.Joints?.Bytes.Reinterpret<SkinJoints>(1) ?? default;
using (var vertices = new NativeArray<MeshVertex>(positions.Length, Allocator.TempJob))
{
@@ -55,14 +55,6 @@ namespace UniVRM10
// Jobを完了
jobHandle.Complete();
// 入力のNativeArrayを開放
positions.Dispose();
if (normals.IsCreated) normals.Dispose();
if (texCoords.IsCreated) texCoords.Dispose();
if (colors.IsCreated) colors.Dispose();
if (weights.IsCreated) weights.Dispose();
if (joints.IsCreated) joints.Dispose();
// 頂点を更新
MeshVertex.SetVertexBufferParamsToMesh(mesh, vertices.Length);
mesh.SetVertexBufferData(vertices, 0, 0, vertices.Length);
@@ -74,16 +66,14 @@ namespace UniVRM10
switch (src.IndexBuffer.ComponentType)
{
case AccessorValueType.UNSIGNED_SHORT:
var shortIndices = src.IndexBuffer.AsNativeArray<ushort>(Allocator.Temp);
var shortIndices = src.IndexBuffer.Bytes.Reinterpret<ushort>(1);
mesh.SetIndexBufferParams(shortIndices.Length, IndexFormat.UInt16);
mesh.SetIndexBufferData(shortIndices, 0, 0, shortIndices.Length);
shortIndices.Dispose();
break;
case AccessorValueType.UNSIGNED_INT:
var intIndices = src.IndexBuffer.AsNativeArray<uint>(Allocator.Temp);
var intIndices = src.IndexBuffer.Bytes.Reinterpret<uint>(1);
mesh.SetIndexBufferParams(intIndices.Length, IndexFormat.UInt32);
mesh.SetIndexBufferData(intIndices, 0, 0, intIndices.Length);
intIndices.Dispose();
break;
default:
throw new NotImplementedException();

View File

@@ -126,8 +126,7 @@ namespace UniVRM10
case AccessorValueType.SHORT:
{
// unsigned short -> unsigned short
var source = mesh.IndexBuffer.AsNativeArray<ushort>(Allocator.TempJob);
disposables.Add(source);
var source = mesh.IndexBuffer.Bytes.Reinterpret<ushort>(1);
jobHandle = new CopyIndicesJobs.Ushort2Ushort(
(ushort)vertexOffset,
new NativeSlice<ushort>(source),
@@ -138,8 +137,7 @@ namespace UniVRM10
case AccessorValueType.UNSIGNED_INT:
{
// unsigned int -> unsigned short
var source = mesh.IndexBuffer.AsNativeArray<uint>(Allocator.TempJob);
disposables.Add(source);
var source = mesh.IndexBuffer.Bytes.Reinterpret<uint>(1);
jobHandle = new CopyIndicesJobs.Uint2Ushort(
(ushort)vertexOffset,
source,
@@ -173,8 +171,7 @@ namespace UniVRM10
case AccessorValueType.SHORT:
{
// unsigned short -> unsigned int
var source = mesh.IndexBuffer.AsNativeArray<ushort>(Allocator.TempJob);
disposables.Add(source);
var source = mesh.IndexBuffer.Bytes.Reinterpret<ushort>(1);
jobHandle = new CopyIndicesJobs.Ushort2Uint(
(uint)vertexOffset,
source,
@@ -185,8 +182,7 @@ namespace UniVRM10
case AccessorValueType.UNSIGNED_INT:
{
// unsigned int -> unsigned int
var source = mesh.IndexBuffer.AsNativeArray<uint>(Allocator.TempJob);
disposables.Add(source);
var source = mesh.IndexBuffer.Bytes.Reinterpret<uint>(1);
jobHandle = new CopyIndicesJobs.UInt2UInt(
(uint)vertexOffset,
source,
@@ -237,20 +233,15 @@ namespace UniVRM10
foreach (var mesh in meshGroup.Meshes)
{
var positions = mesh.VertexBuffer.Positions.AsNativeArray<Vector3>(Allocator.TempJob);
var normals = mesh.VertexBuffer.Normals.AsNativeArray<Vector3>(Allocator.TempJob);
var texCoords = mesh.VertexBuffer.TexCoords.AsNativeArray<Vector2>(Allocator.TempJob);
var positions = mesh.VertexBuffer.Positions.Bytes.Reinterpret<Vector3>(1);
var normals = mesh.VertexBuffer.Normals.Bytes.Reinterpret<Vector3>(1);
var texCoords = mesh.VertexBuffer.TexCoords.Bytes.Reinterpret<Vector2>(1);
var weights = meshGroup.Skin != null
? mesh.VertexBuffer.Weights.AsNativeArray<Vector4>(Allocator.TempJob)
? mesh.VertexBuffer.Weights.Bytes.Reinterpret<Vector4>(1)
: default;
var joints = meshGroup.Skin != null
? mesh.VertexBuffer.Joints.AsNativeArray<SkinJoints>(Allocator.TempJob)
? mesh.VertexBuffer.Joints.Bytes.Reinterpret<SkinJoints>(1)
: default;
if (positions.IsCreated) disposables.Add(positions);
if (normals.IsCreated) disposables.Add(normals);
if (texCoords.IsCreated) disposables.Add(texCoords);
if (weights.IsCreated) disposables.Add(weights);
if (joints.IsCreated) disposables.Add(joints);
interleaveVertexJob = new InterleaveMeshVerticesJob(
new NativeSlice<MeshVertex>(vertices, indexOffset, mesh.VertexBuffer.Count),

View File

@@ -1,8 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using UniGLTF;
using Unity.Collections;
using VrmLib;
namespace UniVRM10
@@ -12,48 +12,6 @@ namespace UniVRM10
/// </summary>
public static class MeshWriter
{
static void Vec3MinMax(ArraySegment<byte> bytes, glTFAccessor accessor)
{
var positions = SpanLike.Wrap<Vector3>(bytes);
var min = new Vector3(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity);
var max = new Vector3(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity);
foreach (var p in positions)
{
min = Vector3.Min(min, p);
max = Vector3.Max(max, p);
}
accessor.min = min.ToFloat3();
accessor.max = max.ToFloat3();
}
static int ExportIndices(Vrm10ExportData storage, BufferAccessor x, int offset, int count, ExportArgs option)
{
if (x.Count <= ushort.MaxValue)
{
if (x.ComponentType == AccessorValueType.UNSIGNED_INT)
{
// ensure ushort
var src = x.GetSpan<UInt32>().Slice(offset, count);
var bytes = new byte[src.Length * 2];
var dst = SpanLike.Wrap<UInt16>(new ArraySegment<byte>(bytes));
for (int i = 0; i < src.Length; ++i)
{
dst[i] = (ushort)src[i];
}
var accessor = new BufferAccessor(new ArraySegment<byte>(bytes), AccessorValueType.UNSIGNED_SHORT, AccessorVectorType.SCALAR, count);
return accessor.AddAccessorTo(storage, 0, option.sparse, null, 0, count);
}
else
{
return x.AddAccessorTo(storage, 0, option.sparse, null, offset, count);
}
}
else
{
return x.AddAccessorTo(storage, 0, option.sparse, null, offset, count);
}
}
/// <summary>
/// https://github.com/vrm-c/UniVRM/issues/800
///
@@ -62,14 +20,14 @@ namespace UniVRM10
/// </summary>
/// <param name="mesh"></param>
/// <param name="materials"></param>
/// <param name="storage"></param>
/// <param name="data"></param>
/// <param name="gltfMesh"></param>
/// <param name="option"></param>
static IEnumerable<glTFPrimitives> ExportMeshDivided(this VrmLib.Mesh mesh, List<object> materials,
ExportingGltfData writer, ExportArgs option)
ExportingGltfData writer, ExportArgs option)
{
var usedIndices = new List<int>();
var meshIndices = SpanLike.CopyFrom(mesh.IndexBuffer.GetAsIntArray());
var meshIndices = mesh.IndexBuffer.GetAsIntArray();
var positions = mesh.VertexBuffer.Positions.GetSpan<UnityEngine.Vector3>().ToArray();
var normals = mesh.VertexBuffer.Normals.GetSpan<UnityEngine.Vector3>().ToArray();
var uv = mesh.VertexBuffer.TexCoords.GetSpan<UnityEngine.Vector2>().ToArray();
@@ -87,7 +45,7 @@ namespace UniVRM10
foreach (var submesh in mesh.Submeshes)
{
var indices = meshIndices.Slice(submesh.Offset, submesh.DrawCount).ToArray();
var indices = meshIndices.GetSubArray(submesh.Offset, submesh.DrawCount).ToArray();
var hash = new HashSet<int>(indices);
// mesh
@@ -131,7 +89,7 @@ namespace UniVRM10
// index の順に attributes を蓄える
var morph = mesh.MorphTargets[j];
var blendShapePositions = morph.VertexBuffer.Positions.GetSpan<UnityEngine.Vector3>();
SpanLike<UnityEngine.Vector3>? blendShapeNormals = default;
NativeArray<UnityEngine.Vector3>? blendShapeNormals = default;
if (morph.VertexBuffer.Normals != null)
{
blendShapeNormals = morph.VertexBuffer.Normals.GetSpan<UnityEngine.Vector3>();
@@ -157,10 +115,10 @@ namespace UniVRM10
/// </summary>
/// <param name="src"></param>
/// <param name="materials"></param>
/// <param name="storage"></param>
/// <param name="data"></param>
/// <param name="option"></param>
/// <returns></returns>
public static glTFMesh ExportMeshGroup(this MeshGroup src, List<object> materials, ExportingGltfData writer, ExportArgs option)
public static glTFMesh ExportMeshGroup(this MeshGroup src, List<object> materials, ExportingGltfData writer, ExportArgs option)
{
var gltfMesh = new glTFMesh
{

View File

@@ -1,7 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using UniGLTF;
using Unity.Collections;
using UnityEngine;
using VrmLib;
@@ -23,11 +25,11 @@ namespace UniVRM10
/// </summary>
/// <param name="root"></param>
/// <returns></returns>
public VrmLib.Model Export(GameObject root)
public VrmLib.Model Export(INativeArrayManager arrayManager, GameObject root)
{
Model = new VrmLib.Model(VrmLib.Coordinates.Unity);
_Export(root);
_Export(arrayManager, root);
// humanoid
{
@@ -51,7 +53,7 @@ namespace UniVRM10
return Model;
}
VrmLib.Model _Export(GameObject root)
VrmLib.Model _Export(INativeArrayManager arrayManager, GameObject root)
{
if (Model == null)
{
@@ -94,8 +96,8 @@ namespace UniVRM10
{
if (skinnedMeshRenderer.sharedMesh != null)
{
var mesh = CreateMesh(skinnedMeshRenderer.sharedMesh, skinnedMeshRenderer, Materials);
var skin = CreateSkin(skinnedMeshRenderer, Nodes, root);
var mesh = CreateMesh(arrayManager, skinnedMeshRenderer.sharedMesh, skinnedMeshRenderer, Materials);
var skin = CreateSkin(arrayManager, skinnedMeshRenderer, Nodes, root);
if (skin != null)
{
// blendshape only で skinning が無いやつがある
@@ -112,7 +114,7 @@ namespace UniVRM10
var filter = meshRenderer.gameObject.GetComponent<MeshFilter>();
if (filter != null && filter.sharedMesh != null)
{
var mesh = CreateMesh(filter.sharedMesh, meshRenderer, Materials);
var mesh = CreateMesh(arrayManager, filter.sharedMesh, meshRenderer, Materials);
Model.MeshGroups.Add(mesh);
Nodes[renderer.gameObject].MeshGroup = mesh;
if (!Meshes.ContainsKey(filter.sharedMesh))
@@ -167,30 +169,30 @@ namespace UniVRM10
return null;
}
private static VrmLib.MeshGroup CreateMesh(UnityEngine.Mesh mesh, Renderer renderer, List<UnityEngine.Material> materials)
private static VrmLib.MeshGroup CreateMesh(INativeArrayManager arrayManager, UnityEngine.Mesh mesh, Renderer renderer, List<UnityEngine.Material> materials)
{
var meshGroup = new VrmLib.MeshGroup(mesh.name);
var vrmMesh = new VrmLib.Mesh();
vrmMesh.VertexBuffer = new VrmLib.VertexBuffer();
vrmMesh.VertexBuffer.Add(VrmLib.VertexBuffer.PositionKey, ToBufferAccessor(mesh.vertices));
vrmMesh.VertexBuffer.Add(VrmLib.VertexBuffer.PositionKey, ToBufferAccessor(arrayManager, mesh.vertices));
if (mesh.boneWeights.Length == mesh.vertexCount)
{
vrmMesh.VertexBuffer.Add(
VrmLib.VertexBuffer.WeightKey,
ToBufferAccessor(mesh.boneWeights.Select(x =>
ToBufferAccessor(arrayManager, mesh.boneWeights.Select(x =>
new Vector4(x.weight0, x.weight1, x.weight2, x.weight3)).ToArray()
));
vrmMesh.VertexBuffer.Add(
VrmLib.VertexBuffer.JointKey,
ToBufferAccessor(mesh.boneWeights.Select(x =>
ToBufferAccessor(arrayManager, mesh.boneWeights.Select(x =>
new SkinJoints((ushort)x.boneIndex0, (ushort)x.boneIndex1, (ushort)x.boneIndex2, (ushort)x.boneIndex3)).ToArray()
));
}
if (mesh.uv.Length == mesh.vertexCount) vrmMesh.VertexBuffer.Add(VrmLib.VertexBuffer.TexCoordKey, ToBufferAccessor(mesh.uv));
if (mesh.normals.Length == mesh.vertexCount) vrmMesh.VertexBuffer.Add(VrmLib.VertexBuffer.NormalKey, ToBufferAccessor(mesh.normals));
if (mesh.colors.Length == mesh.vertexCount) vrmMesh.VertexBuffer.Add(VrmLib.VertexBuffer.ColorKey, ToBufferAccessor(mesh.colors));
vrmMesh.IndexBuffer = ToBufferAccessor(mesh.triangles);
if (mesh.uv.Length == mesh.vertexCount) vrmMesh.VertexBuffer.Add(VrmLib.VertexBuffer.TexCoordKey, ToBufferAccessor(arrayManager, mesh.uv));
if (mesh.normals.Length == mesh.vertexCount) vrmMesh.VertexBuffer.Add(VrmLib.VertexBuffer.NormalKey, ToBufferAccessor(arrayManager, mesh.normals));
if (mesh.colors.Length == mesh.vertexCount) vrmMesh.VertexBuffer.Add(VrmLib.VertexBuffer.ColorKey, ToBufferAccessor(arrayManager, mesh.colors));
vrmMesh.IndexBuffer = ToBufferAccessor(arrayManager, mesh.triangles);
int offset = 0;
for (int i = 0; i < mesh.subMeshCount; i++)
@@ -240,7 +242,7 @@ namespace UniVRM10
{
var morphTarget = new VrmLib.MorphTarget(mesh.GetBlendShapeName(i));
morphTarget.VertexBuffer = new VrmLib.VertexBuffer();
morphTarget.VertexBuffer.Add(VrmLib.VertexBuffer.PositionKey, ToBufferAccessor(blendShapeVertices));
morphTarget.VertexBuffer.Add(VrmLib.VertexBuffer.PositionKey, ToBufferAccessor(arrayManager, blendShapeVertices));
vrmMesh.MorphTargets.Add(morphTarget);
}
}
@@ -249,7 +251,7 @@ namespace UniVRM10
return meshGroup;
}
private static VrmLib.Skin CreateSkin(
private static VrmLib.Skin CreateSkin(INativeArrayManager arrayManager,
SkinnedMeshRenderer skinnedMeshRenderer,
Dictionary<GameObject, VrmLib.Node> nodes,
GameObject root)
@@ -260,7 +262,7 @@ namespace UniVRM10
}
var skin = new VrmLib.Skin();
skin.InverseMatrices = ToBufferAccessor(skinnedMeshRenderer.sharedMesh.bindposes);
skin.InverseMatrices = ToBufferAccessor(arrayManager, skinnedMeshRenderer.sharedMesh.bindposes);
if (skinnedMeshRenderer.rootBone != null)
{
skin.Root = nodes[skinnedMeshRenderer.rootBone.gameObject];
@@ -270,46 +272,45 @@ namespace UniVRM10
return skin;
}
private static VrmLib.BufferAccessor ToBufferAccessor(SkinJoints[] values)
private static VrmLib.BufferAccessor ToBufferAccessor(INativeArrayManager arrayManager, SkinJoints[] values)
{
return ToBufferAccessor(values, VrmLib.AccessorValueType.UNSIGNED_SHORT, VrmLib.AccessorVectorType.VEC4);
return ToBufferAccessor(arrayManager, values, VrmLib.AccessorValueType.UNSIGNED_SHORT, VrmLib.AccessorVectorType.VEC4);
}
private static VrmLib.BufferAccessor ToBufferAccessor(Color[] colors)
private static VrmLib.BufferAccessor ToBufferAccessor(INativeArrayManager arrayManager, Color[] colors)
{
return ToBufferAccessor(colors, VrmLib.AccessorValueType.FLOAT, VrmLib.AccessorVectorType.VEC4);
return ToBufferAccessor(arrayManager, colors, VrmLib.AccessorValueType.FLOAT, VrmLib.AccessorVectorType.VEC4);
}
private static VrmLib.BufferAccessor ToBufferAccessor(Vector4[] vectors)
private static VrmLib.BufferAccessor ToBufferAccessor(INativeArrayManager arrayManager, Vector4[] vectors)
{
return ToBufferAccessor(vectors, VrmLib.AccessorValueType.FLOAT, VrmLib.AccessorVectorType.VEC4);
return ToBufferAccessor(arrayManager, vectors, VrmLib.AccessorValueType.FLOAT, VrmLib.AccessorVectorType.VEC4);
}
private static VrmLib.BufferAccessor ToBufferAccessor(Vector3[] vectors)
private static VrmLib.BufferAccessor ToBufferAccessor(INativeArrayManager arrayManager, Vector3[] vectors)
{
return ToBufferAccessor(vectors, VrmLib.AccessorValueType.FLOAT, VrmLib.AccessorVectorType.VEC3);
return ToBufferAccessor(arrayManager, vectors, VrmLib.AccessorValueType.FLOAT, VrmLib.AccessorVectorType.VEC3);
}
private static VrmLib.BufferAccessor ToBufferAccessor(Vector2[] vectors)
private static VrmLib.BufferAccessor ToBufferAccessor(INativeArrayManager arrayManager, Vector2[] vectors)
{
return ToBufferAccessor(vectors, VrmLib.AccessorValueType.FLOAT, VrmLib.AccessorVectorType.VEC2);
return ToBufferAccessor(arrayManager, vectors, VrmLib.AccessorValueType.FLOAT, VrmLib.AccessorVectorType.VEC2);
}
private static VrmLib.BufferAccessor ToBufferAccessor(int[] scalars)
private static VrmLib.BufferAccessor ToBufferAccessor(INativeArrayManager arrayManager, int[] scalars)
{
return ToBufferAccessor(scalars, VrmLib.AccessorValueType.UNSIGNED_INT, VrmLib.AccessorVectorType.SCALAR);
return ToBufferAccessor(arrayManager, scalars, VrmLib.AccessorValueType.UNSIGNED_INT, VrmLib.AccessorVectorType.SCALAR);
}
private static VrmLib.BufferAccessor ToBufferAccessor(Matrix4x4[] matrixes)
private static VrmLib.BufferAccessor ToBufferAccessor(INativeArrayManager arrayManager, Matrix4x4[] matrixes)
{
return ToBufferAccessor(matrixes, VrmLib.AccessorValueType.FLOAT, VrmLib.AccessorVectorType.MAT4);
return ToBufferAccessor(arrayManager, matrixes, VrmLib.AccessorValueType.FLOAT, VrmLib.AccessorVectorType.MAT4);
}
private static VrmLib.BufferAccessor ToBufferAccessor<T>(T[] value, VrmLib.AccessorValueType valueType, VrmLib.AccessorVectorType vectorType) where T : struct
private static VrmLib.BufferAccessor ToBufferAccessor<T>(INativeArrayManager arrayManager, T[] value, VrmLib.AccessorValueType valueType, VrmLib.AccessorVectorType vectorType) where T : struct
{
var span = SpanLike.CopyFrom(value);
return new VrmLib.BufferAccessor(
span.Bytes,
return new VrmLib.BufferAccessor(arrayManager,
arrayManager.CreateNativeArray(value).Reinterpret<byte>(Marshal.SizeOf<T>()),
valueType,
vectorType,
value.Length

View File

@@ -1,34 +0,0 @@
using System;
using UniGLTF;
using UniJSON;
namespace UniVRM10
{
public class Vrm10ExportData : ExportingGltfData
{
public void Reserve(int bytesLength)
{
_buffer.ExtendCapacity(bytesLength);
}
public int AppendToBuffer(ArraySegment<byte> segment)
{
var gltfBufferView = _buffer.Extend(segment);
var viewIndex = GLTF.bufferViews.Count;
GLTF.bufferViews.Add(gltfBufferView);
return viewIndex;
}
public byte[] ToBytes()
{
GLTF.buffers[0].byteLength = _buffer.Bytes.Count;
var f = new JsonFormatter();
UniGLTF.GltfSerializer.Serialize(f, GLTF);
var json = f.GetStoreBytes();
var glb = UniGLTF.Glb.Create(json, _buffer.Bytes);
return glb.ToBytes();
}
}
}

View File

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

View File

@@ -18,7 +18,7 @@ namespace UniVRM10
public const string LICENSE_URL_JA = "https://vrm.dev/licenses/1.0/";
public const string LICENSE_URL_EN = "https://vrm.dev/licenses/1.0/en/";
public readonly Vrm10ExportData Storage = new Vrm10ExportData();
public readonly ExportingGltfData Storage = new ExportingGltfData();
public readonly string VrmExtensionName = "VRMC_vrm";
@@ -36,12 +36,12 @@ namespace UniVRM10
throw new ArgumentException(nameof(textureSerializer));
}
Storage.GLTF.extensionsUsed.Add(glTF_KHR_texture_transform.ExtensionName);
Storage.GLTF.extensionsUsed.Add(UniGLTF.Extensions.VRMC_vrm.VRMC_vrm.ExtensionName);
Storage.GLTF.extensionsUsed.Add(glTF_KHR_materials_unlit.ExtensionName);
Storage.GLTF.extensionsUsed.Add(UniGLTF.Extensions.VRMC_materials_mtoon.VRMC_materials_mtoon.ExtensionName);
Storage.GLTF.extensionsUsed.Add(UniGLTF.Extensions.VRMC_springBone.VRMC_springBone.ExtensionName);
Storage.GLTF.extensionsUsed.Add(UniGLTF.Extensions.VRMC_node_constraint.VRMC_node_constraint.ExtensionName);
Storage.Gltf.extensionsUsed.Add(glTF_KHR_texture_transform.ExtensionName);
Storage.Gltf.extensionsUsed.Add(UniGLTF.Extensions.VRMC_vrm.VRMC_vrm.ExtensionName);
Storage.Gltf.extensionsUsed.Add(glTF_KHR_materials_unlit.ExtensionName);
Storage.Gltf.extensionsUsed.Add(UniGLTF.Extensions.VRMC_materials_mtoon.VRMC_materials_mtoon.ExtensionName);
Storage.Gltf.extensionsUsed.Add(UniGLTF.Extensions.VRMC_springBone.VRMC_springBone.ExtensionName);
Storage.Gltf.extensionsUsed.Add(UniGLTF.Extensions.VRMC_node_constraint.VRMC_node_constraint.ExtensionName);
m_textureSerializer = textureSerializer;
m_textureExporter = new TextureExporter(m_textureSerializer);
@@ -70,7 +70,7 @@ namespace UniVRM10
}
}
public static IEnumerable<(glTFNode, glTFSkin)> ExportNodes(List<Node> nodes, List<MeshGroup> groups, Vrm10ExportData storage, ExportArgs option)
public static IEnumerable<(glTFNode, glTFSkin)> ExportNodes(INativeArrayManager arrayManager, List<Node> nodes, List<MeshGroup> groups, ExportingGltfData data, ExportArgs option)
{
foreach (var node in nodes)
{
@@ -96,11 +96,11 @@ namespace UniVRM10
};
if (skin.InverseMatrices == null)
{
skin.CalcInverseMatrices();
skin.CalcInverseMatrices(arrayManager);
}
if (skin.InverseMatrices != null)
{
gltfSkin.inverseBindMatrices = skin.InverseMatrices.AddAccessorTo(storage, 0, option.sparse);
gltfSkin.inverseBindMatrices = skin.InverseMatrices.AddAccessorTo(data, 0, option.sparse);
}
if (skin.Root != null)
{
@@ -166,36 +166,39 @@ namespace UniVRM10
public void Export(GameObject root, Model model, ModelExporter converter, ExportArgs option, VRM10ObjectMeta vrmMeta = null)
{
Storage.GLTF.asset = ExportAsset(model);
Storage.Gltf.asset = ExportAsset(model);
Storage.Reserve(CalcReserveBytes(model));
foreach (var material in ExportMaterials(model, m_textureExporter, m_settings))
{
Storage.GLTF.materials.Add(material);
Storage.Gltf.materials.Add(material);
}
foreach (var mesh in ExportMeshes(model.MeshGroups, model.Materials, Storage, option))
{
Storage.GLTF.meshes.Add(mesh);
Storage.Gltf.meshes.Add(mesh);
}
foreach (var (node, skin) in ExportNodes(model.Nodes, model.MeshGroups, Storage, option))
using (var arrayManager = new NativeArrayManager())
{
Storage.GLTF.nodes.Add(node);
if (skin != null)
foreach (var (node, skin) in ExportNodes(arrayManager, model.Nodes, model.MeshGroups, Storage, option))
{
var skinIndex = Storage.GLTF.skins.Count;
Storage.GLTF.skins.Add(skin);
node.skin = skinIndex;
Storage.Gltf.nodes.Add(node);
if (skin != null)
{
var skinIndex = Storage.Gltf.skins.Count;
Storage.Gltf.skins.Add(skin);
node.skin = skinIndex;
}
}
}
Storage.GLTF.scenes.Add(new gltfScene()
Storage.Gltf.scenes.Add(new gltfScene()
{
nodes = model.Root.Children.Select(child => model.Nodes.IndexOfThrow(child)).ToArray()
});
var (vrm, vrmSpringBone, thumbnailTextureIndex) = ExportVrm(root, model, converter, vrmMeta, Storage.GLTF.nodes, m_textureExporter);
var (vrm, vrmSpringBone, thumbnailTextureIndex) = ExportVrm(root, model, converter, vrmMeta, Storage.Gltf.nodes, m_textureExporter);
// Extension で Texture が増える場合があるので最後に呼ぶ
var exportedTextures = m_textureExporter.Export();
@@ -207,18 +210,18 @@ namespace UniVRM10
if (thumbnailTextureIndex.HasValue)
{
vrm.Meta.ThumbnailImage = Storage.GLTF.textures[thumbnailTextureIndex.Value].source;
vrm.Meta.ThumbnailImage = Storage.Gltf.textures[thumbnailTextureIndex.Value].source;
}
UniGLTF.Extensions.VRMC_vrm.GltfSerializer.SerializeTo(ref Storage.GLTF.extensions, vrm);
UniGLTF.Extensions.VRMC_vrm.GltfSerializer.SerializeTo(ref Storage.Gltf.extensions, vrm);
if (vrmSpringBone != null)
{
UniGLTF.Extensions.VRMC_springBone.GltfSerializer.SerializeTo(ref Storage.GLTF.extensions, vrmSpringBone);
UniGLTF.Extensions.VRMC_springBone.GltfSerializer.SerializeTo(ref Storage.Gltf.extensions, vrmSpringBone);
}
// Fix Duplicated name
gltfExporter.FixName(Storage.GLTF);
gltfExporter.FixName(Storage.Gltf);
}
@@ -343,7 +346,8 @@ namespace UniVRM10
colliders.Length == 0 &&
controller.SpringBone.ColliderGroups.Count == 0 &&
controller.SpringBone.Springs.Count == 0
) {
)
{
return null;
}
@@ -803,20 +807,23 @@ namespace UniVRM10
/// <returns></returns>
public static byte[] Export(GameObject go, ITextureSerializer textureSerializer = null)
{
// ヒエラルキーからジオメトリーを収集
var converter = new UniVRM10.ModelExporter();
var model = converter.Export(go);
// 右手系に変換
model.ConvertCoordinate(VrmLib.Coordinates.Vrm1);
// Model と go から VRM-1.0 にExport
var exporter10 = new Vrm10Exporter(textureSerializer ?? new RuntimeTextureSerializer(), new GltfExportSettings());
var option = new VrmLib.ExportArgs
using (var arrayManager = new NativeArrayManager())
{
};
exporter10.Export(go, model, converter, option);
return exporter10.Storage.ToBytes();
// ヒエラルキーからジオメトリーを収集
var converter = new UniVRM10.ModelExporter();
var model = converter.Export(arrayManager, go);
// 右手系に変換
model.ConvertCoordinate(VrmLib.Coordinates.Vrm1);
// Model と go から VRM-1.0 にExport
var exporter10 = new Vrm10Exporter(textureSerializer ?? new RuntimeTextureSerializer(), new GltfExportSettings());
var option = new VrmLib.ExportArgs
{
};
exporter10.Export(go, model, converter, option);
return exporter10.Storage.ToGlbBytes();
}
}
}
}

View File

@@ -5,6 +5,7 @@ using System.Numerics;
using UniGLTF;
using VrmLib;
using System.Collections.Generic;
using Unity.Collections;
namespace UniVRM10
{
@@ -33,8 +34,6 @@ namespace UniVRM10
public UniGLTF.Extensions.VRMC_springBone.VRMC_springBone gltfVrmSpringBone;
ArraySegmentByteBuffer _buffer;
/// <summary>
/// for import
/// </summary>
@@ -55,11 +54,19 @@ namespace UniVRM10
{
gltfVrmSpringBone = springBone;
}
_buffer = new ArraySegmentByteBuffer(new ArraySegment<byte>(data.Bin.ToArray()));
}
public ArraySegment<byte> GetBufferBytes(UniGLTF.glTFBufferView bufferView)
public NativeArray<byte> GetBufferBytes(UniGLTF.glTFBuffer buffer)
{
int index = Gltf.buffers.IndexOf(buffer);
if (index != 0)
{
throw new NotImplementedException();
}
return m_data.Bin;
}
public NativeArray<byte> GetBufferBytes(UniGLTF.glTFBufferView bufferView)
{
if (!bufferView.buffer.TryGetValidIndex(Gltf.buffers.Count, out int bufferViewBufferIndex))
{
@@ -68,28 +75,18 @@ namespace UniVRM10
return GetBufferBytes(Gltf.buffers[bufferViewBufferIndex]);
}
public ArraySegment<byte> GetBufferBytes(UniGLTF.glTFBuffer buffer)
{
int index = Gltf.buffers.IndexOf(buffer);
if (index != 0)
{
throw new NotImplementedException();
}
return _buffer.Bytes;
}
static ArraySegment<byte> RestoreSparseAccessorUInt16<T>(ArraySegment<byte> bytes, int accessorCount, ArraySegment<byte> indicesBytes, ArraySegment<byte> valuesBytes)
static NativeArray<byte> RestoreSparseAccessorUInt16<T>(INativeArrayManager arrayManager, NativeArray<byte> bytes, int accessorCount, NativeArray<byte> indicesBytes, NativeArray<byte> valuesBytes)
where T : struct
{
var stride = Marshal.SizeOf(typeof(T));
if (bytes.Count == 0)
if (bytes.Length == 0)
{
bytes = new ArraySegment<byte>(new byte[accessorCount * stride]);
bytes = arrayManager.CreateNativeArray<byte>(accessorCount * stride);
}
var dst = SpanLike.Wrap<T>(bytes);
var dst = bytes.Reinterpret<T>(1);
var indices = SpanLike.Wrap<UInt16>(indicesBytes);
var values = SpanLike.Wrap<T>(valuesBytes);
var indices = indicesBytes.Reinterpret<UInt16>(1);
var values = valuesBytes.Reinterpret<T>(1);
for (int i = 0; i < indices.Length; ++i)
{
@@ -101,18 +98,18 @@ namespace UniVRM10
return bytes;
}
static ArraySegment<byte> RestoreSparseAccessorUInt32<T>(ArraySegment<byte> bytes, int accessorCount, ArraySegment<byte> indicesBytes, ArraySegment<byte> valuesBytes)
static NativeArray<byte> RestoreSparseAccessorUInt32<T>(INativeArrayManager arrayManager, NativeArray<byte> bytes, int accessorCount, NativeArray<byte> indicesBytes, NativeArray<byte> valuesBytes)
where T : struct
{
var stride = Marshal.SizeOf(typeof(T));
if (bytes.Count == 0)
if (bytes.Length == 0)
{
bytes = new ArraySegment<byte>(new byte[accessorCount * stride]);
bytes = arrayManager.CreateNativeArray<byte>(accessorCount * stride);
}
var dst = SpanLike.Wrap<T>(bytes);
var dst = bytes.Reinterpret<T>(1);
var indices = SpanLike.Wrap<Int32>(indicesBytes);
var values = SpanLike.Wrap<T>(valuesBytes);
var indices = indicesBytes.Reinterpret<Int32>(1);
var values = valuesBytes.Reinterpret<T>(1);
for (int i = 0; i < indices.Length; ++i)
{
@@ -124,12 +121,12 @@ namespace UniVRM10
return bytes;
}
public ArraySegment<byte> GetAccessorBytes(int accessorIndex)
public NativeArray<byte> GetAccessorBytes(int accessorIndex)
{
var accessor = Gltf.accessors[accessorIndex];
var sparse = accessor.sparse;
ArraySegment<byte> bytes = default(ArraySegment<byte>);
NativeArray<byte> bytes = default;
if (accessor.bufferView.TryGetValidIndex(Gltf.bufferViews.Count, out int bufferViewIndex))
{
@@ -137,9 +134,8 @@ namespace UniVRM10
if (view.buffer.TryGetValidIndex(Gltf.buffers.Count, out int bufferIndex))
{
var buffer = m_data.Bin;
var bin = _buffer.Bytes;
var byteSize = accessor.CalcByteSize();
bytes = bin.Slice(view.byteOffset, view.byteLength).Slice(accessor.byteOffset, byteSize);
bytes = m_data.Bin.GetSubArray(view.byteOffset, view.byteLength).GetSubArray(accessor.byteOffset, byteSize);
}
}
@@ -152,8 +148,8 @@ namespace UniVRM10
var sparseIndexView = Gltf.bufferViews[sparseIndicesBufferViewIndex];
var sparseIndexBin = GetBufferBytes(sparseIndexView);
var sparseIndexBytes = sparseIndexBin
.Slice(sparseIndexView.byteOffset, sparseIndexView.byteLength)
.Slice(sparse.indices.byteOffset, ((AccessorValueType)sparse.indices.componentType).ByteSize() * sparse.count)
.GetSubArray(sparseIndexView.byteOffset, sparseIndexView.byteLength)
.GetSubArray(sparse.indices.byteOffset, ((AccessorValueType)sparse.indices.componentType).ByteSize() * sparse.count)
;
if (!sparse.values.bufferView.TryGetValidIndex(Gltf.bufferViews.Count, out int sparseValuesBufferViewIndex))
@@ -163,21 +159,21 @@ namespace UniVRM10
var sparseValueView = Gltf.bufferViews[sparseValuesBufferViewIndex];
var sparseValueBin = GetBufferBytes(sparseValueView);
var sparseValueBytes = sparseValueBin
.Slice(sparseValueView.byteOffset, sparseValueView.byteLength)
.Slice(sparse.values.byteOffset, accessor.GetStride() * sparse.count);
.GetSubArray(sparseValueView.byteOffset, sparseValueView.byteLength)
.GetSubArray(sparse.values.byteOffset, accessor.GetStride() * sparse.count);
;
if (sparse.indices.componentType == (UniGLTF.glComponentType)AccessorValueType.UNSIGNED_SHORT
&& accessor.componentType == (UniGLTF.glComponentType)AccessorValueType.FLOAT
&& accessor.type == "VEC3")
{
return RestoreSparseAccessorUInt16<Vector3>(bytes, accessor.count, sparseIndexBytes, sparseValueBytes);
return RestoreSparseAccessorUInt16<Vector3>(m_data.NativeArrayManager, bytes, accessor.count, sparseIndexBytes, sparseValueBytes);
}
if (sparse.indices.componentType == (UniGLTF.glComponentType)AccessorValueType.UNSIGNED_INT
&& accessor.componentType == (UniGLTF.glComponentType)AccessorValueType.FLOAT
&& accessor.type == "VEC3")
{
return RestoreSparseAccessorUInt32<Vector3>(bytes, accessor.count, sparseIndexBytes, sparseValueBytes);
return RestoreSparseAccessorUInt32<Vector3>(m_data.NativeArrayManager, bytes, accessor.count, sparseIndexBytes, sparseValueBytes);
}
else
{
@@ -186,10 +182,10 @@ namespace UniVRM10
}
else
{
if (bytes.Count == 0)
if (bytes.Length == 0)
{
// sparse and all value is zero
return new ArraySegment<byte>(new byte[accessor.GetStride() * accessor.count]);
return m_data.NativeArrayManager.CreateNativeArray<byte>(accessor.GetStride() * accessor.count);
}
return bytes;
@@ -206,7 +202,7 @@ namespace UniVRM10
var accessor = Gltf.accessors[accessorIndex];
var bytes = GetAccessorBytes(accessorIndex);
var vectorType = EnumUtil.Parse<AccessorVectorType>(accessor.type);
ba = new BufferAccessor(bytes,
ba = new BufferAccessor(m_data.NativeArrayManager, bytes,
(AccessorValueType)accessor.componentType, vectorType, accessor.count);
return true;
}
@@ -278,8 +274,8 @@ namespace UniVRM10
}
var buffer = Gltf.buffers[firstViewBufferIndex];
var bin = GetBufferBytes(buffer);
var bytes = bin.Slice(start, totalCount * firstAccessor.GetStride());
return new BufferAccessor(bytes,
var bytes = bin.GetSubArray(start, totalCount * firstAccessor.GetStride());
return new BufferAccessor(m_data.NativeArrayManager, bytes,
(AccessorValueType)firstAccessor.componentType,
EnumUtil.Parse<AccessorVectorType>(firstAccessor.type),
totalCount);
@@ -287,62 +283,64 @@ namespace UniVRM10
else
{
// IndexBufferが連続して格納されていない => Int[] を作り直す
var indices = new byte[totalCount * Marshal.SizeOf(typeof(int))];
var span = SpanLike.Wrap<Int32>(new ArraySegment<byte>(indices));
var offset = 0;
foreach (var accessorIndex in accessorIndices)
using (var indices = new NativeArray<byte>(totalCount * Marshal.SizeOf(typeof(int)), Allocator.Persistent))
{
var accessor = Gltf.accessors[accessorIndex];
if (accessor.type != "SCALAR")
var span = indices.Reinterpret<Int32>(1);
var offset = 0;
foreach (var accessorIndex in accessorIndices)
{
throw new ArgumentException($"accessor.type: {accessor.type}");
}
var view = Gltf.bufferViews[accessor.bufferView];
if (!view.buffer.TryGetValidIndex(Gltf.buffers.Count, out int viewBufferIndex))
{
throw new Exception();
}
var buffer = Gltf.buffers[viewBufferIndex];
var bin = GetBufferBytes(buffer);
var start = view.byteOffset + accessor.byteOffset;
var bytes = bin.Slice(start, accessor.count * accessor.GetStride());
var dst = SpanLike.Wrap<Int32>(new ArraySegment<byte>(indices)).Slice(offset, accessor.count);
offset += accessor.count;
switch ((AccessorValueType)accessor.componentType)
{
case AccessorValueType.UNSIGNED_BYTE:
{
var src = SpanLike.Wrap<Byte>(bytes);
for (int i = 0; i < src.Length; ++i)
var accessor = Gltf.accessors[accessorIndex];
if (accessor.type != "SCALAR")
{
throw new ArgumentException($"accessor.type: {accessor.type}");
}
var view = Gltf.bufferViews[accessor.bufferView];
if (!view.buffer.TryGetValidIndex(Gltf.buffers.Count, out int viewBufferIndex))
{
throw new Exception();
}
var buffer = Gltf.buffers[viewBufferIndex];
var bin = GetBufferBytes(buffer);
var start = view.byteOffset + accessor.byteOffset;
var bytes = bin.GetSubArray(start, accessor.count * accessor.GetStride());
var dst = indices.Reinterpret<Int32>(1).GetSubArray(offset, accessor.count);
offset += accessor.count;
switch ((AccessorValueType)accessor.componentType)
{
case AccessorValueType.UNSIGNED_BYTE:
{
// byte to int
dst[i] = src[i];
var src = bytes;
for (int i = 0; i < src.Length; ++i)
{
// byte to int
dst[i] = src[i];
}
}
}
break;
break;
case AccessorValueType.UNSIGNED_SHORT:
{
var src = SpanLike.Wrap<UInt16>(bytes);
for (int i = 0; i < src.Length; ++i)
case AccessorValueType.UNSIGNED_SHORT:
{
// ushort to int
dst[i] = src[i];
var src = bytes.Reinterpret<UInt16>(1);
for (int i = 0; i < src.Length; ++i)
{
// ushort to int
dst[i] = src[i];
}
}
}
break;
break;
case AccessorValueType.UNSIGNED_INT:
{
Buffer.BlockCopy(bytes.Array, bytes.Offset, dst.Bytes.Array, dst.Bytes.Offset, bytes.Count);
}
break;
case AccessorValueType.UNSIGNED_INT:
{
NativeArray<byte>.Copy(bytes, dst.Reinterpret<byte>(Marshal.SizeOf<Int32>()));
}
break;
default:
throw new NotImplementedException($"accessor.componentType: {accessor.componentType}");
default:
throw new NotImplementedException($"accessor.componentType: {accessor.componentType}");
}
}
return new BufferAccessor(m_data.NativeArrayManager, indices, AccessorValueType.UNSIGNED_INT, AccessorVectorType.SCALAR, totalCount);
}
return new BufferAccessor(new ArraySegment<byte>(indices), AccessorValueType.UNSIGNED_INT, AccessorVectorType.SCALAR, totalCount);
}
}

View File

@@ -92,7 +92,7 @@ namespace UniVRM10
if (m_doNormalize)
{
var result = m_model.SkinningBake();
var result = m_model.SkinningBake(Data.NativeArrayManager);
Debug.Log($"SkinningBake: {result}");
}

View File

@@ -1,7 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using UniGLTF;
using Unity.Collections;
using UnityEngine;
namespace UniVRM10
@@ -23,7 +25,7 @@ namespace UniVRM10
_buffer = new ArrayByteBuffer(new byte[data.Bin.Length]);
}
int AddBuffer(ArraySegment<byte> bytes)
int AddBuffer(NativeArray<byte> bytes)
{
var bufferView = _buffer.Extend(bytes);
var index = _bufferViews.Count;
@@ -31,9 +33,9 @@ namespace UniVRM10
return index;
}
int AddAccessor<T>(SpanLike<T> span) where T : struct
int AddAccessor<T>(NativeArray<T> span) where T : struct
{
var bufferViewIndex = AddBuffer(span.Bytes);
var bufferViewIndex = AddBuffer(span.Reinterpret<byte>(Marshal.SizeOf<T>()));
var accessor = new glTFAccessor
{
bufferView = bufferViewIndex,
@@ -70,24 +72,20 @@ namespace UniVRM10
foreach (var image in gltf.images)
{
var bytes = _data.GetBytesFromBufferView(image.bufferView);
image.bufferView = AddBuffer(new ArraySegment<byte>(bytes.ToArray()));
image.bufferView = AddBuffer(bytes);
}
// update Mesh
foreach (var (gltfMesh, mesh) in Enumerable.Zip(gltf.meshes, model.MeshGroups, (l, r) => (l, r.Meshes[0])))
{
SpanLike<uint> indices;
NativeArray<uint> indices;
switch (mesh.IndexBuffer.Stride)
{
case 1:
{
// byte
var byte_indices = mesh.IndexBuffer.GetSpan<byte>();
indices = SpanLike.Create<uint>(byte_indices.Length);
for (int i = 0; i < byte_indices.Length; ++i)
{
indices[i] = byte_indices[i];
}
indices = _data.NativeArrayManager.Convert(byte_indices, (byte x) => (uint)x);
break;
}
@@ -95,11 +93,7 @@ namespace UniVRM10
{
// ushort
var ushort_indices = mesh.IndexBuffer.GetSpan<ushort>();
indices = SpanLike.Create<uint>(ushort_indices.Length);
for (int i = 0; i < ushort_indices.Length; ++i)
{
indices[i] = ushort_indices[i];
}
indices = _data.NativeArrayManager.Convert(ushort_indices, (ushort x) => (uint)x);
break;
}
@@ -132,7 +126,7 @@ namespace UniVRM10
foreach (var (gltfPrim, submesh) in Enumerable.Zip(gltfMesh.primitives, mesh.Submeshes, (l, r) => (l, r)))
{
var subIndices = indices.Slice(submesh.Offset, submesh.DrawCount);
var subIndices = indices.GetSubArray(submesh.Offset, submesh.DrawCount);
gltfPrim.indices = AddAccessor(subIndices);
gltfPrim.attributes.POSITION = position.Value;
gltfPrim.attributes.NORMAL = normal.GetValueOrDefault(-1); // たぶん、ありえる
@@ -178,7 +172,8 @@ namespace UniVRM10
gltfSkin.inverseBindMatrices = AddAccessor(node.MeshGroup.Skin.InverseMatrices.GetSpan<Matrix4x4>());
gltf.skins.Add(gltfSkin);
}
else{
else
{
// multi nodes sharing a same skin may be error ?
// edge case.
}

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic;
using UniGLTF;
using UniJSON;
using Unity.Collections;
namespace UniVRM10
{
@@ -18,7 +19,7 @@ namespace UniVRM10
}
}
static (int, int) GetVertexRange(SpanLike<int> indices)
static (int, int) GetVertexRange(NativeArray<int> indices)
{
var min = int.MaxValue; ;
var max = 0;

View File

@@ -31,7 +31,7 @@ namespace UniVRM10.Test
private (GameObject, IReadOnlyList<VRMShaders.MaterialFactory.MaterialLoadInfo>) ToUnity(byte[] bytes)
{
// Vrm => Model
using(var data = new GlbBinaryParser(bytes, "tmp.vrm").Parse())
using (var data = new GlbBinaryParser(bytes, "tmp.vrm").Parse())
using (var migrated = Vrm10Data.Migrate(data, out Vrm10Data result, out MigrationData migration))
{
if (result == null)
@@ -54,11 +54,14 @@ namespace UniVRM10.Test
private Model ToVrmModel(GameObject root)
{
var exporter = new UniVRM10.ModelExporter();
var model = exporter.Export(root);
using (var arrayManager = new NativeArrayManager())
{
var exporter = new UniVRM10.ModelExporter();
var model = exporter.Export(arrayManager, root);
model.ConvertCoordinate(VrmLib.Coordinates.Vrm1, ignoreVrm: false);
return model;
model.ConvertCoordinate(VrmLib.Coordinates.Vrm1, ignoreVrm: false);
return model;
}
}
void EqualColor(Color color1, Color color2)

View File

@@ -4,6 +4,7 @@ using System.Linq;
using System.Numerics;
using UniGLTF;
namespace VrmLib
{
/// <summary>
@@ -128,7 +129,7 @@ namespace VrmLib
{
get
{
var span = SpanLike.Wrap<Single>(Rotation.In.Bytes);
var span = Rotation.In.Bytes.Reinterpret<Single>(1);
if (Index < span.Length)
{
return span[Index];
@@ -160,8 +161,10 @@ namespace VrmLib
list.Clear();
var min = float.PositiveInfinity;
foreach (var (curve, index) in curves)
foreach (var kv in curves)
{
var curve = kv.Key;
var index = kv.Value;
var keyframe = new KeyFrameReference(curve, index);
var seconds = keyframe.Seconds;
if (seconds < min)
@@ -218,108 +221,5 @@ namespace VrmLib
return m_root;
}
}
/// <summary>
/// モーションの基本姿勢を basePose ベースに再計算する
///
/// basePose は Humanoid.CopyNodes が必用 !
/// </summary>
public Animation RebaseAnimation(Humanoid basePose)
{
var map = NodeMap.ToDictionary(kv => kv.Key, kv => new List<Quaternion>());
var hipsPositions = new List<Vector3>();
foreach (var (seconds, keyframes) in KeyFramesGroupBySeconds())
{
// モーション適用
SetTime(seconds);
Root.CalcWorldMatrix();
foreach (var keyframe in keyframes)
{
if (!keyframe.Node.HumanoidBone.HasValue
|| keyframe.Node.HumanoidBone.Value == HumanoidBones.unknown)
{
continue;
}
// ローカル回転を算出する
var t = basePose[keyframe.Node].Rotation;
var w = keyframe.Node.Rotation;
var w_from_t = w * Quaternion.Inverse(t);
// parent
var key = keyframe.Node.HumanoidBone.Value;
var curve = map[keyframe.Node];
if (key != HumanoidBones.hips)
{
if (basePose[key].Parent == null)
{
throw new Exception();
}
var parent_t = basePose[key].Parent.Rotation;
var parent_w = keyframe.Node.Parent.Rotation;
var parent_w_from_t = parent_w * Quaternion.Inverse(parent_t);
var r = Quaternion.Inverse(parent_w_from_t) * w_from_t;
curve.Add(r);
}
else
{
// hips
curve.Add(w_from_t);
hipsPositions.Add(keyframe.Node.Translation);
}
}
}
var dst = new Animation(Name + ".tpose");
foreach (var kv in map)
{
if (!kv.Value.Any())
{
continue;
}
var bone = kv.Key.HumanoidBone.Value;
var inCurve = NodeMap[kv.Key].Curves[AnimationPathType.Rotation].In;
if (inCurve.Count != kv.Value.Count)
{
throw new Exception();
}
var nodeAnimation = new NodeAnimation();
nodeAnimation.Curves.Add(AnimationPathType.Rotation, new CurveSampler
{
In = inCurve,
Out = BufferAccessor.Create(kv.Value.ToArray()),
});
if (bone == HumanoidBones.hips)
{
nodeAnimation.Curves.Add(AnimationPathType.Translation, new CurveSampler
{
In = inCurve,
Out = BufferAccessor.Create(hipsPositions.ToArray()),
});
}
dst.AddCurve(kv.Key, nodeAnimation);
}
return dst;
}
/// <summary>
/// 指定された数のフレームを先頭から取り除く
/// </summary>
public void SkipFrame(int skipFrames)
{
foreach (var kv in NodeMap)
{
foreach (var curve in kv.Value.Curves)
{
curve.Value.SkipFrame(skipFrames);
}
}
}
}
}

View File

@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Runtime.InteropServices;
using UniGLTF;
@@ -79,7 +78,9 @@ namespace VrmLib
public class BufferAccessor
{
public ArraySegment<byte> Bytes;
public INativeArrayManager ArrayManager { get; }
public NativeArray<byte> Bytes;
public AccessorValueType ComponentType;
@@ -91,19 +92,20 @@ namespace VrmLib
public int ByteLength => Stride * Count;
public BufferAccessor(ArraySegment<byte> bytes, AccessorValueType componentType, AccessorVectorType accessorType, int count)
public BufferAccessor(INativeArrayManager arrayManager, NativeArray<byte> bytes, AccessorValueType componentType, AccessorVectorType accessorType, int count)
{
ArrayManager = arrayManager;
Bytes = bytes;
ComponentType = componentType;
AccessorType = accessorType;
Count = count;
}
public static BufferAccessor Create<T>(T[] list) where T : struct
public static BufferAccessor Create<T>(INativeArrayManager arrayManager, T[] list) where T : struct
{
var t = typeof(T);
var bytes = new byte[list.Length * Marshal.SizeOf(t)];
var span = SpanLike.Wrap<T>(new ArraySegment<byte>(bytes));
var bytes = arrayManager.CreateNativeArray<byte>(list.Length * Marshal.SizeOf(t));
var span = bytes.Reinterpret<T>(1);
for (int i = 0; i < list.Length; ++i)
{
span[i] = list[i];
@@ -144,8 +146,7 @@ namespace VrmLib
{
throw new NotImplementedException();
}
return new BufferAccessor(
new ArraySegment<byte>(bytes), componentType, accessorType, list.Length);
return new BufferAccessor(arrayManager, bytes, componentType, accessorType, list.Length);
}
public override string ToString()
@@ -153,47 +154,13 @@ namespace VrmLib
return $"{Stride}stride x{Count}";
}
public SpanLike<T> GetSpan<T>(bool checkStride = true) where T : struct
public NativeArray<T> GetSpan<T>(bool checkStride = true) where T : struct
{
if (checkStride && Marshal.SizeOf(typeof(T)) != Stride)
{
throw new Exception("different sizeof(T) with stride");
}
return SpanLike.Wrap<T>(Bytes);
}
/// <summary>
/// バッファをNativeArrayに変換して返す
/// 開放の責務は使い手側にある点に注意
/// </summary>
public unsafe NativeArray<T> AsNativeArray<T>(Allocator allocator) where T : struct
{
if (Stride == Marshal.SizeOf(typeof(T)))
{
fixed (byte* byteArray = Bytes.Array)
{
var nativeArray = new NativeArray<T>(Bytes.Count / Marshal.SizeOf<T>(), allocator);
UnsafeUtility.MemCpy(nativeArray.GetUnsafePtr(), byteArray + Bytes.Offset, Bytes.Count);
return nativeArray;
}
}
else
{
if (typeof(T) == typeof(SkinJoints) && Stride == 4)
{
// 例えば SkinJoints を使う JOINTS_0 は UNSIGNED_BYTE と UNSIGNED_SHORT の2種類がありえる。
fixed (UShort4* p = GetAsUShort4())
{
var nativeArray = new NativeArray<T>(Count, allocator);
UnsafeUtility.MemCpy(nativeArray.GetUnsafePtr(), p, Bytes.Count);
return nativeArray;
}
}
else
{
throw new Exception($"Stride:{Stride}!= sizeof({typeof(T).Name}:{Marshal.SizeOf(typeof(T))}");
}
}
return Bytes.Reinterpret<T>(1);
}
/// <summary>
@@ -201,10 +168,8 @@ namespace VrmLib
/// </summary>
public unsafe void CopyToNativeSlice<T>(NativeSlice<T> destArray) where T : unmanaged
{
fixed (byte* byteArray = Bytes.Array)
{
UnsafeUtility.MemCpy((T*)destArray.GetUnsafePtr(), byteArray + Bytes.Offset, Bytes.Count);
}
var byteArray = NativeArrayUnsafeUtility.GetUnsafePtr(Bytes);
UnsafeUtility.MemCpy((T*)destArray.GetUnsafePtr(), byteArray, Bytes.Length);
}
public void Assign<T>(T[] values) where T : struct
@@ -213,24 +178,24 @@ namespace VrmLib
{
throw new Exception("invalid element size");
}
var array = new byte[Stride * values.Length];
Bytes = new ArraySegment<byte>(array);
values.ToBytes(Bytes);
Bytes = ArrayManager.CreateNativeArray<byte>(Stride * values.Length);
Count = values.Length;
Bytes.Reinterpret<T>(1).CopyFrom(values);
}
public void Assign<T>(SpanLike<T> values) where T : struct
public void Assign<T>(NativeArray<T> values) where T : struct
{
if (Marshal.SizeOf(typeof(T)) != Stride)
{
throw new Exception("invalid element size");
}
Bytes = values.Bytes;
Bytes = ArrayManager.CreateNativeArray<byte>(Marshal.SizeOf<T>() * values.Length);
NativeArray<T>.Copy(values, Bytes.Reinterpret<T>(1));
Count = values.Length;
}
// for index buffer
public void AssignAsShort(SpanLike<int> values)
public void AssignAsShort(NativeArray<int> values)
{
if (AccessorType != AccessorVectorType.SCALAR)
{
@@ -238,17 +203,12 @@ namespace VrmLib
}
ComponentType = AccessorValueType.UNSIGNED_SHORT;
Bytes = new ArraySegment<byte>(new byte[Stride * values.Length]);
var span = GetSpan<ushort>();
Bytes = ArrayManager.Convert(values, (int x) => (ushort)x).Reinterpret<Byte>(Marshal.SizeOf<ushort>());
Count = values.Length;
for (int i = 0; i < values.Length; ++i)
{
span[i] = (ushort)values[i];
}
}
// Index用
public int[] GetAsIntArray()
public NativeArray<int> GetAsIntArray()
{
if (AccessorType != AccessorVectorType.SCALAR)
{
@@ -257,104 +217,10 @@ namespace VrmLib
switch (ComponentType)
{
case AccessorValueType.UNSIGNED_SHORT:
{
var span = SpanLike.Wrap<UInt16>(Bytes);
var array = new int[span.Length];
for (int i = 0; i < span.Length; ++i)
{
array[i] = span[i];
}
return array;
}
return ArrayManager.Convert(Bytes.Reinterpret<ushort>(1), (ushort x) => (int)x);
case AccessorValueType.UNSIGNED_INT:
return SpanLike.Wrap<Int32>(Bytes).ToArray();
default:
throw new NotImplementedException();
}
}
public List<int> GetAsIntList()
{
if (AccessorType != AccessorVectorType.SCALAR)
{
throw new InvalidOperationException("not scalar");
}
switch (ComponentType)
{
case AccessorValueType.UNSIGNED_SHORT:
{
var span = SpanLike.Wrap<UInt16>(Bytes);
var array = new List<int>(Count);
if (span.Length != Count)
{
for (int i = 0; i < Count; ++i)
{
array.Add(span[i]);
}
}
else
{
// Spanが動かないWorkAround
var bytes = Bytes.ToArray();
var offset = 0;
for (int i = 0; i < Count; ++i)
{
array.Add(BitConverter.ToUInt16(bytes, offset));
offset += 2;
}
}
return array;
}
case AccessorValueType.UNSIGNED_INT:
return SpanLike.Wrap<Int32>(Bytes).ToArray().ToList();
default:
throw new NotImplementedException();
}
}
// Joints用
public UShort4[] GetAsUShort4()
{
if (AccessorType != AccessorVectorType.VEC4)
{
throw new InvalidOperationException("not vec4");
}
switch (ComponentType)
{
case AccessorValueType.UNSIGNED_SHORT:
return SpanLike.Wrap<UShort4>(Bytes).ToArray();
case AccessorValueType.UNSIGNED_BYTE:
{
var array = new UShort4[Count];
var span = SpanLike.Wrap<Byte4>(Bytes);
for (int i = 0; i < span.Length; ++i)
{
array[i] = new UShort4(span[i].x, span[i].y, span[i].z, span[i].w);
}
return array;
}
default:
throw new NotImplementedException();
}
}
// Weigt用
public Vector4[] GetAsVector4()
{
if (AccessorType != AccessorVectorType.VEC4)
{
throw new InvalidOperationException("not vec4");
}
switch (ComponentType)
{
case AccessorValueType.FLOAT:
return SpanLike.Wrap<Vector4>(Bytes).ToArray();
return Bytes.Reinterpret<Int32>(1);
default:
throw new NotImplementedException();
@@ -374,14 +240,14 @@ namespace VrmLib
void ToByteLength(int byteLength)
{
var newBytes = new byte[byteLength];
Buffer.BlockCopy(Bytes.Array, Bytes.Offset, newBytes, 0, Bytes.Count);
Bytes = new ArraySegment<byte>(newBytes);
var newBytes = ArrayManager.CreateNativeArray<byte>(byteLength);
NativeArray<byte>.Copy(Bytes, newBytes);
Bytes = newBytes;
}
public void Extend(int count)
{
var oldLength = Bytes.Count;
var oldLength = Bytes.Length;
ToByteLength(oldLength + Stride * count);
Count += count;
}
@@ -406,30 +272,17 @@ namespace VrmLib
//ushort to uint
case AccessorValueType.UNSIGNED_SHORT:
{
var src = SpanLike.Wrap<UInt16>(a.Bytes).Slice(0, a.Count);
var bytes = new byte[src.Length * 4];
var dst = SpanLike.Wrap<UInt32>(new ArraySegment<byte>(bytes));
for (int i = 0; i < src.Length; ++i)
{
dst[i] = (uint)src[i];
}
var accessor = new BufferAccessor(new ArraySegment<byte>(bytes), AccessorValueType.UNSIGNED_INT, AccessorVectorType.SCALAR, a.Count);
var bytes = ArrayManager.Convert(a.Bytes.Reinterpret<UInt16>(1), (UInt16 x) => (UInt32)x).Reinterpret<byte>(Marshal.SizeOf<UInt32>());
var accessor = new BufferAccessor(ArrayManager, bytes, AccessorValueType.UNSIGNED_INT, AccessorVectorType.SCALAR, a.Count);
a = accessor;
break;
}
//uint to ushort (おそらく通ることはない)
case AccessorValueType.UNSIGNED_INT:
{
var src = SpanLike.Wrap<UInt32>(a.Bytes).Slice(0, a.Count);
var bytes = new byte[src.Length * 2];
var dst = SpanLike.Wrap<UInt16>(new ArraySegment<byte>(bytes));
for (int i = 0; i < src.Length; ++i)
{
dst[i] = (ushort)src[i];
}
var accessor = new BufferAccessor(new ArraySegment<byte>(bytes), ComponentType, AccessorVectorType.SCALAR, a.Count);
var bytes = ArrayManager.Convert(a.Bytes.Reinterpret<UInt32>(1), (UInt32 x) => (UInt16)x).Reinterpret<byte>(Marshal.SizeOf<UInt16>());
var accessor = new BufferAccessor(ArrayManager, bytes, ComponentType, AccessorVectorType.SCALAR, a.Count);
a = accessor;
break;
}
@@ -441,10 +294,10 @@ namespace VrmLib
}
// 連結した新しいバッファを確保
var oldLength = Bytes.Count;
ToByteLength(oldLength + a.Bytes.Count);
var oldLength = Bytes.Length;
ToByteLength(oldLength + a.Bytes.Length);
// 後ろにコピー
Buffer.BlockCopy(a.Bytes.Array, a.Bytes.Offset, Bytes.Array, Bytes.Offset + oldLength, a.Bytes.Count);
NativeArray<byte>.Copy(a.Bytes, Bytes.GetSubArray(oldLength, Bytes.Length - oldLength));
Count += a.Count;
if (offset > 0)
@@ -454,7 +307,7 @@ namespace VrmLib
{
case AccessorValueType.UNSIGNED_SHORT:
{
var span = SpanLike.Wrap<UInt16>(Bytes.Slice(oldLength));
var span = Bytes.GetSubArray(oldLength, Bytes.Length - oldLength).Reinterpret<UInt16>(1);
var ushortOffset = (ushort)offset;
for (int i = 0; i < span.Length; ++i)
{
@@ -465,7 +318,7 @@ namespace VrmLib
case AccessorValueType.UNSIGNED_INT:
{
var span = SpanLike.Wrap<UInt32>(Bytes.Slice(oldLength));
var span = Bytes.GetSubArray(oldLength, Bytes.Length - oldLength).Reinterpret<UInt32>(1);
var uintOffset = (uint)offset;
for (int i = 0; i < span.Length; ++i)
{
@@ -487,18 +340,16 @@ namespace VrmLib
{
return this;
}
return new BufferAccessor(Bytes.Slice(Stride * skipFrames), ComponentType, AccessorType, Count - skipFrames);
var start = Stride * skipFrames;
return new BufferAccessor(ArrayManager, Bytes.GetSubArray(start, Bytes.Length - start), ComponentType, AccessorType, Count - skipFrames);
}
public BufferAccessor CloneWithOffset(int offsetCount)
{
var offsetSize = Stride * offsetCount;
var buffer = new byte[offsetSize + Bytes.Count];
Buffer.BlockCopy(Bytes.Array, Bytes.Offset, buffer, offsetSize, Bytes.Count);
return new BufferAccessor(new ArraySegment<byte>(buffer), ComponentType, AccessorType, Count + offsetCount);
var buffer = ArrayManager.CreateNativeArray<byte>(offsetSize + Bytes.Length);
NativeArray<byte>.Copy(Bytes, buffer.GetSubArray(offsetSize, buffer.Length - offsetSize));
return new BufferAccessor(ArrayManager, buffer, ComponentType, AccessorType, Count + offsetCount);
}
public void AddTo(Dictionary<string, BufferAccessor> dict, string key)

View File

@@ -4,6 +4,7 @@ using System.Linq;
using System.Numerics;
using System.Text;
using UniGLTF;
using Unity.Collections;
namespace VrmLib
{
@@ -65,7 +66,7 @@ namespace VrmLib
/// indicesの最大値が65535未満(-1を避ける)ならばushort 型で、
/// そうでなければ int型で IndexBufferを代入する
/// </summary>
public void AssignIndexBuffer(SpanLike<int> indices)
public void AssignIndexBuffer(NativeArray<int> indices)
{
bool isInt = false;
foreach (var i in indices)
@@ -247,8 +248,8 @@ namespace VrmLib
{
m.Translation = Vector3.Zero;
var position = SpanLike.Wrap<Vector3>(VertexBuffer.Positions.Bytes);
var normal = SpanLike.Wrap<Vector3>(VertexBuffer.Normals.Bytes);
var position = VertexBuffer.Positions.Bytes.Reinterpret<Vector3>(1);
var normal = VertexBuffer.Normals.Bytes.Reinterpret<Vector3>(1);
for (int i = 0; i < position.Length; ++i)
{

View File

@@ -4,6 +4,7 @@ using System.Linq;
using System.Numerics;
using System.Text;
using UniGLTF;
using Unity.Collections;
namespace VrmLib
{
@@ -222,61 +223,9 @@ namespace VrmLib
this.Nodes.Remove(remove);
}
/// <summary>
/// Nodeを置き換える。参照を置換する。
/// </summary>
public void NodeReplace(Node src, Node dst)
{
if (src == null)
{
throw new ArgumentNullException();
}
if (dst == null)
{
throw new ArgumentNullException();
}
// add dst same parent
src.Parent.Add(dst, ChildMatrixMode.KeepWorld);
// remove all child
foreach (var child in src.Children.ToArray())
{
dst.Add(child, ChildMatrixMode.KeepWorld);
}
// remove from parent
src.Parent.Remove(src);
this.Nodes.Remove(src);
// remove from skinning
foreach (var skin in this.Skins)
{
skin.Replace(src, dst);
}
// fix animation reference
foreach (var animation in this.Animations)
{
if (animation.NodeMap.TryGetValue(src, out NodeAnimation nodeAnimation))
{
animation.NodeMap.Remove(src);
animation.NodeMap.Add(dst, nodeAnimation);
}
}
if (this.Nodes.Contains(dst))
{
throw new Exception("already exists");
}
this.Nodes.Add(dst);
// TODO: SpringBone
}
#endregion
public string SkinningBake()
public string SkinningBake(INativeArrayManager arrayManager)
{
foreach (var node in this.Nodes)
{
@@ -294,7 +243,7 @@ namespace VrmLib
{
{
// Skinningの出力先を自身にすることでBakeする
meshGroup.Skin.Skinning(mesh.VertexBuffer);
meshGroup.Skin.Skinning(arrayManager, mesh.VertexBuffer);
}
// morphのPositionは相対値が入っているはずなので、手を加えない正規化されていない場合、二重に補正が掛かる
@@ -339,7 +288,7 @@ namespace VrmLib
{
if (meshGroup.Skin != null)
{
meshGroup.Skin.CalcInverseMatrices();
meshGroup.Skin.CalcInverseMatrices(arrayManager);
}
}
}
@@ -355,7 +304,7 @@ namespace VrmLib
}
if (ba.AccessorType == AccessorVectorType.VEC3)
{
var span = SpanLike.Wrap<Vector3>(ba.Bytes);
var span = ba.Bytes.Reinterpret<Vector3>(1);
for (int i = 0; i < span.Length; ++i)
{
span[i] = span[i].ReverseX();
@@ -363,7 +312,7 @@ namespace VrmLib
}
else if (ba.AccessorType == AccessorVectorType.MAT4)
{
var span = SpanLike.Wrap<Matrix4x4>(ba.Bytes);
var span = ba.Bytes.Reinterpret<Matrix4x4>(1);
for (int i = 0; i < span.Length; ++i)
{
span[i] = span[i].ReverseX();
@@ -383,7 +332,7 @@ namespace VrmLib
}
if (ba.AccessorType == AccessorVectorType.VEC3)
{
var span = SpanLike.Wrap<Vector3>(ba.Bytes);
var span = ba.Bytes.Reinterpret<Vector3>(1);
for (int i = 0; i < span.Length; ++i)
{
span[i] = span[i].ReverseZ();
@@ -391,7 +340,7 @@ namespace VrmLib
}
else if (ba.AccessorType == AccessorVectorType.MAT4)
{
var span = SpanLike.Wrap<Matrix4x4>(ba.Bytes);
var span = ba.Bytes.Reinterpret<Matrix4x4>(1);
for (int i = 0; i < span.Length; ++i)
{
span[i] = span[i].ReverseZ();
@@ -476,7 +425,7 @@ namespace VrmLib
var uv = m.VertexBuffer.TexCoords;
if (uv != null)
{
var span = SpanLike.Wrap<Vector2>(uv.Bytes);
var span = uv.Bytes.Reinterpret<Vector2>(1);
for (int i = 0; i < span.Length; ++i)
{
span[i] = span[i].UVVerticalFlip();
@@ -495,14 +444,16 @@ namespace VrmLib
{
// 複数の gltf.accessor が別の要素間で共有されている場合に、2回処理されることを防ぐ
// edgecase: InverseBindMatrices で遭遇
var unique = new HashSet<ArraySegment<byte>>();
var unique = new HashSet<NativeArray<byte>>();
foreach (var g in MeshGroups)
{
foreach (var m in g.Meshes)
{
foreach (var (k, v) in m.VertexBuffer)
foreach (var kv in m.VertexBuffer)
{
var k = kv.Key;
var v = kv.Value;
if (k == VertexBuffer.PositionKey || k == VertexBuffer.NormalKey)
{
if (unique.Add(v.Bytes))
@@ -521,13 +472,13 @@ namespace VrmLib
switch (m.IndexBuffer.ComponentType)
{
case AccessorValueType.UNSIGNED_BYTE:
FlipTriangle(SpanLike.Wrap<Byte>(m.IndexBuffer.Bytes));
FlipTriangle(m.IndexBuffer.Bytes);
break;
case AccessorValueType.UNSIGNED_SHORT:
FlipTriangle(SpanLike.Wrap<UInt16>(m.IndexBuffer.Bytes));
FlipTriangle(m.IndexBuffer.Bytes.Reinterpret<UInt16>(1));
break;
case AccessorValueType.UNSIGNED_INT:
FlipTriangle(SpanLike.Wrap<UInt32>(m.IndexBuffer.Bytes));
FlipTriangle(m.IndexBuffer.Bytes.Reinterpret<UInt32>(1));
break;
default:
throw new NotImplementedException();
@@ -536,8 +487,10 @@ namespace VrmLib
foreach (var mt in m.MorphTargets)
{
foreach (var (k, v) in mt.VertexBuffer)
foreach (var kv in mt.VertexBuffer)
{
var k = kv.Key;
var v = kv.Value;
if (k == VertexBuffer.PositionKey || k == VertexBuffer.NormalKey)
{
if (unique.Add(v.Bytes))
@@ -580,7 +533,7 @@ namespace VrmLib
}
}
static void FlipTriangle(SpanLike<byte> indices)
static void FlipTriangle(NativeArray<byte> indices)
{
for (int i = 0; i < indices.Length; i += 3)
{
@@ -591,7 +544,7 @@ namespace VrmLib
}
}
static void FlipTriangle(SpanLike<ushort> indices)
static void FlipTriangle(NativeArray<ushort> indices)
{
for (int i = 0; i < indices.Length; i += 3)
{
@@ -602,7 +555,7 @@ namespace VrmLib
}
}
static void FlipTriangle(SpanLike<uint> indices)
static void FlipTriangle(NativeArray<uint> indices)
{
for (int i = 0; i < indices.Length; i += 3)
{

View File

@@ -25,7 +25,7 @@ namespace VrmLib
{
if (In.ComponentType == AccessorValueType.FLOAT)
{
var times = SpanLike.Wrap<Single>(In.Bytes);
var times = In.Bytes.Reinterpret<Single>(1);
return times[times.Length - 1];
}
else

View File

@@ -5,6 +5,7 @@ using System.Numerics;
using System.Runtime.InteropServices;
using System.Text;
using UniGLTF;
using Unity.Collections;
namespace VrmLib
{
@@ -29,7 +30,7 @@ namespace VrmLib
/// <summary>
/// BoneSkinningもしくはMorphTargetの適用
/// <summary>
public void Skinning(VertexBuffer vertexBuffer = null)
public void Skinning(INativeArrayManager arrayManager, VertexBuffer vertexBuffer = null)
{
m_indexOfRoot = (ushort)Joints.IndexOf(Root);
var addRoot = Root != null && m_indexOfRoot == ushort.MaxValue;
@@ -46,13 +47,13 @@ namespace VrmLib
if (InverseMatrices == null)
{
CalcInverseMatrices();
CalcInverseMatrices(arrayManager);
}
else
{
if (addRoot)
{
var inverseArray = SpanLike.Wrap<Matrix4x4>(InverseMatrices.Bytes).ToArray();
var inverseArray = InverseMatrices.Bytes.Reinterpret<Matrix4x4>(1);
var concat = inverseArray.Concat(new[] { Root.InverseMatrix }).ToArray();
InverseMatrices.Assign(concat);
}
@@ -80,33 +81,33 @@ namespace VrmLib
if (vertexBuffer != null)
{
Apply(vertexBuffer);
Apply(arrayManager, vertexBuffer);
}
}
void Apply(VertexBuffer vertexBuffer)
void Apply(INativeArrayManager arrayManager, VertexBuffer vertexBuffer)
{
var dstPosition = SpanLike.Wrap<Vector3>(vertexBuffer.Positions.Bytes);
var dstPosition = vertexBuffer.Positions.Bytes.Reinterpret<Vector3>(1);
// Span<Vector3> emptyNormal = stackalloc Vector3[0];
Apply(vertexBuffer, dstPosition, vertexBuffer.Normals != null ? SpanLike.Wrap<Vector3>(vertexBuffer.Normals.Bytes) : default);
Apply(arrayManager, vertexBuffer, dstPosition, vertexBuffer.Normals != null ? vertexBuffer.Normals.Bytes.Reinterpret<Vector3>(1) : default);
}
public void Apply(VertexBuffer vertexBuffer, SpanLike<Vector3> dstPosition, SpanLike<Vector3> dstNormal)
public void Apply(INativeArrayManager arrayManager, VertexBuffer vertexBuffer, NativeArray<Vector3> dstPosition, NativeArray<Vector3> dstNormal)
{
var jointsBuffer = vertexBuffer.Joints;
var joints = (jointsBuffer != null || jointsBuffer.Count == 0)
? SpanLike.Wrap<SkinJoints>(jointsBuffer.Bytes)
: SpanLike.Create<SkinJoints>(vertexBuffer.Count) // when MorphTarget only
? jointsBuffer.Bytes.Reinterpret<SkinJoints>(1)
: arrayManager.CreateNativeArray<SkinJoints>(vertexBuffer.Count) // when MorphTarget only
;
var weightsBuffer = vertexBuffer.Weights;
var weights = (weightsBuffer != null || weightsBuffer.Count == 0)
? SpanLike.Wrap<Vector4>(weightsBuffer.Bytes)
: SpanLike.Create<Vector4>(vertexBuffer.Count) // when MorphTarget only
? weightsBuffer.Bytes.Reinterpret<Vector4>(1)
: arrayManager.CreateNativeArray<Vector4>(vertexBuffer.Count) // when MorphTarget only
;
var positionBuffer = vertexBuffer.Positions;
var position = SpanLike.Wrap<Vector3>(positionBuffer.Bytes);
var position = positionBuffer.Bytes.Reinterpret<Vector3>(1);
bool useNormal = false;
if (dstNormal.Length > 0)
@@ -148,7 +149,7 @@ namespace VrmLib
if (useNormal)
{
var normalBuffer = vertexBuffer.Normals;
var normal = normalBuffer != null ? SpanLike.Wrap<Vector3>(normalBuffer.Bytes) : dstNormal;
var normal = normalBuffer != null ? normalBuffer.Bytes.Reinterpret<Vector3>(1) : dstNormal;
var src = new Vector4(normal[i], 0); // 方向ベクトル
var dst = Vector4.Zero;
if (w.X > 0) dst += Vector4.Transform(src, m_matrices[j.Joint0]) * w.X * factor;
@@ -190,7 +191,7 @@ namespace VrmLib
if (InverseMatrices != null)
{
var sb = new StringBuilder();
var matrices = SpanLike.Wrap<Matrix4x4>(InverseMatrices.Bytes);
var matrices = InverseMatrices.Bytes.Reinterpret<Matrix4x4>(1);
var count = 0;
// var rootMatrix = Matrix4x4.Identity;
// if (Root != null)
@@ -221,7 +222,7 @@ namespace VrmLib
}
}
public void Replace(Node src, Node dst)
public void Replace(INativeArrayManager arrayManager, Node src, Node dst)
{
var removeIndex = Joints.IndexOf(src);
if (removeIndex >= 0)
@@ -229,11 +230,11 @@ namespace VrmLib
Joints[removeIndex] = dst;
// エクスポート時に再計算させる
CalcInverseMatrices();
CalcInverseMatrices(arrayManager);
}
}
public void CalcInverseMatrices()
public void CalcInverseMatrices(INativeArrayManager arrayManager)
{
// var root = Root;
// if (root == null)
@@ -243,8 +244,8 @@ namespace VrmLib
// root.CalcWorldMatrix(Matrix4x4.Identity, true);
// calc inverse bind matrices
var matricesBytes = new Byte[Marshal.SizeOf(typeof(Matrix4x4)) * Joints.Count];
var matrices = SpanLike.Wrap<Matrix4x4>(new ArraySegment<byte>(matricesBytes));
var matricesBytes = arrayManager.CreateNativeArray<Byte>(Marshal.SizeOf(typeof(Matrix4x4)) * Joints.Count);
var matrices = matricesBytes.Reinterpret<Matrix4x4>(1);
for (int i = 0; i < Joints.Count; ++i)
{
// var w = Joints[i].Matrix;
@@ -254,7 +255,7 @@ namespace VrmLib
matrices[i] = Joints[i].InverseMatrix;
}
}
InverseMatrices = new BufferAccessor(new ArraySegment<byte>(matricesBytes), AccessorValueType.FLOAT, AccessorVectorType.MAT4, Joints.Count);
InverseMatrices = new BufferAccessor(arrayManager, matricesBytes, AccessorValueType.FLOAT, AccessorVectorType.MAT4, Joints.Count);
}
static void Update(ref float weight, ref ushort index, int[] indexMap)
@@ -275,39 +276,5 @@ namespace VrmLib
index = (ushort)indexMap[index];
}
}
/// <summary>
/// nullになったjointを除去して、boneweightを前に詰める
/// </summary>
public void FixBoneWeight(BufferAccessor jointsAccessor, BufferAccessor weightsAccessor)
{
var map = Joints.Select((x, i) => ValueTuple.Create(i, x)).Where(x => x.Item2 != null).ToArray();
var indexMap = Enumerable.Repeat(-1, Joints.Count).ToArray();
{
for (int i = 0; i < map.Length; ++i)
{
indexMap[map[i].Item1] = i;
}
}
Joints.RemoveAll(x => x == null);
var joints = jointsAccessor.GetSpan<SkinJoints>();
var weights = weightsAccessor.GetSpan<Vector4>();
for (int i = 0; i < joints.Length; ++i)
{
var j = joints[i];
var w = weights[i];
Update(ref w.X, ref j.Joint0, indexMap);
Update(ref w.Y, ref j.Joint1, indexMap);
Update(ref w.Z, ref j.Joint2, indexMap);
Update(ref w.W, ref j.Joint3, indexMap);
joints[i] = j;
weights[i] = w;
}
CalcInverseMatrices();
}
}
}
}

View File

@@ -2,9 +2,6 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Runtime.InteropServices;
using UniGLTF;
namespace VrmLib
{
@@ -185,107 +182,5 @@ namespace VrmLib
public VertexBuffer()
{
}
public VertexBuffer CloneWithOffset(int offsetCount)
{
var vb = new VertexBuffer();
foreach (var kv in VertexBuffers)
{
vb.VertexBuffers[kv.Key] = kv.Value.CloneWithOffset(offsetCount);
}
return vb;
}
public SpanLike<SkinJoints> GetOrCreateJoints()
{
var buffer = Joints;
if (buffer == null)
{
buffer = new BufferAccessor(
new ArraySegment<byte>(new byte[Marshal.SizeOf(typeof(SkinJoints)) * Count]),
AccessorValueType.UNSIGNED_SHORT,
AccessorVectorType.VEC4, Count);
Add(JointKey, buffer);
}
return SpanLike.Wrap<SkinJoints>(buffer.Bytes);
}
public SpanLike<Vector4> GetOrCreateWeights()
{
var buffer = Weights;
if (buffer == null)
{
buffer = new BufferAccessor(
new ArraySegment<byte>(new byte[Marshal.SizeOf(typeof(Vector4)) * Count]),
AccessorValueType.FLOAT,
AccessorVectorType.VEC4, Count);
Add(WeightKey, buffer);
}
return SpanLike.Wrap<Vector4>(buffer.Bytes);
}
static bool HasSameKeys<T>(Dictionary<string, T> lhs, Dictionary<string, T> rhs)
{
if (lhs.Count != rhs.Count) return false;
foreach (var (l, r) in Enumerable.Zip(lhs.Keys.OrderBy(x => x), rhs.Keys.OrderBy(x => x), (l, r) => (l, r)))
{
if (l != r)
{
return false;
}
}
return true;
}
public void Append(VertexBuffer v)
{
var keys = VertexBuffers.Keys.ToList();
var lastCount = Count;
// v から VertexBufferfs に足す
foreach (var kv in v.VertexBuffers)
{
if (VertexBuffers.TryGetValue(kv.Key, out BufferAccessor buffer))
{
// used
keys.Remove(kv.Key);
if (buffer.Count != lastCount)
{
throw new ArgumentException();
}
}
else
{
// add empty
var byteLength = lastCount * kv.Value.Stride;
buffer = new BufferAccessor(new ArraySegment<byte>(new byte[byteLength]), kv.Value.ComponentType, kv.Value.AccessorType, lastCount);
if (buffer.Count != lastCount)
{
throw new ArgumentException();
}
VertexBuffers.Add(kv.Key, buffer);
}
buffer.Append(kv.Value);
}
// 足されなかったキーに同じ長さを詰める
foreach (var key in keys)
{
var dst = VertexBuffers[key];
dst.Extend(v.Positions.Count);
}
ValidateLength();
}
public void Resize(int n)
{
foreach (var kv in VertexBuffers)
{
kv.Value.Resize(n);
}
}
}
}
}

View File

@@ -20,15 +20,15 @@ namespace VrmLibTests
model.NodeAdd(node1, node0);
Assert.AreEqual(2, model.Nodes.Count);
var node2 = new Node("node2");
model.NodeReplace(node0, node2);
Assert.AreEqual(2, model.Nodes.Count);
Assert.AreEqual(node2, model.Nodes[1]);
Assert.AreEqual(1, node2.Children.Count);
// var node2 = new Node("node2");
// model.NodeReplace(node0, node2);
// Assert.AreEqual(2, model.Nodes.Count);
// Assert.AreEqual(node2, model.Nodes[1]);
// Assert.AreEqual(1, node2.Children.Count);
model.NodeRemove(node1);
Assert.AreEqual(1, model.Nodes.Count);
Assert.AreEqual(0, node2.Children.Count);
// model.NodeRemove(node1);
// Assert.AreEqual(1, model.Nodes.Count);
// Assert.AreEqual(0, node2.Children.Count);
}
}
}