GltfData.Bin を ArraySegment<byte> から NatriveArray<byte> に置き換え。Dispose の責務が発生したが、ImporterContext が Dispose することにした。

This commit is contained in:
ousttrue
2022-01-25 18:03:10 +09:00
parent 64d6a6bde4
commit ab0964293f
11 changed files with 200 additions and 156 deletions

View File

@@ -2,7 +2,7 @@
using System.Linq;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Unity.Collections;
namespace UniGLTF
{
@@ -102,7 +102,7 @@ namespace UniGLTF
public static class ListExtensions
{
public static void Assign<T>(this List<T> dst, T[] src, Func<T, T> pred)
public static void Assign<T>(this List<T> dst, NativeArray<T> src, Func<T, T> pred) where T : struct
{
dst.Capacity = src.Length;
dst.AddRange(src.Select(pred));

View File

@@ -208,8 +208,8 @@ namespace UniGLTF
clip,
relativePath,
new string[] { "localPosition.x", "localPosition.y", "localPosition.z" },
input,
output,
input.ToArray(),
output.ToArray(),
sampler.interpolation,
typeof(Transform),
(values, last) =>
@@ -231,8 +231,8 @@ namespace UniGLTF
clip,
relativePath,
new string[] { "localRotation.x", "localRotation.y", "localRotation.z", "localRotation.w" },
input,
output,
input.ToArray(),
output.ToArray(),
sampler.interpolation,
typeof(Transform),
(values, last) =>
@@ -257,8 +257,8 @@ namespace UniGLTF
clip,
relativePath,
new string[] { "localScale.x", "localScale.y", "localScale.z" },
input,
output,
input.ToArray(),
output.ToArray(),
sampler.interpolation,
typeof(Transform),
(values, last) => values);
@@ -289,8 +289,8 @@ namespace UniGLTF
clip,
relativePath,
keyNames,
input,
output,
input.ToArray(),
output.ToArray(),
sampler.interpolation,
typeof(SkinnedMeshRenderer),
(values, last) =>

View File

@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using Unity.Collections;
namespace UniGLTF
{
@@ -9,7 +10,7 @@ namespace UniGLTF
/// * JSON is parsed but not validated as glTF
/// * For glb, bin chunks are already available
/// </summary>
public sealed class GltfData
public sealed class GltfData : IDisposable
{
/// <summary>
/// Source file path.
@@ -43,21 +44,7 @@ namespace UniGLTF
/// > This chunk MUST be the second chunk of the Binary glTF asset
/// </summary>
/// <returns></returns>
public ArraySegment<byte> Bin
{
get
{
if (Chunks == null)
{
return default;
}
if (Chunks.Count < 2)
{
return default;
}
return Chunks[1].Bytes;
}
}
public readonly NativeArray<byte> Bin;
/// <summary>
/// Migration Flags used by ImporterContext
@@ -74,7 +61,7 @@ namespace UniGLTF
/// uri = 相対パス。File.ReadAllBytes
/// </summary>
/// <returns></returns>
Dictionary<string, ArraySegment<byte>> _UriCache = new Dictionary<string, ArraySegment<byte>>();
Dictionary<string, NativeArray<byte>> _UriCache = new Dictionary<string, NativeArray<byte>>();
public GltfData(string targetPath, string json, glTF gltf, IReadOnlyList<GlbChunk> chunks, IStorage storage, MigrationFlags migrationFlags)
{
@@ -84,6 +71,14 @@ namespace UniGLTF
Chunks = chunks;
_storage = storage;
MigrationFlags = migrationFlags;
if (Chunks != null)
{
if (Chunks.Count >= 2)
{
Bin = CreateNativeArray(Chunks[1].Bytes);
}
}
}
public static GltfData CreateFromExportForTest(ExportingGltfData data)
@@ -107,14 +102,14 @@ namespace UniGLTF
);
}
ArraySegment<Byte> GetBytesFromUri(string uri)
NativeArray<Byte> GetBytesFromUri(string uri)
{
if (string.IsNullOrEmpty(uri))
{
throw new ArgumentNullException();
}
if (_UriCache.TryGetValue(uri, out ArraySegment<byte> data))
if (_UriCache.TryGetValue(uri, out NativeArray<byte> data))
{
// return cache
return data;
@@ -122,20 +117,20 @@ namespace UniGLTF
if (uri.StartsWith("data:", StringComparison.Ordinal))
{
data = new ArraySegment<byte>(UriByteBuffer.ReadEmbedded(uri));
data = CreateNativeArray(UriByteBuffer.ReadEmbedded(uri));
}
else
{
data = _storage.Get(uri);
data = CreateNativeArray(_storage.Get(uri));
}
_UriCache.Add(uri, data);
return data;
}
public ArraySegment<Byte> GetBytesFromBuffer(int bufferIndex)
public NativeArray<Byte> GetBytesFromBuffer(int bufferIndex)
{
var buffer = GLTF.buffers[bufferIndex];
if (bufferIndex == 0 && Bin.Array != null)
if (bufferIndex == 0 && Bin.IsCreated)
{
// https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#glb-stored-buffer
return Bin;
@@ -146,23 +141,20 @@ namespace UniGLTF
}
}
public ArraySegment<Byte> GetBytesFromBufferView(int bufferView)
public NativeArray<Byte> GetBytesFromBufferView(int bufferView)
{
var view = GLTF.bufferViews[bufferView];
var segment = GetBytesFromBuffer(view.buffer);
return new ArraySegment<byte>(segment.Array, segment.Offset + view.byteOffset, view.byteLength);
return segment.GetSubArray(view.byteOffset, view.byteLength);
}
T[] GetTypedFromBufferView<T>(int count, int byteOffset, glTFBufferView view) where T : struct
NativeArray<T> GetTypedFromBufferView<T>(int count, int byteOffset, glTFBufferView view) where T : struct
{
var segment = GetBytesFromBuffer(view.buffer);
var attrib = new T[count];
var bytes = new ArraySegment<Byte>(segment.Array, segment.Offset + view.byteOffset + byteOffset, count * Marshal.SizeOf<T>());
SafeMarshalCopy.CopyBytesToArray(bytes, attrib);
return attrib;
return segment.GetSubArray(view.byteOffset + byteOffset, count * Marshal.SizeOf<T>()).Reinterpret<T>(1);
}
T[] GetTypedFromAccessor<T>(glTFAccessor accessor, glTFBufferView view) where T : struct
NativeArray<T> GetTypedFromAccessor<T>(glTFAccessor accessor, glTFBufferView view) where T : struct
{
return GetTypedFromBufferView<T>(accessor.count, accessor.byteOffset, view);
}
@@ -247,15 +239,15 @@ namespace UniGLTF
return indices;
}
public T[] GetArrayFromAccessor<T>(int accessorIndex) where T : struct
public NativeArray<T> GetArrayFromAccessor<T>(int accessorIndex) where T : struct
{
var vertexAccessor = GLTF.accessors[accessorIndex];
if (vertexAccessor.count <= 0) return new T[] { };
if (vertexAccessor.count <= 0) return CreateNativeArray<T>(0);
var result = (vertexAccessor.bufferView != -1)
? GetTypedFromAccessor<T>(vertexAccessor, GLTF.bufferViews[vertexAccessor.bufferView])
: new T[vertexAccessor.count]
: CreateNativeArray<T>(vertexAccessor.count)
;
var sparse = vertexAccessor.sparse;
@@ -275,27 +267,24 @@ namespace UniGLTF
return result;
}
public float[] FlatternFloatArrayFromAccessor(int accessorIndex)
public NativeArray<float> FlatternFloatArrayFromAccessor(int accessorIndex)
{
var vertexAccessor = GLTF.accessors[accessorIndex];
if (vertexAccessor.count <= 0) return new float[] { };
if (vertexAccessor.count <= 0) return CreateNativeArray<float>(0);
var bufferCount = vertexAccessor.count * vertexAccessor.TypeCount;
float[] result = null;
NativeArray<float> result = default;
if (vertexAccessor.bufferView != -1)
{
var attrib = new float[vertexAccessor.count * vertexAccessor.TypeCount];
var view = GLTF.bufferViews[vertexAccessor.bufferView];
var segment = GetBytesFromBuffer(view.buffer);
var bytes = new ArraySegment<Byte>(segment.Array, segment.Offset + view.byteOffset + vertexAccessor.byteOffset, vertexAccessor.count * 4 * vertexAccessor.TypeCount);
SafeMarshalCopy.CopyBytesToArray(bytes, attrib);
result = attrib;
result = segment.GetSubArray(view.byteOffset + vertexAccessor.byteOffset, vertexAccessor.count * 4 * vertexAccessor.TypeCount).Reinterpret<float>(1);
}
else
{
result = new float[bufferCount];
result = CreateNativeArray<float>(bufferCount);
}
var sparse = vertexAccessor.sparse;
@@ -315,7 +304,7 @@ namespace UniGLTF
return result;
}
public (ArraySegment<byte> binary, string mimeType)? GetBytesFromImage(int imageIndex)
public (NativeArray<byte> binary, string mimeType)? GetBytesFromImage(int imageIndex)
{
if (imageIndex < 0 || imageIndex >= GLTF.images.Count) return default;
@@ -373,5 +362,46 @@ namespace UniGLTF
return false;
}
/// <summary>
/// NativeArrayを新規作成し、Dispose管理する。
/// 個別にDisposeする必要が無い。
/// </summary>
/// <param name="size"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public NativeArray<T> CreateNativeArray<T>(int size) where T : struct
{
var array = new NativeArray<T>(size, Allocator.Persistent);
m_disposables.Add(array);
return array;
}
NativeArray<T> CreateNativeArray<T>(ArraySegment<T> data) where T : struct
{
var array = CreateNativeArray<T>(data.Count);
// TODO: remove ToArray
array.CopyFrom(data.ToArray());
return array;
}
NativeArray<T> CreateNativeArray<T>(T[] data) where T : struct
{
var array = CreateNativeArray<T>(data.Length);
array.CopyFrom(data);
return array;
}
List<IDisposable> m_disposables = new List<IDisposable>();
public void Dispose()
{
foreach (var disposable in m_disposables)
{
disposable.Dispose();
}
m_disposables.Clear();
_UriCache.Clear();
}
}
}

View File

@@ -330,6 +330,9 @@ namespace UniGLTF
AnimationClipFactory?.Dispose();
MaterialFactory?.Dispose();
TextureFactory?.Dispose();
// OK ?
Data.Dispose();
}
/// <summary>

View File

@@ -142,7 +142,7 @@ namespace UniGLTF
for (var i = 0; i < positions.Length; ++i)
{
var position = inverter.InvertVector3(positions[i]);
var normal = normals != null ? inverter.InvertVector3(normals[i]) : Vector3.zero;
var normal = normals != null ? inverter.InvertVector3(normals.Value[i]) : Vector3.zero;
var texCoord0 = Vector2.zero;
if (texCoords0 != null)
@@ -151,20 +151,20 @@ namespace UniGLTF
{
#pragma warning disable 0612
// backward compatibility
texCoord0 = texCoords0[i].ReverseY();
texCoord0 = texCoords0.Value[i].ReverseY();
#pragma warning restore 0612
}
else
{
texCoord0 = texCoords0[i].ReverseUV();
texCoord0 = texCoords0.Value[i].ReverseUV();
}
}
var texCoord1 = texCoords1 != null ? texCoords1[i].ReverseUV() : Vector2.zero;
var texCoord1 = texCoords1 != null ? texCoords1.Value[i].ReverseUV() : Vector2.zero;
var joints = jointsGetter?.Invoke(i) ?? (0, 0, 0, 0);
var weights = weightsGetter != null ? NormalizeBoneWeight(weightsGetter(i)) : (0, 0, 0, 0);
var color = colors != null ? colors[i] : Color.white;
var color = colors != null ? colors.Value[i] : Color.white;
_vertices.Add(
new MeshVertex(
position,
@@ -285,24 +285,24 @@ namespace UniGLTF
for (var i = 0; i < positions.Length; ++i)
{
var position = inverter.InvertVector3(positions[i]);
var normal = normals != null ? inverter.InvertVector3(normals[i]) : Vector3.zero;
var normal = normals != null ? inverter.InvertVector3(normals.Value[i]) : Vector3.zero;
var texCoord0 = Vector2.zero;
if (texCoords0 != null)
{
if (data.GLTF.IsGeneratedUniGLTFAndOlder(1, 16))
{
#pragma warning disable 0612
texCoord0 = texCoords0[i].ReverseY();
texCoord0 = texCoords0.Value[i].ReverseY();
#pragma warning restore 0612
}
else
{
texCoord0 = texCoords0[i].ReverseUV();
texCoord0 = texCoords0.Value[i].ReverseUV();
}
}
var texCoord1 = texCoords1 != null ? texCoords1[i].ReverseUV() : Vector2.zero;
var color = colors != null ? colors[i] : Color.white;
var texCoord1 = texCoords1 != null ? texCoords1.Value[i].ReverseUV() : Vector2.zero;
var color = colors != null ? colors.Value[i] : Color.white;
var joints = jointsGetter?.Invoke(i) ?? (0, 0, 0, 0);
var weights = weightsGetter != null ? NormalizeBoneWeight(weightsGetter(i)) : (0, 0, 0, 0);

View File

@@ -1,4 +1,5 @@
using System;
using Unity.Collections;
using UnityEngine;
namespace UniGLTF
@@ -11,12 +12,12 @@ namespace UniGLTF
public static bool HasSkin(this glTFPrimitives primitives) => primitives.attributes.JOINTS_0 != -1 && primitives.attributes.WEIGHTS_0 != -1;
public static bool HasColor(this glTFPrimitives primitives) => primitives.attributes.COLOR_0 != -1;
public static Vector3[] GetPositions(this glTFPrimitives primitives, GltfData data)
public static NativeArray<Vector3> GetPositions(this glTFPrimitives primitives, GltfData data)
{
return data.GetArrayFromAccessor<Vector3>(primitives.attributes.POSITION);
}
public static Vector3[] GetNormals(this glTFPrimitives primitives, GltfData data, int positionsLength)
public static NativeArray<Vector3>? GetNormals(this glTFPrimitives primitives, GltfData data, int positionsLength)
{
if (!HasNormal(primitives)) return null;
var result = data.GetArrayFromAccessor<Vector3>(primitives.attributes.NORMAL);
@@ -28,7 +29,7 @@ namespace UniGLTF
return result;
}
public static Vector2[] GetTexCoords0(this glTFPrimitives primitives, GltfData data, int positionsLength)
public static NativeArray<Vector2>? GetTexCoords0(this glTFPrimitives primitives, GltfData data, int positionsLength)
{
if (!HasTexCoord0(primitives)) return null;
var result = data.GetArrayFromAccessor<Vector2>(primitives.attributes.TEXCOORD_0);
@@ -39,8 +40,8 @@ namespace UniGLTF
return result;
}
public static Vector2[] GetTexCoords1(this glTFPrimitives primitives, GltfData data, int positionsLength)
public static NativeArray<Vector2>? GetTexCoords1(this glTFPrimitives primitives, GltfData data, int positionsLength)
{
if (!HasTexCoord1(primitives)) return null;
var result = data.GetArrayFromAccessor<Vector2>(primitives.attributes.TEXCOORD_1);
@@ -48,33 +49,33 @@ namespace UniGLTF
{
throw new Exception("different length");
}
return result;
}
public static Color[] GetColors(this glTFPrimitives primitives, GltfData data, int positionsLength)
public static NativeArray<Color>? GetColors(this glTFPrimitives primitives, GltfData data, int positionsLength)
{
if (!HasColor(primitives)) return null;
switch (data.GLTF.accessors[primitives.attributes.COLOR_0].TypeCount)
{
case 3:
{
var vec3Color = data.GetArrayFromAccessor<Vector3>(primitives.attributes.COLOR_0);
if (vec3Color.Length != positionsLength)
{
throw new Exception("different length");
}
var colors = new Color[vec3Color.Length];
var vec3Color = data.GetArrayFromAccessor<Vector3>(primitives.attributes.COLOR_0);
if (vec3Color.Length != positionsLength)
{
throw new Exception("different length");
}
var colors = data.CreateNativeArray<Color>(vec3Color.Length);
for (var index = 0; index < vec3Color.Length; index++)
{
var color = vec3Color[index];
colors[index] = new Color(color.x, color.y, color.z);
}
for (var index = 0; index < vec3Color.Length; index++)
{
var color = vec3Color[index];
colors[index] = new Color(color.x, color.y, color.z);
}
return colors;
}
return colors;
}
case 4:
var result = data.GetArrayFromAccessor<Color>(primitives.attributes.COLOR_0);
if (result.Length != positionsLength)
@@ -89,7 +90,7 @@ namespace UniGLTF
}
}
public static JointsAccessor.Getter GetJoints(this glTFPrimitives primitives, GltfData data, int positionsLength)
public static JointsAccessor.Getter GetJoints(this glTFPrimitives primitives, GltfData data, int positionsLength)
{
// skin
if (!HasSkin(primitives)) return null;

View File

@@ -1,5 +1,6 @@
using System;
using System.Threading.Tasks;
using Unity.Collections;
using UnityEngine;
using VRMShaders;
@@ -201,22 +202,23 @@ namespace UniGLTF
return data.GLTF.textures[textureIndex].source;
}
private static byte[] ToArray(ArraySegment<byte> bytes)
private static byte[] ToArray(NativeArray<byte> bytes)
{
if (bytes.Array == null)
{
return new byte[] { };
}
else if (bytes.Offset == 0 && bytes.Count == bytes.Array.Length)
{
return bytes.Array;
}
else
{
var result = new byte[bytes.Count];
Buffer.BlockCopy(bytes.Array, bytes.Offset, result, 0, result.Length);
return result;
}
// if (bytes.Array == null)
// {
// return new byte[] { };
// }
// else if (bytes.Offset == 0 && bytes.Count == bytes.Array.Length)
// {
// return bytes.Array;
// }
// else
// {
// var result = new byte[bytes.Count];
// Buffer.BlockCopy(bytes.Array, bytes.Offset, result, 0, result.Length);
// return result;
// }
return bytes.ToArray();
}
}
}

View File

@@ -14,7 +14,7 @@ namespace UniVRM10
Other,
}
public class Vrm10Data
public class Vrm10Data : IDisposable
{
public GltfData Data { get; }
public UniGLTF.Extensions.VRMC_vrm.VRMC_vrm VrmExtension { get; }
@@ -86,77 +86,85 @@ namespace UniVRM10
// try migrateion
byte[] migrated = default;
Migration.Vrm0Meta oldMeta = default;
try
using (data)
{
var json = data.Json.ParseAsJson();
try
{
if (!json.TryGet("extensions", out JsonNode extensions))
var json = data.Json.ParseAsJson();
try
{
result = new Vrm10Data(default, default, Vrm10FileType.Other, "gltf: no extensions");
if (!json.TryGet("extensions", out JsonNode extensions))
{
result = new Vrm10Data(default, default, Vrm10FileType.Other, "gltf: no extensions");
return false;
}
if (!extensions.TryGet("VRM", out JsonNode vrm0))
{
result = new Vrm10Data(default, default, Vrm10FileType.Other, "gltf: no vrm0");
return false;
}
}
catch (Exception ex)
{
result = new Vrm10Data(default, default, Vrm10FileType.Other, $"error: {ex}");
return false;
}
if (!extensions.TryGet("VRM", out JsonNode vrm0))
if (!doMigrate)
{
result = new Vrm10Data(default, default, Vrm10FileType.Other, "gltf: no vrm0");
result = new Vrm10Data(default, default, Vrm10FileType.Vrm0, "vrm0: not migrated");
return false;
}
migrated = MigrationVrm.Migrate(data);
if (migrated == null)
{
result = new Vrm10Data(default, default, Vrm10FileType.Vrm0, "vrm0: cannot migrate");
return false;
}
oldMeta = Migration.Vrm0Meta.FromJsonBytes(json);
}
catch (Exception ex)
{
result = new Vrm10Data(default, default, Vrm10FileType.Other, $"error: {ex}");
result = new Vrm10Data(default, default, Vrm10FileType.Vrm0, $"vrm0: migration error: {ex}");
return false;
}
if (!doMigrate)
{
result = new Vrm10Data(default, default, Vrm10FileType.Vrm0, "vrm0: not migrated");
return false;
}
migrated = MigrationVrm.Migrate(data);
if (migrated == null)
{
result = new Vrm10Data(default, default, Vrm10FileType.Vrm0, "vrm0: cannot migrate");
return false;
}
oldMeta = Migration.Vrm0Meta.FromJsonBytes(json);
}
catch (Exception ex)
{
result = new Vrm10Data(default, default, Vrm10FileType.Vrm0, $"vrm0: migration error: {ex}");
return false;
}
{
var migratedData = new GlbLowLevelParser(data.TargetPath, migrated).Parse();
if (UniGLTF.Extensions.VRMC_vrm.GltfDeserializer.TryGet(migratedData.GLTF.extensions, out VRMC_vrm vrm))
{
// success
if (oldMeta == null)
var migratedData = new GlbLowLevelParser(data.TargetPath, migrated).Parse();
if (UniGLTF.Extensions.VRMC_vrm.GltfDeserializer.TryGet(migratedData.GLTF.extensions, out VRMC_vrm vrm))
{
throw new NullReferenceException("oldMeta");
}
byte[] migratedBytes = null;
if (VRMShaders.Symbols.VRM_DEVELOP)
{
// 右手左手座標変換でバッファが破壊的変更されるので、コピーを作っている
migratedBytes = migrated.Select(x => x).ToArray();
// success
if (oldMeta == null)
{
throw new NullReferenceException("oldMeta");
}
byte[] migratedBytes = null;
if (VRMShaders.Symbols.VRM_DEVELOP)
{
// 右手左手座標変換でバッファが破壊的変更されるので、コピーを作っている
migratedBytes = migrated.Select(x => x).ToArray();
}
result = new Vrm10Data(migratedData, vrm, Vrm10FileType.Vrm0,
message: "vrm0: migrated",
oldMeta: oldMeta,
migratedBytes: migratedBytes
);
return true;
}
result = new Vrm10Data(migratedData, vrm, Vrm10FileType.Vrm0,
message: "vrm0: migrated",
oldMeta: oldMeta,
migratedBytes: migratedBytes
);
return true;
result = new Vrm10Data(default, default, Vrm10FileType.Vrm0, "vrm0: migrate but error ?");
return false;
}
result = new Vrm10Data(default, default, Vrm10FileType.Vrm0, "vrm0: migrate but error ?");
return false;
}
}
public void Dispose()
{
Data.Dispose();
}
}
}

View File

@@ -55,7 +55,7 @@ namespace UniVRM10
gltfVrmSpringBone = springBone;
}
_buffer = new ArraySegmentByteBuffer(data.Bin);
_buffer = new ArraySegmentByteBuffer(new ArraySegment<byte>(data.Bin.ToArray()));
}
public void Reserve(int bytesLength)

View File

@@ -20,7 +20,7 @@ namespace UniVRM10
public MeshUpdater(GltfData data)
{
_data = data;
_buffer = new ArrayByteBuffer(new byte[data.Bin.Count]);
_buffer = new ArrayByteBuffer(new byte[data.Bin.Length]);
}
int AddBuffer(ArraySegment<byte> bytes)
@@ -70,7 +70,7 @@ namespace UniVRM10
foreach (var image in gltf.images)
{
var bytes = _data.GetBytesFromBufferView(image.bufferView);
image.bufferView = AddBuffer(bytes);
image.bufferView = AddBuffer(new ArraySegment<byte>(bytes.ToArray()));
}
// update Mesh

View File

@@ -73,7 +73,7 @@ namespace UniVRM10
if (bufferViewIndex != -1)
{
var buffer = data.GetBytesFromBufferView(bufferViewIndex);
var span = SpanLike.Wrap<UnityEngine.Vector3>(buffer);
var span = buffer.Reinterpret<UnityEngine.Vector3>(1);
for (int i = 0; i < span.Length; ++i)
{
span[i] = span[i].RotateY180();
@@ -114,7 +114,7 @@ namespace UniVRM10
{
var accessor = data.GLTF.accessors[skin.inverseBindMatrices];
var buffer = data.GetBytesFromBufferView(accessor.bufferView);
var span = SpanLike.Wrap<UnityEngine.Matrix4x4>(buffer);
var span = buffer.Reinterpret<UnityEngine.Matrix4x4>(1);
for (int i = 0; i < span.Length; ++i)
{
span[i] = span[i].RotateY180();