mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-09-11 21:38:56 -05:00
Merge pull request #1523 from ousttrue/fix10/spanlike_to_nativearray
SpanLike を NativeArray で置き換える
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f857b8b7ca45b1746af90c7fb86b2398
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2ce69a95857efe041a1e3dd9d2e6c98b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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管理する。
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8ef774aa861dc6f46a94330c7169bf04
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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,
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace UniGLTF
|
||||
{
|
||||
protected ExportingGltfData _data;
|
||||
|
||||
protected glTF _gltf => _data.GLTF;
|
||||
protected glTF _gltf => _data.Gltf;
|
||||
|
||||
public GameObject Copy
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f70b7312ba0d32b4493231c6f8a42e4c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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()))
|
||||
{
|
||||
|
||||
@@ -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 = */
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 53bfc0b12550a494e8da90e632e1c456
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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}");
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user