mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-09-08 20:08:53 -05:00
UniGLTF/Runtime/UniGLTF/Format の UnityEngine 依存を除去
This commit is contained in:
431
Assets/UniGLTF/Runtime/Extensions/glTFExtensions.cs
Normal file
431
Assets/UniGLTF/Runtime/Extensions/glTFExtensions.cs
Normal file
@@ -0,0 +1,431 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using UnityEngine;
|
||||
using System.IO;
|
||||
using UniJSON;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
[Serializable, StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct UShort4
|
||||
{
|
||||
public ushort x;
|
||||
public ushort y;
|
||||
public ushort z;
|
||||
public ushort w;
|
||||
|
||||
public UShort4(ushort _x, ushort _y, ushort _z, ushort _w)
|
||||
{
|
||||
x = _x;
|
||||
y = _y;
|
||||
z = _z;
|
||||
w = _w;
|
||||
}
|
||||
}
|
||||
|
||||
public static class glTFExtensions
|
||||
{
|
||||
struct ComponentVec
|
||||
{
|
||||
public glComponentType ComponentType;
|
||||
public int ElementCount;
|
||||
|
||||
public ComponentVec(glComponentType componentType, int elementCount)
|
||||
{
|
||||
ComponentType = componentType;
|
||||
ElementCount = elementCount;
|
||||
}
|
||||
}
|
||||
|
||||
static Dictionary<Type, ComponentVec> ComponentTypeMap = new Dictionary<Type, ComponentVec>
|
||||
{
|
||||
{ typeof(Vector2), new ComponentVec(glComponentType.FLOAT, 2) },
|
||||
{ typeof(Vector3), new ComponentVec(glComponentType.FLOAT, 3) },
|
||||
{ typeof(Vector4), new ComponentVec(glComponentType.FLOAT, 4) },
|
||||
{ typeof(UShort4), new ComponentVec(glComponentType.UNSIGNED_SHORT, 4) },
|
||||
{ typeof(Matrix4x4), new ComponentVec(glComponentType.FLOAT, 16) },
|
||||
{ typeof(Color), new ComponentVec(glComponentType.FLOAT, 4) },
|
||||
};
|
||||
|
||||
static glComponentType GetComponentType<T>()
|
||||
{
|
||||
var cv = default(ComponentVec);
|
||||
if (ComponentTypeMap.TryGetValue(typeof(T), out cv))
|
||||
{
|
||||
return cv.ComponentType;
|
||||
}
|
||||
else if (typeof(T) == typeof(uint))
|
||||
{
|
||||
return glComponentType.UNSIGNED_INT;
|
||||
}
|
||||
else if (typeof(T) == typeof(float))
|
||||
{
|
||||
return glComponentType.FLOAT;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException(typeof(T).Name);
|
||||
}
|
||||
}
|
||||
|
||||
static string GetAccessorType<T>()
|
||||
{
|
||||
var cv = default(ComponentVec);
|
||||
if (ComponentTypeMap.TryGetValue(typeof(T), out cv))
|
||||
{
|
||||
switch (cv.ElementCount)
|
||||
{
|
||||
case 2: return "VEC2";
|
||||
case 3: return "VEC3";
|
||||
case 4: return "VEC4";
|
||||
case 16: return "MAT4";
|
||||
default: throw new Exception();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return "SCALAR";
|
||||
}
|
||||
}
|
||||
|
||||
static int GetAccessorElementCount<T>()
|
||||
{
|
||||
var cv = default(ComponentVec);
|
||||
if (ComponentTypeMap.TryGetValue(typeof(T), out cv))
|
||||
{
|
||||
return cv.ElementCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
public static int ExtendBufferAndGetAccessorIndex<T>(this glTF gltf, int bufferIndex, T[] array,
|
||||
glBufferTarget target = glBufferTarget.NONE) where T : struct
|
||||
{
|
||||
return gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, new ArraySegment<T>(array), target);
|
||||
}
|
||||
|
||||
public static int ExtendBufferAndGetAccessorIndex<T>(this glTF gltf, int bufferIndex,
|
||||
ArraySegment<T> array,
|
||||
glBufferTarget target = glBufferTarget.NONE) where T : struct
|
||||
{
|
||||
if (array.Count == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
var viewIndex = ExtendBufferAndGetViewIndex(gltf, bufferIndex, array, target);
|
||||
|
||||
// index buffer's byteStride is unnecessary
|
||||
gltf.bufferViews[viewIndex].byteStride = 0;
|
||||
|
||||
var accessorIndex = gltf.accessors.Count;
|
||||
gltf.accessors.Add(new glTFAccessor
|
||||
{
|
||||
bufferView = viewIndex,
|
||||
byteOffset = 0,
|
||||
componentType = GetComponentType<T>(),
|
||||
type = GetAccessorType<T>(),
|
||||
count = array.Count,
|
||||
});
|
||||
return accessorIndex;
|
||||
}
|
||||
|
||||
public static int ExtendBufferAndGetViewIndex<T>(this glTF gltf, int bufferIndex,
|
||||
T[] array,
|
||||
glBufferTarget target = glBufferTarget.NONE) where T : struct
|
||||
{
|
||||
return ExtendBufferAndGetViewIndex(gltf, bufferIndex, new ArraySegment<T>(array), target);
|
||||
}
|
||||
|
||||
public static int ExtendBufferAndGetViewIndex<T>(this glTF gltf, int bufferIndex,
|
||||
ArraySegment<T> array,
|
||||
glBufferTarget target = glBufferTarget.NONE) where T : struct
|
||||
{
|
||||
if (array.Count == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
var view = gltf.buffers[bufferIndex].Append(array, target);
|
||||
var viewIndex = gltf.bufferViews.Count;
|
||||
gltf.bufferViews.Add(view);
|
||||
return viewIndex;
|
||||
}
|
||||
|
||||
public static int ExtendSparseBufferAndGetAccessorIndex<T>(this glTF gltf, int bufferIndex,
|
||||
int accessorCount,
|
||||
T[] sparseValues, int[] sparseIndices, int sparseViewIndex,
|
||||
glBufferTarget target = glBufferTarget.NONE) where T : struct
|
||||
{
|
||||
return ExtendSparseBufferAndGetAccessorIndex(gltf, bufferIndex,
|
||||
accessorCount,
|
||||
new ArraySegment<T>(sparseValues), sparseIndices, sparseViewIndex,
|
||||
target);
|
||||
}
|
||||
|
||||
public static int ExtendSparseBufferAndGetAccessorIndex<T>(this glTF gltf, int bufferIndex,
|
||||
int accessorCount,
|
||||
ArraySegment<T> sparseValues, int[] sparseIndices, int sparseIndicesViewIndex,
|
||||
glBufferTarget target = glBufferTarget.NONE) where T : struct
|
||||
{
|
||||
if (sparseValues.Count == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
var sparseValuesViewIndex = ExtendBufferAndGetViewIndex(gltf, bufferIndex, sparseValues, target);
|
||||
var accessorIndex = gltf.accessors.Count;
|
||||
gltf.accessors.Add(new glTFAccessor
|
||||
{
|
||||
byteOffset = 0,
|
||||
componentType = GetComponentType<T>(),
|
||||
type = GetAccessorType<T>(),
|
||||
count = accessorCount,
|
||||
|
||||
sparse = new glTFSparse
|
||||
{
|
||||
count = sparseIndices.Length,
|
||||
indices = new glTFSparseIndices
|
||||
{
|
||||
bufferView = sparseIndicesViewIndex,
|
||||
componentType = glComponentType.UNSIGNED_INT
|
||||
},
|
||||
values = new glTFSparseValues
|
||||
{
|
||||
bufferView = sparseValuesViewIndex,
|
||||
}
|
||||
}
|
||||
});
|
||||
return accessorIndex;
|
||||
}
|
||||
|
||||
public static int AddBuffer(this glTF self, IBytesBuffer bytesBuffer)
|
||||
{
|
||||
var index = self.buffers.Count;
|
||||
self.buffers.Add(new glTFBuffer(bytesBuffer));
|
||||
return index;
|
||||
}
|
||||
|
||||
static T[] GetAttrib<T>(this glTF self, int count, int byteOffset, glTFBufferView view) where T : struct
|
||||
{
|
||||
var attrib = new T[count];
|
||||
var segment = self.buffers[view.buffer].GetBytes();
|
||||
var bytes = new ArraySegment<Byte>(segment.Array, segment.Offset + view.byteOffset + byteOffset, count * view.byteStride);
|
||||
bytes.MarshalCopyTo(attrib);
|
||||
return attrib;
|
||||
}
|
||||
|
||||
static T[] GetAttrib<T>(this glTF self, glTFAccessor accessor, glTFBufferView view) where T : struct
|
||||
{
|
||||
return self.GetAttrib<T>(accessor.count, accessor.byteOffset, view);
|
||||
}
|
||||
|
||||
static IEnumerable<int> _GetIndices(this glTF self, glTFAccessor accessor, out int count)
|
||||
{
|
||||
count = accessor.count;
|
||||
var view = self.bufferViews[accessor.bufferView];
|
||||
switch ((glComponentType)accessor.componentType)
|
||||
{
|
||||
case glComponentType.UNSIGNED_BYTE:
|
||||
{
|
||||
return self.GetAttrib<Byte>(accessor, view).Select(x => (int)(x));
|
||||
}
|
||||
|
||||
case glComponentType.UNSIGNED_SHORT:
|
||||
{
|
||||
return self.GetAttrib<UInt16>(accessor, view).Select(x => (int)(x));
|
||||
}
|
||||
|
||||
case glComponentType.UNSIGNED_INT:
|
||||
{
|
||||
return self.GetAttrib<UInt32>(accessor, view).Select(x => (int)(x));
|
||||
}
|
||||
}
|
||||
throw new NotImplementedException("GetIndices: unknown componenttype: " + accessor.componentType);
|
||||
}
|
||||
|
||||
static IEnumerable<int> _GetIndices(this glTF self, glTFBufferView view, int count, int byteOffset, glComponentType componentType)
|
||||
{
|
||||
switch (componentType)
|
||||
{
|
||||
case glComponentType.UNSIGNED_BYTE:
|
||||
{
|
||||
return self.GetAttrib<Byte>(count, byteOffset, view).Select(x => (int)(x));
|
||||
}
|
||||
|
||||
case glComponentType.UNSIGNED_SHORT:
|
||||
{
|
||||
return self.GetAttrib<UInt16>(count, byteOffset, view).Select(x => (int)(x));
|
||||
}
|
||||
|
||||
case glComponentType.UNSIGNED_INT:
|
||||
{
|
||||
return self.GetAttrib<UInt32>(count, byteOffset, view).Select(x => (int)(x));
|
||||
}
|
||||
}
|
||||
throw new NotImplementedException("GetIndices: unknown componenttype: " + componentType);
|
||||
}
|
||||
|
||||
public static int[] GetIndices(this glTF self, int accessorIndex)
|
||||
{
|
||||
int count;
|
||||
var result = self._GetIndices(self.accessors[accessorIndex], out count);
|
||||
var indices = new int[count];
|
||||
|
||||
// flip triangles
|
||||
var it = result.GetEnumerator();
|
||||
{
|
||||
for (int i = 0; i < count; i += 3)
|
||||
{
|
||||
it.MoveNext(); indices[i + 2] = it.Current;
|
||||
it.MoveNext(); indices[i + 1] = it.Current;
|
||||
it.MoveNext(); indices[i] = it.Current;
|
||||
}
|
||||
}
|
||||
|
||||
return indices;
|
||||
}
|
||||
|
||||
public static T[] GetArrayFromAccessor<T>(this glTF self, int accessorIndex) where T : struct
|
||||
{
|
||||
var vertexAccessor = self.accessors[accessorIndex];
|
||||
|
||||
if (vertexAccessor.count <= 0) return new T[] { };
|
||||
|
||||
var result = (vertexAccessor.bufferView != -1)
|
||||
? self.GetAttrib<T>(vertexAccessor, self.bufferViews[vertexAccessor.bufferView])
|
||||
: new T[vertexAccessor.count]
|
||||
;
|
||||
|
||||
var sparse = vertexAccessor.sparse;
|
||||
if (sparse != null && sparse.count > 0)
|
||||
{
|
||||
// override sparse values
|
||||
var indices = self._GetIndices(self.bufferViews[sparse.indices.bufferView], sparse.count, sparse.indices.byteOffset, sparse.indices.componentType);
|
||||
var values = self.GetAttrib<T>(sparse.count, sparse.values.byteOffset, self.bufferViews[sparse.values.bufferView]);
|
||||
|
||||
var it = indices.GetEnumerator();
|
||||
for (int i = 0; i < sparse.count; ++i)
|
||||
{
|
||||
it.MoveNext();
|
||||
result[it.Current] = values[i];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static ArraySegment<Byte> GetImageBytes(this glTF self, IStorage storage, int imageIndex, out string textureName)
|
||||
{
|
||||
var image = self.images[imageIndex];
|
||||
if (string.IsNullOrEmpty(image.uri))
|
||||
{
|
||||
//
|
||||
// use buffer view (GLB)
|
||||
//
|
||||
//m_imageBytes = ToArray(byteSegment);
|
||||
textureName = !string.IsNullOrEmpty(image.name) ? image.name : string.Format("{0:00}#GLB", imageIndex);
|
||||
return self.GetViewBytes(image.bufferView);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (image.uri.StartsWith("data:"))
|
||||
{
|
||||
textureName = !string.IsNullOrEmpty(image.name) ? image.name : string.Format("{0:00}#Base64Embedded", imageIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
textureName = !string.IsNullOrEmpty(image.name) ? image.name : Path.GetFileNameWithoutExtension(image.uri);
|
||||
}
|
||||
return storage.Get(image.uri);
|
||||
}
|
||||
}
|
||||
|
||||
static Utf8String s_extensions = Utf8String.From("extensions");
|
||||
|
||||
static bool UsedExtension(this glTF self, string key)
|
||||
{
|
||||
if (self.extensionsUsed.Contains(key))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void Traverse(this glTF self, ListTreeNode<JsonValue> node, JsonFormatter f, Utf8String parentKey)
|
||||
{
|
||||
if (node.IsMap())
|
||||
{
|
||||
f.BeginMap();
|
||||
foreach (var kv in node.ObjectItems())
|
||||
{
|
||||
if (parentKey == s_extensions)
|
||||
{
|
||||
if (!self.UsedExtension(kv.Key.GetString()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
f.Key(kv.Key.GetUtf8String());
|
||||
self.Traverse(kv.Value, f, kv.Key.GetUtf8String());
|
||||
}
|
||||
f.EndMap();
|
||||
}
|
||||
else if (node.IsArray())
|
||||
{
|
||||
f.BeginList();
|
||||
foreach (var x in node.ArrayItems())
|
||||
{
|
||||
self.Traverse(x, f, default(Utf8String));
|
||||
}
|
||||
f.EndList();
|
||||
}
|
||||
else
|
||||
{
|
||||
f.Value(node);
|
||||
}
|
||||
}
|
||||
|
||||
static string RemoveUnusedExtensions(this glTF self, string json)
|
||||
{
|
||||
var f = new JsonFormatter();
|
||||
self.Traverse(JsonParser.Parse(json), f, default(Utf8String));
|
||||
return f.ToString();
|
||||
}
|
||||
|
||||
public static byte[] ToGlbBytes(this glTF self)
|
||||
{
|
||||
var f = new JsonFormatter();
|
||||
GltfSerializer.Serialize(f, self);
|
||||
|
||||
var json = f.ToString().ParseAsJson().ToString(" ");
|
||||
|
||||
self.RemoveUnusedExtensions(json);
|
||||
|
||||
return Glb.ToBytes(json, self.buffers[0].GetBytes());
|
||||
}
|
||||
|
||||
public static (string, List<glTFBuffer>) ToGltf(this glTF self, string gltfPath)
|
||||
{
|
||||
var f = new JsonFormatter();
|
||||
|
||||
// fix buffer path
|
||||
if (self.buffers.Count == 1)
|
||||
{
|
||||
var withoutExt = Path.GetFileNameWithoutExtension(gltfPath);
|
||||
self.buffers[0].uri = $"{withoutExt}.bin";
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
GltfSerializer.Serialize(f, self);
|
||||
var json = f.ToString().ParseAsJson().ToString(" ");
|
||||
self.RemoveUnusedExtensions(json);
|
||||
return (json, self.buffers);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,203 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
[Serializable, StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct UShort4
|
||||
{
|
||||
public ushort x;
|
||||
public ushort y;
|
||||
public ushort z;
|
||||
public ushort w;
|
||||
|
||||
public UShort4(ushort _x, ushort _y, ushort _z, ushort _w)
|
||||
{
|
||||
x = _x;
|
||||
y = _y;
|
||||
z = _z;
|
||||
w = _w;
|
||||
}
|
||||
}
|
||||
|
||||
public static class glTFExtensions
|
||||
{
|
||||
struct ComponentVec
|
||||
{
|
||||
public glComponentType ComponentType;
|
||||
public int ElementCount;
|
||||
|
||||
public ComponentVec(glComponentType componentType, int elementCount)
|
||||
{
|
||||
ComponentType = componentType;
|
||||
ElementCount = elementCount;
|
||||
}
|
||||
}
|
||||
|
||||
static Dictionary<Type, ComponentVec> ComponentTypeMap = new Dictionary<Type, ComponentVec>
|
||||
{
|
||||
{ typeof(Vector2), new ComponentVec(glComponentType.FLOAT, 2) },
|
||||
{ typeof(Vector3), new ComponentVec(glComponentType.FLOAT, 3) },
|
||||
{ typeof(Vector4), new ComponentVec(glComponentType.FLOAT, 4) },
|
||||
{ typeof(UShort4), new ComponentVec(glComponentType.UNSIGNED_SHORT, 4) },
|
||||
{ typeof(Matrix4x4), new ComponentVec(glComponentType.FLOAT, 16) },
|
||||
{ typeof(Color), new ComponentVec(glComponentType.FLOAT, 4) },
|
||||
};
|
||||
|
||||
static glComponentType GetComponentType<T>()
|
||||
{
|
||||
var cv = default(ComponentVec);
|
||||
if (ComponentTypeMap.TryGetValue(typeof(T), out cv))
|
||||
{
|
||||
return cv.ComponentType;
|
||||
}
|
||||
else if (typeof(T) == typeof(uint))
|
||||
{
|
||||
return glComponentType.UNSIGNED_INT;
|
||||
}
|
||||
else if (typeof(T) == typeof(float))
|
||||
{
|
||||
return glComponentType.FLOAT;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException(typeof(T).Name);
|
||||
}
|
||||
}
|
||||
|
||||
static string GetAccessorType<T>()
|
||||
{
|
||||
var cv = default(ComponentVec);
|
||||
if (ComponentTypeMap.TryGetValue(typeof(T), out cv))
|
||||
{
|
||||
switch (cv.ElementCount)
|
||||
{
|
||||
case 2: return "VEC2";
|
||||
case 3: return "VEC3";
|
||||
case 4: return "VEC4";
|
||||
case 16: return "MAT4";
|
||||
default: throw new Exception();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return "SCALAR";
|
||||
}
|
||||
}
|
||||
|
||||
static int GetAccessorElementCount<T>()
|
||||
{
|
||||
var cv = default(ComponentVec);
|
||||
if (ComponentTypeMap.TryGetValue(typeof(T), out cv))
|
||||
{
|
||||
return cv.ElementCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
public static int ExtendBufferAndGetAccessorIndex<T>(this glTF gltf, int bufferIndex, T[] array,
|
||||
glBufferTarget target = glBufferTarget.NONE) where T : struct
|
||||
{
|
||||
return gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, new ArraySegment<T>(array), target);
|
||||
}
|
||||
|
||||
public static int ExtendBufferAndGetAccessorIndex<T>(this glTF gltf, int bufferIndex,
|
||||
ArraySegment<T> array,
|
||||
glBufferTarget target = glBufferTarget.NONE) where T : struct
|
||||
{
|
||||
if (array.Count == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
var viewIndex = ExtendBufferAndGetViewIndex(gltf, bufferIndex, array, target);
|
||||
|
||||
// index buffer's byteStride is unnecessary
|
||||
gltf.bufferViews[viewIndex].byteStride = 0;
|
||||
|
||||
var accessorIndex = gltf.accessors.Count;
|
||||
gltf.accessors.Add(new glTFAccessor
|
||||
{
|
||||
bufferView = viewIndex,
|
||||
byteOffset = 0,
|
||||
componentType = GetComponentType<T>(),
|
||||
type = GetAccessorType<T>(),
|
||||
count = array.Count,
|
||||
});
|
||||
return accessorIndex;
|
||||
}
|
||||
|
||||
public static int ExtendBufferAndGetViewIndex<T>(this glTF gltf, int bufferIndex,
|
||||
T[] array,
|
||||
glBufferTarget target = glBufferTarget.NONE) where T : struct
|
||||
{
|
||||
return ExtendBufferAndGetViewIndex(gltf, bufferIndex, new ArraySegment<T>(array), target);
|
||||
}
|
||||
|
||||
public static int ExtendBufferAndGetViewIndex<T>(this glTF gltf, int bufferIndex,
|
||||
ArraySegment<T> array,
|
||||
glBufferTarget target = glBufferTarget.NONE) where T : struct
|
||||
{
|
||||
if (array.Count == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
var view = gltf.buffers[bufferIndex].Append(array, target);
|
||||
var viewIndex = gltf.bufferViews.Count;
|
||||
gltf.bufferViews.Add(view);
|
||||
return viewIndex;
|
||||
}
|
||||
|
||||
public static int ExtendSparseBufferAndGetAccessorIndex<T>(this glTF gltf, int bufferIndex,
|
||||
int accessorCount,
|
||||
T[] sparseValues, int[] sparseIndices, int sparseViewIndex,
|
||||
glBufferTarget target = glBufferTarget.NONE) where T : struct
|
||||
{
|
||||
return ExtendSparseBufferAndGetAccessorIndex(gltf, bufferIndex,
|
||||
accessorCount,
|
||||
new ArraySegment<T>(sparseValues), sparseIndices, sparseViewIndex,
|
||||
target);
|
||||
}
|
||||
|
||||
public static int ExtendSparseBufferAndGetAccessorIndex<T>(this glTF gltf, int bufferIndex,
|
||||
int accessorCount,
|
||||
ArraySegment<T> sparseValues, int[] sparseIndices, int sparseIndicesViewIndex,
|
||||
glBufferTarget target = glBufferTarget.NONE) where T : struct
|
||||
{
|
||||
if (sparseValues.Count == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
var sparseValuesViewIndex = ExtendBufferAndGetViewIndex(gltf, bufferIndex, sparseValues, target);
|
||||
var accessorIndex = gltf.accessors.Count;
|
||||
gltf.accessors.Add(new glTFAccessor
|
||||
{
|
||||
byteOffset = 0,
|
||||
componentType = GetComponentType<T>(),
|
||||
type = GetAccessorType<T>(),
|
||||
count = accessorCount,
|
||||
|
||||
sparse = new glTFSparse
|
||||
{
|
||||
count=sparseIndices.Length,
|
||||
indices = new glTFSparseIndices
|
||||
{
|
||||
bufferView = sparseIndicesViewIndex,
|
||||
componentType = glComponentType.UNSIGNED_INT
|
||||
},
|
||||
values = new glTFSparseValues
|
||||
{
|
||||
bufferView = sparseValuesViewIndex,
|
||||
}
|
||||
}
|
||||
});
|
||||
return accessorIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
|
||||
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 ArraySegment<byte> GetBytes()
|
||||
{
|
||||
return m_bytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f857b8b7ca45b1746af90c7fb86b2398
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -2,7 +2,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UniJSON;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
@@ -90,21 +89,21 @@ namespace UniGLTF
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void Serialize(glTFTextureInfo info, Vector2 offset, Vector2 scale)
|
||||
public static void Serialize(glTFTextureInfo info, (float, float) offset, (float, float) scale)
|
||||
{
|
||||
var f = new JsonFormatter();
|
||||
f.BeginMap();
|
||||
|
||||
f.Key("offset");
|
||||
f.BeginList();
|
||||
f.Value(offset.x);
|
||||
f.Value(offset.y);
|
||||
f.Value(offset.Item1);
|
||||
f.Value(offset.Item2);
|
||||
f.EndList();
|
||||
|
||||
f.Key("scale");
|
||||
f.BeginList();
|
||||
f.Value(scale.x);
|
||||
f.Value(scale.y);
|
||||
f.Value(scale.Item1);
|
||||
f.Value(scale.Item2);
|
||||
f.EndList();
|
||||
|
||||
f.EndMap();
|
||||
|
||||
11
Assets/UniGLTF/Runtime/UniGLTF/Format/IBytesBuffer.cs
Normal file
11
Assets/UniGLTF/Runtime/UniGLTF/Format/IBytesBuffer.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using System;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public interface IBytesBuffer
|
||||
{
|
||||
string Uri { get; }
|
||||
ArraySegment<Byte> GetBytes();
|
||||
glTFBufferView Extend<T>(ArraySegment<T> array, glBufferTarget target) where T : struct;
|
||||
}
|
||||
}
|
||||
11
Assets/UniGLTF/Runtime/UniGLTF/Format/IBytesBuffer.cs.meta
Normal file
11
Assets/UniGLTF/Runtime/UniGLTF/Format/IBytesBuffer.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2ce69a95857efe041a1e3dd9d2e6c98b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
16
Assets/UniGLTF/Runtime/UniGLTF/Format/IStorage.cs
Normal file
16
Assets/UniGLTF/Runtime/UniGLTF/Format/IStorage.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public interface IStorage
|
||||
{
|
||||
ArraySegment<Byte> Get(string url);
|
||||
|
||||
/// <summary>
|
||||
/// Get original filepath if exists
|
||||
/// </summary>
|
||||
/// <param name="url"></param>
|
||||
/// <returns></returns>
|
||||
string GetPath(string url);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9cb8b6f878e36a74f90d172daee60bed
|
||||
timeCreated: 1529327531
|
||||
licenseType: Free
|
||||
guid: 6e3316b83a7396047839d12538e5db52
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
@@ -28,12 +28,6 @@ namespace UniGLTF
|
||||
#region Buffer
|
||||
[JsonSchema(MinItems = 1, ExplicitIgnorableItemLength = 0)]
|
||||
public List<glTFBuffer> buffers = new List<glTFBuffer>();
|
||||
public int AddBuffer(IBytesBuffer bytesBuffer)
|
||||
{
|
||||
var index = buffers.Count;
|
||||
buffers.Add(new glTFBuffer(bytesBuffer));
|
||||
return index;
|
||||
}
|
||||
|
||||
[JsonSchema(MinItems = 1, ExplicitIgnorableItemLength = 0)]
|
||||
public List<glTFBufferView> bufferViews = new List<glTFBufferView>();
|
||||
@@ -47,119 +41,12 @@ namespace UniGLTF
|
||||
[JsonSchema(MinItems = 1, ExplicitIgnorableItemLength = 0)]
|
||||
public List<glTFAccessor> accessors = new List<glTFAccessor>();
|
||||
|
||||
T[] GetAttrib<T>(glTFAccessor accessor, glTFBufferView view) where T : struct
|
||||
{
|
||||
return GetAttrib<T>(accessor.count, accessor.byteOffset, view);
|
||||
}
|
||||
T[] GetAttrib<T>(int count, int byteOffset, glTFBufferView view) where T : struct
|
||||
{
|
||||
var attrib = new T[count];
|
||||
var segment = buffers[view.buffer].GetBytes();
|
||||
var bytes = new ArraySegment<Byte>(segment.Array, segment.Offset + view.byteOffset + byteOffset, count * view.byteStride);
|
||||
bytes.MarshalCopyTo(attrib);
|
||||
return attrib;
|
||||
}
|
||||
|
||||
public ArraySegment<Byte> GetViewBytes(int bufferView)
|
||||
{
|
||||
var view = bufferViews[bufferView];
|
||||
var segment = buffers[view.buffer].GetBytes();
|
||||
return new ArraySegment<byte>(segment.Array, segment.Offset + view.byteOffset, view.byteLength);
|
||||
}
|
||||
|
||||
IEnumerable<int> _GetIndices(glTFAccessor accessor, out int count)
|
||||
{
|
||||
count = accessor.count;
|
||||
var view = bufferViews[accessor.bufferView];
|
||||
switch ((glComponentType)accessor.componentType)
|
||||
{
|
||||
case glComponentType.UNSIGNED_BYTE:
|
||||
{
|
||||
return GetAttrib<Byte>(accessor, view).Select(x => (int)(x));
|
||||
}
|
||||
|
||||
case glComponentType.UNSIGNED_SHORT:
|
||||
{
|
||||
return GetAttrib<UInt16>(accessor, view).Select(x => (int)(x));
|
||||
}
|
||||
|
||||
case glComponentType.UNSIGNED_INT:
|
||||
{
|
||||
return GetAttrib<UInt32>(accessor, view).Select(x => (int)(x));
|
||||
}
|
||||
}
|
||||
throw new NotImplementedException("GetIndices: unknown componenttype: " + accessor.componentType);
|
||||
}
|
||||
|
||||
IEnumerable<int> _GetIndices(glTFBufferView view, int count, int byteOffset, glComponentType componentType)
|
||||
{
|
||||
switch (componentType)
|
||||
{
|
||||
case glComponentType.UNSIGNED_BYTE:
|
||||
{
|
||||
return GetAttrib<Byte>(count, byteOffset, view).Select(x => (int)(x));
|
||||
}
|
||||
|
||||
case glComponentType.UNSIGNED_SHORT:
|
||||
{
|
||||
return GetAttrib<UInt16>(count, byteOffset, view).Select(x => (int)(x));
|
||||
}
|
||||
|
||||
case glComponentType.UNSIGNED_INT:
|
||||
{
|
||||
return GetAttrib<UInt32>(count, byteOffset, view).Select(x => (int)(x));
|
||||
}
|
||||
}
|
||||
throw new NotImplementedException("GetIndices: unknown componenttype: " + componentType);
|
||||
}
|
||||
|
||||
public int[] GetIndices(int accessorIndex)
|
||||
{
|
||||
int count;
|
||||
var result = _GetIndices(accessors[accessorIndex], out count);
|
||||
var indices = new int[count];
|
||||
|
||||
// flip triangles
|
||||
var it = result.GetEnumerator();
|
||||
{
|
||||
for (int i = 0; i < count; i += 3)
|
||||
{
|
||||
it.MoveNext(); indices[i + 2] = it.Current;
|
||||
it.MoveNext(); indices[i + 1] = it.Current;
|
||||
it.MoveNext(); indices[i] = it.Current;
|
||||
}
|
||||
}
|
||||
|
||||
return indices;
|
||||
}
|
||||
|
||||
public T[] GetArrayFromAccessor<T>(int accessorIndex) where T : struct
|
||||
{
|
||||
var vertexAccessor = accessors[accessorIndex];
|
||||
|
||||
if (vertexAccessor.count <= 0) return new T[] { };
|
||||
|
||||
var result = (vertexAccessor.bufferView != -1)
|
||||
? GetAttrib<T>(vertexAccessor, bufferViews[vertexAccessor.bufferView])
|
||||
: new T[vertexAccessor.count]
|
||||
;
|
||||
|
||||
var sparse = vertexAccessor.sparse;
|
||||
if (sparse != null && sparse.count > 0)
|
||||
{
|
||||
// override sparse values
|
||||
var indices = _GetIndices(bufferViews[sparse.indices.bufferView], sparse.count, sparse.indices.byteOffset, sparse.indices.componentType);
|
||||
var values = GetAttrib<T>(sparse.count, sparse.values.byteOffset, bufferViews[sparse.values.bufferView]);
|
||||
|
||||
var it = indices.GetEnumerator();
|
||||
for (int i = 0; i < sparse.count; ++i)
|
||||
{
|
||||
it.MoveNext();
|
||||
result[it.Current] = values[i];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#endregion
|
||||
|
||||
[JsonSchema(MinItems = 1, ExplicitIgnorableItemLength = 0)]
|
||||
@@ -196,32 +83,6 @@ namespace UniGLTF
|
||||
return GetSampler(samplerIndex);
|
||||
}
|
||||
|
||||
public ArraySegment<Byte> GetImageBytes(IStorage storage, int imageIndex, out string textureName)
|
||||
{
|
||||
var image = images[imageIndex];
|
||||
if (string.IsNullOrEmpty(image.uri))
|
||||
{
|
||||
//
|
||||
// use buffer view (GLB)
|
||||
//
|
||||
//m_imageBytes = ToArray(byteSegment);
|
||||
textureName = !string.IsNullOrEmpty(image.name) ? image.name : string.Format("{0:00}#GLB", imageIndex);
|
||||
return GetViewBytes(image.bufferView);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (image.uri.StartsWith("data:"))
|
||||
{
|
||||
textureName = !string.IsNullOrEmpty(image.name) ? image.name : string.Format("{0:00}#Base64Embedded", imageIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
textureName = !string.IsNullOrEmpty(image.name) ? image.name : Path.GetFileNameWithoutExtension(image.uri);
|
||||
}
|
||||
return storage.Get(image.uri);
|
||||
}
|
||||
}
|
||||
|
||||
[JsonSchema(MinItems = 1, ExplicitIgnorableItemLength = 0)]
|
||||
public List<glTFMaterial> materials = new List<glTFMaterial>();
|
||||
public string GetUniqueMaterialName(int index)
|
||||
@@ -321,94 +182,5 @@ namespace UniGLTF
|
||||
&& animations.SequenceEqual(other.animations)
|
||||
;
|
||||
}
|
||||
|
||||
bool UsedExtension(string key)
|
||||
{
|
||||
if (extensionsUsed.Contains(key))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static Utf8String s_extensions = Utf8String.From("extensions");
|
||||
|
||||
void Traverse(ListTreeNode<JsonValue> node, JsonFormatter f, Utf8String parentKey)
|
||||
{
|
||||
if (node.IsMap())
|
||||
{
|
||||
f.BeginMap();
|
||||
foreach (var kv in node.ObjectItems())
|
||||
{
|
||||
if (parentKey == s_extensions)
|
||||
{
|
||||
if (!UsedExtension(kv.Key.GetString()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
f.Key(kv.Key.GetUtf8String());
|
||||
Traverse(kv.Value, f, kv.Key.GetUtf8String());
|
||||
}
|
||||
f.EndMap();
|
||||
}
|
||||
else if (node.IsArray())
|
||||
{
|
||||
f.BeginList();
|
||||
foreach (var x in node.ArrayItems())
|
||||
{
|
||||
Traverse(x, f, default(Utf8String));
|
||||
}
|
||||
f.EndList();
|
||||
}
|
||||
else
|
||||
{
|
||||
f.Value(node);
|
||||
}
|
||||
}
|
||||
|
||||
string RemoveUnusedExtensions(string json)
|
||||
{
|
||||
var f = new JsonFormatter();
|
||||
|
||||
Traverse(JsonParser.Parse(json), f, default(Utf8String));
|
||||
|
||||
return f.ToString();
|
||||
}
|
||||
|
||||
public byte[] ToGlbBytes()
|
||||
{
|
||||
var f = new JsonFormatter();
|
||||
GltfSerializer.Serialize(f, this);
|
||||
|
||||
var json = f.ToString().ParseAsJson().ToString(" ");
|
||||
|
||||
RemoveUnusedExtensions(json);
|
||||
|
||||
return Glb.ToBytes(json, buffers[0].GetBytes());
|
||||
}
|
||||
|
||||
public (string, List<glTFBuffer>) ToGltf(string gltfPath)
|
||||
{
|
||||
var f = new JsonFormatter();
|
||||
|
||||
// fix buffer path
|
||||
if (buffers.Count == 1)
|
||||
{
|
||||
var withoutExt = Path.GetFileNameWithoutExtension(gltfPath);
|
||||
buffers[0].uri = $"{withoutExt}.bin";
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
GltfSerializer.Serialize(f, this);
|
||||
var json = f.ToString().ParseAsJson().ToString(" ");
|
||||
RemoveUnusedExtensions(json);
|
||||
return (json, buffers);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,13 +5,6 @@ using System.Runtime.InteropServices;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public interface IBytesBuffer
|
||||
{
|
||||
string Uri { get; }
|
||||
ArraySegment<Byte> GetBytes();
|
||||
glTFBufferView Extend<T>(ArraySegment<T> array, glBufferTarget target) where T : struct;
|
||||
}
|
||||
|
||||
public static class IBytesBufferExtensions
|
||||
{
|
||||
public static glTFBufferView Extend<T>(this IBytesBuffer buffer, T[] array, glBufferTarget target) where T : struct
|
||||
@@ -88,34 +81,6 @@ 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 ArraySegment<byte> GetBytes()
|
||||
{
|
||||
return m_bytes;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// for exporter
|
||||
@@ -1,7 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 33b0000c5446b7547bcad1da1e9768ed
|
||||
timeCreated: 1516730619
|
||||
licenseType: Free
|
||||
guid: 1e9c9201942704b4f9dd050115073032
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
@@ -1,26 +1,13 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public interface IStorage
|
||||
{
|
||||
ArraySegment<Byte> Get(string url);
|
||||
|
||||
/// <summary>
|
||||
/// Get original filepath if exists
|
||||
/// </summary>
|
||||
/// <param name="url"></param>
|
||||
/// <returns></returns>
|
||||
string GetPath(string url);
|
||||
}
|
||||
|
||||
public class SimpleStorage : IStorage
|
||||
{
|
||||
ArraySegment<Byte> m_bytes;
|
||||
|
||||
public SimpleStorage():this(new ArraySegment<byte>())
|
||||
public SimpleStorage() : this(new ArraySegment<byte>())
|
||||
{
|
||||
}
|
||||
|
||||
11
Assets/UniGLTF/Runtime/UniGLTF/IO/FileSystemStorage.cs.meta
Normal file
11
Assets/UniGLTF/Runtime/UniGLTF/IO/FileSystemStorage.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ca59fdd271a96dd409ea98e128fbebca
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -190,7 +190,7 @@ namespace UniGLTF
|
||||
var scale = m.GetTextureScale(propertyName);
|
||||
offset.y = (offset.y + scale.y - 1) * -1.0f;
|
||||
|
||||
glTF_KHR_texture_transform.Serialize(textureInfo, offset, scale);
|
||||
glTF_KHR_texture_transform.Serialize(textureInfo, (offset.x, offset.y), (scale.x, scale.y));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using System.Reflection;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ namespace UniJSON
|
||||
f.Value(new ArraySegment<Byte>(bytes));
|
||||
}
|
||||
|
||||
#if UNITY_5_6_OR_NEWER
|
||||
public static void Value(this IFormatter f, UnityEngine.Vector2 v)
|
||||
{
|
||||
//CommaCheck();
|
||||
@@ -58,6 +59,7 @@ namespace UniJSON
|
||||
f.Key("w"); f.Value(v.w);
|
||||
f.EndMap();
|
||||
}
|
||||
#endif
|
||||
|
||||
static MethodInfo GetMethod<T>(Expression<Func<T>> expression)
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
#if UNITY_EDITOR && VRM_DEVELOP
|
||||
using UnityEngine;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using UnityEngine;
|
||||
using NUnit.Framework;
|
||||
using NUnit.Framework;
|
||||
using System.Collections;
|
||||
using System;
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
|
||||
@@ -142,8 +142,8 @@ namespace VRM.Samples
|
||||
var parsed = f.ToString().ParseAsJson();
|
||||
var newJson = parsed.ToString(" ");
|
||||
|
||||
File.WriteAllText("old.json", oldJson);
|
||||
File.WriteAllText("new.json", newJson);
|
||||
// File.WriteAllText("old.json", oldJson);
|
||||
// File.WriteAllText("new.json", newJson);
|
||||
|
||||
// 比較
|
||||
Assert.AreEqual(oldJson.ParseAsJson().ToString(), newJson.ParseAsJson().ToString());
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.IO;
|
||||
using UniGLTF;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using VRM;
|
||||
|
||||
Reference in New Issue
Block a user