mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-05-12 21:45:06 -05:00
Merge pull request #1483 from ousttrue/fix/use_native_array
Fix/use native array
This commit is contained in:
commit
00a046a06c
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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) =>
|
||||
|
|
|
|||
|
|
@ -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 NativeArray<byte> Bin { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Migration Flags used by ImporterContext
|
||||
|
|
@ -74,7 +61,9 @@ 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>>();
|
||||
|
||||
List<IDisposable> m_disposables = new List<IDisposable>();
|
||||
|
||||
public GltfData(string targetPath, string json, glTF gltf, IReadOnlyList<GlbChunk> chunks, IStorage storage, MigrationFlags migrationFlags)
|
||||
{
|
||||
|
|
@ -84,6 +73,25 @@ namespace UniGLTF
|
|||
Chunks = chunks;
|
||||
_storage = storage;
|
||||
MigrationFlags = migrationFlags;
|
||||
|
||||
// init
|
||||
if (Chunks != null)
|
||||
{
|
||||
if (Chunks.Count >= 2)
|
||||
{
|
||||
Bin = CreateNativeArray(Chunks[1].Bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var disposable in m_disposables)
|
||||
{
|
||||
disposable.Dispose();
|
||||
}
|
||||
m_disposables.Clear();
|
||||
_UriCache.Clear();
|
||||
}
|
||||
|
||||
public static GltfData CreateFromExportForTest(ExportingGltfData data)
|
||||
|
|
@ -107,14 +115,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 +130,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 +154,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 +252,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 +280,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 +317,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 +375,34 @@ 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
25
Assets/UniGLTF/Runtime/UniGLTF/IO/GltfUtility.cs
Normal file
25
Assets/UniGLTF/Runtime/UniGLTF/IO/GltfUtility.cs
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using VRMShaders;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public static class GltfUtility
|
||||
{
|
||||
public static async Task<RuntimeGltfInstance> LoadAsync(string path, IAwaitCaller awaitCaller = null, IMaterialDescriptorGenerator materialGenerator = null)
|
||||
{
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
throw new FileNotFoundException(path);
|
||||
}
|
||||
|
||||
Debug.LogFormat("{0}", path);
|
||||
using (GltfData data = new AutoGltfFileParser(path).Parse())
|
||||
using (var loader = new UniGLTF.ImporterContext(data, materialGenerator: materialGenerator))
|
||||
{
|
||||
return await loader.LoadAsync(awaitCaller);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/UniGLTF/Runtime/UniGLTF/IO/GltfUtility.cs.meta
Normal file
11
Assets/UniGLTF/Runtime/UniGLTF/IO/GltfUtility.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 317decd1053397d4b9bdb9fb183bba4a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -143,16 +143,17 @@ namespace UniGLTF
|
|||
UnityEngine.Object.DestroyImmediate(mat);
|
||||
UnityEngine.Object.DestroyImmediate(root);
|
||||
|
||||
var parsed = GltfData.CreateFromGltfDataForTest(gltf, data.BinBytes);
|
||||
using (var parsed = GltfData.CreateFromGltfDataForTest(gltf, data.BinBytes))
|
||||
{
|
||||
// Extract Image to Texture2D
|
||||
var exportedBytes = parsed.GetBytesFromBufferView(exportedImage.bufferView).ToArray();
|
||||
var exportedTexture = new Texture2D(2, 2, TextureFormat.ARGB32, mipChain: false, linear: false);
|
||||
Assert.IsTrue(exportedTexture.LoadImage(exportedBytes)); // Always true ?
|
||||
Assert.AreEqual(srcTex.width, exportedTexture.width);
|
||||
Assert.AreEqual(srcTex.height, exportedTexture.height);
|
||||
|
||||
// Extract Image to Texture2D
|
||||
var exportedBytes = parsed.GetBytesFromBufferView(exportedImage.bufferView).ToArray();
|
||||
var exportedTexture = new Texture2D(2, 2, TextureFormat.ARGB32, mipChain: false, linear: false);
|
||||
Assert.IsTrue(exportedTexture.LoadImage(exportedBytes)); // Always true ?
|
||||
Assert.AreEqual(srcTex.width, exportedTexture.width);
|
||||
Assert.AreEqual(srcTex.height, exportedTexture.height);
|
||||
|
||||
return exportedTexture;
|
||||
return exportedTexture;
|
||||
}
|
||||
}
|
||||
|
||||
private static Color32 GetFirstPixelInTexture2D(Texture2D tex)
|
||||
|
|
|
|||
|
|
@ -33,11 +33,13 @@ namespace UniGLTF
|
|||
});
|
||||
|
||||
var parser = new GlbLowLevelParser("Test", data.ToGlbBytes());
|
||||
var parsed = parser.Parse();
|
||||
using (var parsed = parser.Parse())
|
||||
{
|
||||
|
||||
Assert.AreEqual("FooBar", parsed.GLTF.textures[0].name);
|
||||
// NOTE: 大文字小文字が違うだけの名前は、同一としてみなされ、Suffix が付く。
|
||||
Assert.AreEqual("foobar__UNIGLTF__DUPLICATED__2", parsed.GLTF.textures[1].name);
|
||||
Assert.AreEqual("FooBar", parsed.GLTF.textures[0].name);
|
||||
// NOTE: 大文字小文字が違うだけの名前は、同一としてみなされ、Suffix が付く。
|
||||
Assert.AreEqual("foobar__UNIGLTF__DUPLICATED__2", parsed.GLTF.textures[1].name);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -61,16 +63,18 @@ namespace UniGLTF
|
|||
Assert.True(File.Exists(path));
|
||||
|
||||
var bytes = File.ReadAllBytes(path);
|
||||
var data = new GlbBinaryParser(bytes, Path.GetFileNameWithoutExtension(path)).Parse();
|
||||
|
||||
// glb header + 1st chunk only
|
||||
var mod = bytes.Take(12 + 8 + data.Chunks[0].Bytes.Count).ToArray();
|
||||
|
||||
Assert.Throws<GlbParseException>(() =>
|
||||
using (var data = new GlbBinaryParser(bytes, Path.GetFileNameWithoutExtension(path)).Parse())
|
||||
{
|
||||
|
||||
// glb header + 1st chunk only
|
||||
var mod = bytes.Take(12 + 8 + data.Chunks[0].Bytes.Count).ToArray();
|
||||
|
||||
Assert.Throws<GlbParseException>(() =>
|
||||
{
|
||||
// 再パース
|
||||
var data2 = new GlbBinaryParser(mod, Path.GetFileNameWithoutExtension(path)).Parse();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@ namespace UniGLTF
|
|||
Debug.LogException(ex);
|
||||
}
|
||||
|
||||
using (data)
|
||||
using (var loader = new ImporterContext(data))
|
||||
{
|
||||
try
|
||||
|
|
@ -136,12 +137,15 @@ namespace UniGLTF
|
|||
}
|
||||
|
||||
// should unique
|
||||
var gltfTextures = new GltfTextureDescriptorGenerator(data).Get().GetEnumerable()
|
||||
.Select(x => x.SubAssetKey)
|
||||
.ToArray();
|
||||
var distinct = gltfTextures.Distinct().ToArray();
|
||||
Assert.True(gltfTextures.Length == distinct.Length);
|
||||
Assert.True(gltfTextures.SequenceEqual(distinct));
|
||||
using (data)
|
||||
{
|
||||
var gltfTextures = new GltfTextureDescriptorGenerator(data).Get().GetEnumerable()
|
||||
.Select(x => x.SubAssetKey)
|
||||
.ToArray();
|
||||
var distinct = gltfTextures.Distinct().ToArray();
|
||||
Assert.True(gltfTextures.Length == distinct.Length);
|
||||
Assert.True(gltfTextures.SequenceEqual(distinct));
|
||||
}
|
||||
}
|
||||
|
||||
static bool Exclude(FileInfo f)
|
||||
|
|
@ -220,13 +224,14 @@ namespace UniGLTF
|
|||
|
||||
{
|
||||
var path = Path.Combine(root.FullName, "DamagedHelmet/glTF-Binary/DamagedHelmet.glb");
|
||||
var data = new AutoGltfFileParser(path).Parse();
|
||||
|
||||
var matDesc = new GltfMaterialDescriptorGenerator().Get(data, 0);
|
||||
Assert.AreEqual("Standard", matDesc.ShaderName);
|
||||
Assert.AreEqual(5, matDesc.TextureSlots.Count);
|
||||
var (key, value) = matDesc.EnumerateSubAssetKeyValue().First();
|
||||
Assert.AreEqual(new SubAssetKey(typeof(Texture2D), "texture_0"), key);
|
||||
using (var data = new AutoGltfFileParser(path).Parse())
|
||||
{
|
||||
var matDesc = new GltfMaterialDescriptorGenerator().Get(data, 0);
|
||||
Assert.AreEqual("Standard", matDesc.ShaderName);
|
||||
Assert.AreEqual(5, matDesc.TextureSlots.Count);
|
||||
var (key, value) = matDesc.EnumerateSubAssetKeyValue().First();
|
||||
Assert.AreEqual(new SubAssetKey(typeof(Texture2D), "texture_0"), key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -137,30 +137,32 @@ namespace UniGLTF
|
|||
: MeshExporter_SharedVertexBuffer.Export(data, unityMesh, Materials, axisInverter, meshExportSettings)
|
||||
;
|
||||
|
||||
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);
|
||||
Assert.AreEqual(0, indices[0]);
|
||||
Assert.AreEqual(1, indices[1]);
|
||||
Assert.AreEqual(5, indices[2]);
|
||||
Assert.AreEqual(5, indices[3]);
|
||||
Assert.AreEqual(1, indices[4]);
|
||||
Assert.AreEqual(4, indices[5]);
|
||||
}
|
||||
|
||||
{
|
||||
var indices = parsed.GetIndices(gltfMesh.primitives[1].indices);
|
||||
Assert.AreEqual(1, indices[0]);
|
||||
Assert.AreEqual(2, indices[1]);
|
||||
Assert.AreEqual(4, indices[2]);
|
||||
Assert.AreEqual(4, indices[3]);
|
||||
Assert.AreEqual(2, indices[4]);
|
||||
Assert.AreEqual(3, indices[5]);
|
||||
}
|
||||
{
|
||||
var indices = parsed.GetIndices(gltfMesh.primitives[0].indices);
|
||||
Assert.AreEqual(0, indices[0]);
|
||||
Assert.AreEqual(1, indices[1]);
|
||||
Assert.AreEqual(5, indices[2]);
|
||||
Assert.AreEqual(5, indices[3]);
|
||||
Assert.AreEqual(1, indices[4]);
|
||||
Assert.AreEqual(4, indices[5]);
|
||||
}
|
||||
|
||||
var positions = parsed.GetArrayFromAccessor<Vector3>(gltfMesh.primitives[0].attributes.POSITION);
|
||||
Assert.AreEqual(6, positions.Length);
|
||||
{
|
||||
var indices = parsed.GetIndices(gltfMesh.primitives[1].indices);
|
||||
Assert.AreEqual(1, indices[0]);
|
||||
Assert.AreEqual(2, indices[1]);
|
||||
Assert.AreEqual(4, indices[2]);
|
||||
Assert.AreEqual(4, indices[3]);
|
||||
Assert.AreEqual(2, indices[4]);
|
||||
Assert.AreEqual(3, indices[5]);
|
||||
}
|
||||
|
||||
var positions = parsed.GetArrayFromAccessor<Vector3>(gltfMesh.primitives[0].attributes.POSITION);
|
||||
Assert.AreEqual(6, positions.Length);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
|
|
|||
26
Assets/UniGLTF/Tests/UniGLTF/NativeArrayTests.cs
Normal file
26
Assets/UniGLTF/Tests/UniGLTF/NativeArrayTests.cs
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
using System;
|
||||
using NUnit.Framework;
|
||||
using Unity.Collections;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public class NativeArrayTests
|
||||
{
|
||||
[Test]
|
||||
public void DisposeTest()
|
||||
{
|
||||
var array = new NativeArray<byte>(64, Allocator.Persistent);
|
||||
var sub = array.GetSubArray(10, 4);
|
||||
Assert.Throws<InvalidOperationException>(() => { sub.Dispose(); });
|
||||
var cast = array.Reinterpret<int>(1);
|
||||
|
||||
// Dispose可能
|
||||
cast.Dispose();
|
||||
|
||||
// Disposed
|
||||
Assert.Throws<InvalidOperationException>(() => { var c = cast[0]; });
|
||||
Assert.Throws<InvalidOperationException>(() => { var a = array[0]; });
|
||||
Assert.Throws<InvalidOperationException>(() => { var s = sub[0]; });
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/UniGLTF/Tests/UniGLTF/NativeArrayTests.cs.meta
Normal file
11
Assets/UniGLTF/Tests/UniGLTF/NativeArrayTests.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d3712bde0d2a4b348ab5bb661fe1a51a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -88,10 +88,7 @@ namespace UniGLTF
|
|||
return;
|
||||
}
|
||||
|
||||
// parse
|
||||
var data = new GlbFileParser(path.FullName).Parse();
|
||||
|
||||
// load
|
||||
using (var data = new GlbFileParser(path.FullName).Parse())
|
||||
using (var context = new ImporterContext(data))
|
||||
{
|
||||
var instance = context.Load();
|
||||
|
|
|
|||
|
|
@ -115,9 +115,7 @@ namespace UniGLTF
|
|||
}
|
||||
|
||||
// parse
|
||||
var parsed = GltfData.CreateFromExportForTest(data);
|
||||
|
||||
// import
|
||||
using (var parsed = GltfData.CreateFromExportForTest(data))
|
||||
using (var context = new ImporterContext(parsed))
|
||||
using (var loaded = context.Load())
|
||||
{
|
||||
|
|
|
|||
57
Assets/VRM/Runtime/IO/VrmUtility.cs
Normal file
57
Assets/VRM/Runtime/IO/VrmUtility.cs
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using UniGLTF;
|
||||
using UnityEngine;
|
||||
using VRMShaders;
|
||||
|
||||
namespace VRM
|
||||
{
|
||||
public static class VrmUtility
|
||||
{
|
||||
public delegate IMaterialDescriptorGenerator MaterialGeneratorCallback(VRM.glTF_VRM_extensions vrm);
|
||||
public delegate void MetaCallback(VRMMetaObject meta);
|
||||
public static async Task<RuntimeGltfInstance> LoadAsync(string path,
|
||||
IAwaitCaller awaitCaller = null,
|
||||
MaterialGeneratorCallback materialGeneratorCallback = null,
|
||||
MetaCallback metaCallback = null
|
||||
)
|
||||
{
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
throw new FileNotFoundException(path);
|
||||
}
|
||||
|
||||
using (GltfData data = new AutoGltfFileParser(path).Parse())
|
||||
{
|
||||
try
|
||||
{
|
||||
var vrm = new VRMData(data);
|
||||
IMaterialDescriptorGenerator materialGen = default;
|
||||
if (materialGeneratorCallback != null)
|
||||
{
|
||||
materialGen = materialGeneratorCallback(vrm.VrmExtension);
|
||||
}
|
||||
using (var loader = new VRMImporterContext(vrm, materialGenerator: materialGen))
|
||||
{
|
||||
if (metaCallback != null)
|
||||
{
|
||||
var meta = await loader.ReadMetaAsync(new ImmediateCaller(), true);
|
||||
metaCallback(meta);
|
||||
}
|
||||
return await loader.LoadAsync(awaitCaller);
|
||||
}
|
||||
}
|
||||
catch (NotVrm0Exception)
|
||||
{
|
||||
// retry
|
||||
Debug.LogWarning("file extension is vrm. but not vrm ?");
|
||||
using (var loader = new UniGLTF.ImporterContext(data))
|
||||
{
|
||||
return await loader.LoadAsync(awaitCaller);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/VRM/Runtime/IO/VrmUtility.cs.meta
Normal file
11
Assets/VRM/Runtime/IO/VrmUtility.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 431e57aed523ae240a0c88b0657677f8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -72,6 +72,7 @@ namespace VRM
|
|||
|
||||
try
|
||||
{
|
||||
using (data)
|
||||
using (var importer = new VRMImporterContext(new VRMData(data)))
|
||||
{
|
||||
return importer.Load().gameObject;
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ namespace VRM
|
|||
{
|
||||
var data = new GlbFileParser(AliciaPath).Parse();
|
||||
byte[] bytes = default;
|
||||
using (data)
|
||||
using (var loader = new VRMImporterContext(new VRMData(data)))
|
||||
using (var loaded = loader.Load())
|
||||
{
|
||||
|
|
@ -37,7 +38,7 @@ namespace VRM
|
|||
});
|
||||
}
|
||||
|
||||
var data2 = new GlbLowLevelParser(AliciaPath, bytes).Parse();
|
||||
using (var data2 = new GlbLowLevelParser(AliciaPath, bytes).Parse())
|
||||
using (var loader2 = new VRMImporterContext(new VRMData(data2)))
|
||||
{
|
||||
Assert.AreEqual(LookAtType.BlendShape, loader2.VRM.firstPerson.lookAtType);
|
||||
|
|
@ -50,6 +51,7 @@ namespace VRM
|
|||
var data = new GlbFileParser(AliciaPath).Parse();
|
||||
byte[] bytes = default;
|
||||
CurveMapper horizontalInner = default;
|
||||
using (data)
|
||||
using (var loader = new VRMImporterContext(new VRMData(data)))
|
||||
using (var loaded = loader.Load())
|
||||
{
|
||||
|
|
@ -65,7 +67,7 @@ namespace VRM
|
|||
});
|
||||
}
|
||||
|
||||
var data2 = new GlbLowLevelParser(AliciaPath, bytes).Parse();
|
||||
using (var data2 = new GlbLowLevelParser(AliciaPath, bytes).Parse())
|
||||
using (var loader = new VRMImporterContext(new VRMData(data2)))
|
||||
using (var loaded = loader.Load())
|
||||
{
|
||||
|
|
@ -83,6 +85,7 @@ namespace VRM
|
|||
var data = new GlbFileParser(AliciaPath).Parse();
|
||||
byte[] bytes = default;
|
||||
CurveMapper horizontalInner = default;
|
||||
using (data)
|
||||
using (var loader = new VRMImporterContext(new VRMData(data)))
|
||||
using (var loaded = loader.Load())
|
||||
{
|
||||
|
|
@ -98,7 +101,7 @@ namespace VRM
|
|||
});
|
||||
}
|
||||
|
||||
var data2 = new GlbLowLevelParser(AliciaPath, bytes).Parse();
|
||||
using (var data2 = new GlbLowLevelParser(AliciaPath, bytes).Parse())
|
||||
using (var loader = new VRMImporterContext(new VRMData(data2)))
|
||||
using (var loaded = loader.Load())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -21,13 +21,15 @@ namespace VRM
|
|||
|
||||
static GameObject Load(byte[] bytes, string path)
|
||||
{
|
||||
var gltf = new GlbLowLevelParser(path, bytes).Parse();
|
||||
var data = new VRMData(gltf);
|
||||
using (var loader = new VRMImporterContext(data))
|
||||
using (var gltf = new GlbLowLevelParser(path, bytes).Parse())
|
||||
{
|
||||
var loaded = loader.Load();
|
||||
loaded.ShowMeshes();
|
||||
return loaded.gameObject;
|
||||
var data = new VRMData(gltf);
|
||||
using (var loader = new VRMImporterContext(data))
|
||||
{
|
||||
var loaded = loader.Load();
|
||||
loaded.ShowMeshes();
|
||||
return loaded.gameObject;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
@ -52,6 +52,11 @@ namespace UniVRM10
|
|||
MigratedBytes = migratedBytes;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Data.Dispose();
|
||||
}
|
||||
|
||||
public static bool TryParseOrMigrate(string path, bool doMigrate, out Vrm10Data result)
|
||||
{
|
||||
return TryParseOrMigrate(path, File.ReadAllBytes(path), doMigrate, out result);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -40,14 +40,16 @@ namespace UniVRM10.Test
|
|||
Debug.Log($"load: {path}");
|
||||
|
||||
Assert.IsTrue(Vrm10Data.TryParseOrMigrate(path, true, out Vrm10Data result));
|
||||
using (result)
|
||||
{
|
||||
var go = BuildGameObject(result, true);
|
||||
Debug.Log(go);
|
||||
|
||||
var go = BuildGameObject(result, true);
|
||||
Debug.Log(go);
|
||||
// export
|
||||
var vrmBytes = Vrm10Exporter.Export(go, new EditorTextureSerializer());
|
||||
|
||||
// export
|
||||
var vrmBytes = Vrm10Exporter.Export(go, new EditorTextureSerializer());
|
||||
|
||||
Debug.Log($"export {vrmBytes.Length} bytes");
|
||||
Debug.Log($"export {vrmBytes.Length} bytes");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,22 +22,24 @@ namespace UniVRM10
|
|||
public void MaterialImporterTest()
|
||||
{
|
||||
var migratedBytes = MigrationVrm.Migrate(File.ReadAllBytes(AliciaPath));
|
||||
var data = new GlbLowLevelParser(AliciaPath, migratedBytes).Parse();
|
||||
using (var data = new GlbLowLevelParser(AliciaPath, migratedBytes).Parse())
|
||||
{
|
||||
|
||||
var matDesc = new Vrm10MaterialDescriptorGenerator().Get(data, 0);
|
||||
Assert.AreEqual("Alicia_body", matDesc.Name);
|
||||
Assert.AreEqual("VRM10/MToon10", matDesc.ShaderName);
|
||||
Assert.AreEqual("Alicia_body", matDesc.TextureSlots["_MainTex"].UnityObjectName);
|
||||
Assert.AreEqual("Alicia_body", matDesc.TextureSlots["_ShadeTex"].UnityObjectName);
|
||||
var matDesc = new Vrm10MaterialDescriptorGenerator().Get(data, 0);
|
||||
Assert.AreEqual("Alicia_body", matDesc.Name);
|
||||
Assert.AreEqual("VRM10/MToon10", matDesc.ShaderName);
|
||||
Assert.AreEqual("Alicia_body", matDesc.TextureSlots["_MainTex"].UnityObjectName);
|
||||
Assert.AreEqual("Alicia_body", matDesc.TextureSlots["_ShadeTex"].UnityObjectName);
|
||||
|
||||
AreColorEqualApproximately(new Color(1, 1, 1, 1), matDesc.Colors["_Color"]);
|
||||
ColorUtility.TryParseHtmlString("#FFDDD6", out var shadeColor);
|
||||
AreColorEqualApproximately(shadeColor, matDesc.Colors["_ShadeColor"]);
|
||||
AreColorEqualApproximately(new Color(1, 1, 1, 1), matDesc.Colors["_Color"]);
|
||||
ColorUtility.TryParseHtmlString("#FFDDD6", out var shadeColor);
|
||||
AreColorEqualApproximately(shadeColor, matDesc.Colors["_ShadeColor"]);
|
||||
|
||||
Assert.AreEqual(1.0f - 0.1f, matDesc.FloatValues["_GiEqualization"]);
|
||||
Assert.AreEqual(1.0f - 0.1f, matDesc.FloatValues["_GiEqualization"]);
|
||||
|
||||
var (key, value) = matDesc.EnumerateSubAssetKeyValue().First();
|
||||
Assert.AreEqual(new SubAssetKey(typeof(Texture2D), "Alicia_body"), key);
|
||||
var (key, value) = matDesc.EnumerateSubAssetKeyValue().First();
|
||||
Assert.AreEqual(new SubAssetKey(typeof(Texture2D), "Alicia_body"), key);
|
||||
}
|
||||
}
|
||||
|
||||
private void AreColorEqualApproximately(Color expected, Color actual)
|
||||
|
|
|
|||
|
|
@ -22,9 +22,11 @@ namespace UniVRM10
|
|||
|
||||
static JsonNode GetVRM0(byte[] bytes)
|
||||
{
|
||||
var glb = new GlbBinaryParser(bytes, "vrm0").Parse();
|
||||
var json = glb.Json.ParseAsJson();
|
||||
return json["extensions"]["VRM"];
|
||||
using (var glb = new GlbBinaryParser(bytes, "vrm0").Parse())
|
||||
{
|
||||
var json = glb.Json.ParseAsJson();
|
||||
return json["extensions"]["VRM"];
|
||||
}
|
||||
}
|
||||
|
||||
T GetExtension<T>(UniGLTF.glTFExtension extensions, UniJSON.Utf8String key, Func<JsonNode, T> deserializer)
|
||||
|
|
@ -50,14 +52,16 @@ namespace UniVRM10
|
|||
var vrm0Json = GetVRM0(vrm0Bytes);
|
||||
|
||||
var vrm1 = MigrationVrm.Migrate(vrm0Bytes);
|
||||
var glb = new GlbBinaryParser(vrm1, "vrm1").Parse();
|
||||
var json = glb.Json.ParseAsJson();
|
||||
var gltf = UniGLTF.GltfDeserializer.Deserialize(json);
|
||||
using (var glb = new GlbBinaryParser(vrm1, "vrm1").Parse())
|
||||
{
|
||||
var json = glb.Json.ParseAsJson();
|
||||
var gltf = UniGLTF.GltfDeserializer.Deserialize(json);
|
||||
|
||||
MigrationVrm.Check(vrm0Json, GetExtension(gltf.extensions, UniGLTF.Extensions.VRMC_vrm.GltfDeserializer.ExtensionNameUtf8,
|
||||
UniGLTF.Extensions.VRMC_vrm.GltfDeserializer.Deserialize), MigrationVrm.CreateMeshToNode(gltf));
|
||||
MigrationVrm.Check(vrm0Json, GetExtension(gltf.extensions, UniGLTF.Extensions.VRMC_springBone.GltfDeserializer.ExtensionNameUtf8,
|
||||
UniGLTF.Extensions.VRMC_springBone.GltfDeserializer.Deserialize), gltf.nodes);
|
||||
MigrationVrm.Check(vrm0Json, GetExtension(gltf.extensions, UniGLTF.Extensions.VRMC_vrm.GltfDeserializer.ExtensionNameUtf8,
|
||||
UniGLTF.Extensions.VRMC_vrm.GltfDeserializer.Deserialize), MigrationVrm.CreateMeshToNode(gltf));
|
||||
MigrationVrm.Check(vrm0Json, GetExtension(gltf.extensions, UniGLTF.Extensions.VRMC_springBone.GltfDeserializer.ExtensionNameUtf8,
|
||||
UniGLTF.Extensions.VRMC_springBone.GltfDeserializer.Deserialize), gltf.nodes);
|
||||
}
|
||||
}
|
||||
|
||||
const float EPS = 1e-4f;
|
||||
|
|
@ -194,7 +198,8 @@ namespace UniVRM10
|
|||
{
|
||||
try
|
||||
{
|
||||
Vrm10Data.TryParseOrMigrate(gltf.FullName, true, out Vrm10Data vrm);
|
||||
Assert.True(Vrm10Data.TryParseOrMigrate(gltf.FullName, true, out Vrm10Data vrm));
|
||||
using (vrm)
|
||||
using (var loader = new Vrm10Importer(vrm))
|
||||
{
|
||||
loader.LoadAsync().Wait();
|
||||
|
|
@ -218,41 +223,47 @@ namespace UniVRM10
|
|||
//
|
||||
var VALUE = new Vector3(-0.0359970331f, -0.0188314915f, 0.00566166639f);
|
||||
var bytes0 = File.ReadAllBytes(AliciaPath);
|
||||
var data0 = new GlbLowLevelParser(AliciaPath, bytes0).Parse();
|
||||
var json0 = data0.Json.ParseAsJson();
|
||||
var groupIndex = json0["extensions"]["VRM"]["secondaryAnimation"]["boneGroups"][0]["colliderGroups"][0].GetInt32();
|
||||
var x = json0["extensions"]["VRM"]["secondaryAnimation"]["colliderGroups"][groupIndex]["colliders"][0]["offset"]["x"].GetSingle();
|
||||
var y = json0["extensions"]["VRM"]["secondaryAnimation"]["colliderGroups"][groupIndex]["colliders"][0]["offset"]["y"].GetSingle();
|
||||
var z = json0["extensions"]["VRM"]["secondaryAnimation"]["colliderGroups"][groupIndex]["colliders"][0]["offset"]["z"].GetSingle();
|
||||
Assert.AreEqual(VALUE.x, x);
|
||||
Assert.AreEqual(VALUE.y, y);
|
||||
Assert.AreEqual(VALUE.z, z);
|
||||
int groupIndex = default;
|
||||
using (var data0 = new GlbLowLevelParser(AliciaPath, bytes0).Parse())
|
||||
{
|
||||
var json0 = data0.Json.ParseAsJson();
|
||||
groupIndex = json0["extensions"]["VRM"]["secondaryAnimation"]["boneGroups"][0]["colliderGroups"][0].GetInt32();
|
||||
var x = json0["extensions"]["VRM"]["secondaryAnimation"]["colliderGroups"][groupIndex]["colliders"][0]["offset"]["x"].GetSingle();
|
||||
var y = json0["extensions"]["VRM"]["secondaryAnimation"]["colliderGroups"][groupIndex]["colliders"][0]["offset"]["y"].GetSingle();
|
||||
var z = json0["extensions"]["VRM"]["secondaryAnimation"]["colliderGroups"][groupIndex]["colliders"][0]["offset"]["z"].GetSingle();
|
||||
Assert.AreEqual(VALUE.x, x);
|
||||
Assert.AreEqual(VALUE.y, y);
|
||||
Assert.AreEqual(VALUE.z, z);
|
||||
}
|
||||
|
||||
//
|
||||
// vrm1 に migrate
|
||||
//
|
||||
var bytes1 = MigrationVrm.Migrate(bytes0);
|
||||
var data1 = new GlbLowLevelParser(AliciaPath, bytes1).Parse();
|
||||
Assert.True(UniGLTF.Extensions.VRMC_springBone.GltfDeserializer.TryGet(data1.GLTF.extensions, out UniGLTF.Extensions.VRMC_springBone.VRMC_springBone springBone));
|
||||
var spring = springBone.Springs[0];
|
||||
// var colliderNodeIndex = spring.ColliderGroups[0];
|
||||
// x軸だけが反転する
|
||||
|
||||
var colliderIndex = 0;
|
||||
for (int i = 0; i < groupIndex; ++i)
|
||||
using (var data1 = new GlbLowLevelParser(AliciaPath, bytes1).Parse())
|
||||
{
|
||||
colliderIndex += springBone.ColliderGroups[i].Colliders.Length;
|
||||
}
|
||||
Assert.True(UniGLTF.Extensions.VRMC_springBone.GltfDeserializer.TryGet(data1.GLTF.extensions, out UniGLTF.Extensions.VRMC_springBone.VRMC_springBone springBone));
|
||||
var spring = springBone.Springs[0];
|
||||
// var colliderNodeIndex = spring.ColliderGroups[0];
|
||||
// x軸だけが反転する
|
||||
|
||||
Assert.AreEqual(-VALUE.x, springBone.Colliders[colliderIndex].Shape.Sphere.Offset[0]);
|
||||
Assert.AreEqual(VALUE.y, springBone.Colliders[colliderIndex].Shape.Sphere.Offset[1]);
|
||||
Assert.AreEqual(VALUE.z, springBone.Colliders[colliderIndex].Shape.Sphere.Offset[2]);
|
||||
var colliderIndex = 0;
|
||||
for (int i = 0; i < groupIndex; ++i)
|
||||
{
|
||||
colliderIndex += springBone.ColliderGroups[i].Colliders.Length;
|
||||
}
|
||||
|
||||
Assert.AreEqual(-VALUE.x, springBone.Colliders[colliderIndex].Shape.Sphere.Offset[0]);
|
||||
Assert.AreEqual(VALUE.y, springBone.Colliders[colliderIndex].Shape.Sphere.Offset[1]);
|
||||
Assert.AreEqual(VALUE.z, springBone.Colliders[colliderIndex].Shape.Sphere.Offset[2]);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MigrateMeta()
|
||||
{
|
||||
Assert.True(Vrm10Data.TryParseOrMigrate(AliciaPath, true, out Vrm10Data vrm));
|
||||
vrm.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ namespace UniVRM10
|
|||
public static Vrm10Instance LoadAlicia()
|
||||
{
|
||||
Vrm10Data.TryParseOrMigrate(AliciaPath, true, out Vrm10Data vrm);
|
||||
using (vrm)
|
||||
using (var loader = new Vrm10Importer(vrm))
|
||||
{
|
||||
var task = loader.LoadAsync(new VRMShaders.ImmediateCaller());
|
||||
|
|
|
|||
|
|
@ -85,27 +85,8 @@ namespace VRM.FirstPersonSample
|
|||
|
||||
// GLB形式でJSONを取得しParseします
|
||||
// VRM extension を parse します
|
||||
var data = new GlbFileParser(path).Parse();
|
||||
var vrm = new VRMData(data);
|
||||
using (var context = new VRMImporterContext(vrm))
|
||||
{
|
||||
// metaを取得(todo: thumbnailテクスチャのロード)
|
||||
var meta = await context.ReadMetaAsync();
|
||||
Debug.LogFormat("meta: title:{0}", meta.Title);
|
||||
|
||||
// ParseしたJSONをシーンオブジェクトに変換していく
|
||||
var loaded = default(RuntimeGltfInstance);
|
||||
if (m_loadAsync)
|
||||
{
|
||||
loaded = await context.LoadAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
loaded = context.Load();
|
||||
}
|
||||
|
||||
OnLoaded(loaded);
|
||||
}
|
||||
var loaded = await VrmUtility.LoadAsync(path);
|
||||
OnLoaded(loaded);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -49,25 +49,11 @@ namespace VRM.RuntimeExporterSample
|
|||
return;
|
||||
}
|
||||
|
||||
// GLB形式でJSONを取得しParseします
|
||||
var data = new GlbFileParser(path).Parse();
|
||||
// VRM extension を parse します
|
||||
var vrm = new VRMData(data);
|
||||
using (var context = new VRMImporterContext(vrm))
|
||||
{
|
||||
var loaded = await VrmUtility.LoadAsync(path);
|
||||
|
||||
// metaを取得(todo: thumbnailテクスチャのロード)
|
||||
var meta = await context.ReadMetaAsync();
|
||||
Debug.LogFormat("meta: title:{0}", meta.Title);
|
||||
|
||||
// ParseしたJSONをシーンオブジェクトに変換していく
|
||||
var loaded = await context.LoadAsync();
|
||||
|
||||
loaded.ShowMeshes();
|
||||
loaded.EnableUpdateWhenOffscreen();
|
||||
|
||||
OnLoaded(loaded.gameObject);
|
||||
}
|
||||
loaded.ShowMeshes();
|
||||
loaded.EnableUpdateWhenOffscreen();
|
||||
OnLoaded(loaded.gameObject);
|
||||
}
|
||||
|
||||
void OnLoaded(GameObject go)
|
||||
|
|
|
|||
|
|
@ -103,10 +103,8 @@ namespace VRM.SimpleViewer
|
|||
m_textDistributionOther.text = "";
|
||||
}
|
||||
|
||||
public async Task UpdateMetaAsync(VRMImporterContext context)
|
||||
public void UpdateMeta(VRMMetaObject meta)
|
||||
{
|
||||
var meta = await context.ReadMetaAsync(new ImmediateCaller(), true);
|
||||
|
||||
m_textModelTitle.text = meta.Title;
|
||||
m_textModelVersion.text = meta.Version;
|
||||
m_textModelAuthor.text = meta.Author;
|
||||
|
|
@ -321,7 +319,7 @@ namespace VRM.SimpleViewer
|
|||
string[] cmds = System.Environment.GetCommandLineArgs();
|
||||
if (cmds.Length > 1)
|
||||
{
|
||||
LoadModel(cmds[1]);
|
||||
LoadModelAsync(cmds[1]);
|
||||
}
|
||||
|
||||
m_texts.Start();
|
||||
|
|
@ -366,10 +364,10 @@ namespace VRM.SimpleViewer
|
|||
return;
|
||||
}
|
||||
|
||||
LoadModel(path);
|
||||
LoadModelAsync(path);
|
||||
}
|
||||
|
||||
void LoadModel(string path)
|
||||
async void LoadModelAsync(string path)
|
||||
{
|
||||
var ext = Path.GetExtension(path).ToLower();
|
||||
switch (ext)
|
||||
|
|
@ -377,12 +375,21 @@ namespace VRM.SimpleViewer
|
|||
case ".gltf":
|
||||
case ".glb":
|
||||
case ".zip":
|
||||
LoadModelAsync(path, false);
|
||||
break;
|
||||
{
|
||||
var instance = await GltfUtility.LoadAsync(path,
|
||||
GetIAwaitCaller(m_useAsync.isOn),
|
||||
GetGltfMaterialGenerator(m_useUrpMaterial.isOn));
|
||||
break;
|
||||
}
|
||||
|
||||
case ".vrm":
|
||||
LoadModelAsync(path, true);
|
||||
break;
|
||||
{
|
||||
VrmUtility.MaterialGeneratorCallback materialCallback = (VRM.glTF_VRM_extensions vrm) => GetVrmMaterialGenerator(m_useUrpMaterial.isOn, vrm);
|
||||
VrmUtility.MetaCallback metaCallback = m_texts.UpdateMeta;
|
||||
var instance = await VrmUtility.LoadAsync(path, GetIAwaitCaller(m_useAsync.isOn), materialCallback, metaCallback);
|
||||
SetModel(instance);
|
||||
break;
|
||||
}
|
||||
|
||||
case ".bvh":
|
||||
LoadMotion(path, File.ReadAllText(path));
|
||||
|
|
@ -431,59 +438,6 @@ namespace VRM.SimpleViewer
|
|||
}
|
||||
}
|
||||
|
||||
async void LoadModelAsync(string path, bool isVrm)
|
||||
{
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Debug.LogFormat("{0}", path);
|
||||
|
||||
GltfData data;
|
||||
try
|
||||
{
|
||||
data = new AutoGltfFileParser(path).Parse();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogWarningFormat("parse error: {0}", ex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isVrm)
|
||||
{
|
||||
try
|
||||
{
|
||||
var vrm = new VRMData(data);
|
||||
using (var loader = new VRMImporterContext(vrm, materialGenerator: GetVrmMaterialGenerator(m_useUrpMaterial.isOn, vrm.VrmExtension)))
|
||||
{
|
||||
await m_texts.UpdateMetaAsync(loader);
|
||||
var instance = await loader.LoadAsync(GetIAwaitCaller(m_useAsync.isOn));
|
||||
SetModel(instance);
|
||||
}
|
||||
}
|
||||
catch (NotVrm0Exception)
|
||||
{
|
||||
// retry
|
||||
Debug.LogWarning("file extension is vrm. but not vrm ?");
|
||||
using (var loader = new UniGLTF.ImporterContext(data, materialGenerator: GetGltfMaterialGenerator(m_useUrpMaterial.isOn)))
|
||||
{
|
||||
var instance = await loader.LoadAsync(GetIAwaitCaller(m_useAsync.isOn));
|
||||
SetModel(instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
using (var loader = new UniGLTF.ImporterContext(data, materialGenerator: GetGltfMaterialGenerator(m_useUrpMaterial.isOn)))
|
||||
{
|
||||
var instance = await loader.LoadAsync(GetIAwaitCaller(m_useAsync.isOn));
|
||||
SetModel(instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SetModel(RuntimeGltfInstance instance)
|
||||
{
|
||||
// cleanup
|
||||
|
|
@ -495,7 +449,7 @@ namespace VRM.SimpleViewer
|
|||
|
||||
if (m_useFastSpringBone.isOn)
|
||||
{
|
||||
FastSpringBoneReplacer.ReplaceAsync(instance.Root);
|
||||
var _ = FastSpringBoneReplacer.ReplaceAsync(instance.Root);
|
||||
}
|
||||
|
||||
instance.EnableUpdateWhenOffscreen();
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user