mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-05-15 07:00:10 -05:00
Merge pull request #1736 from ousttrue/fix/pass_gltf_validator
[exporter] fix for gltf_validator
This commit is contained in:
commit
085c33e774
|
|
@ -75,6 +75,10 @@ namespace UniGLTF
|
|||
return new StringKeyDictionarySerialization(t,
|
||||
GetSerialization(t.GetGenericArguments()[1], path, attr, prefix));
|
||||
}
|
||||
else if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>))
|
||||
{
|
||||
return new NullableSerialization(t.GetGenericArguments()[0], path, attr, prefix);
|
||||
}
|
||||
|
||||
// GetCollectionType(fi.FieldType, out suffix, out t);
|
||||
if (t == typeof(sbyte))
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public class NullableSerialization : IValueSerialization
|
||||
{
|
||||
public NullableSerialization(Type t, string path, JsonSchemaAttribute attr, string prefix)
|
||||
{
|
||||
if (t != typeof(int))
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public Type ValueType => typeof(Int32);
|
||||
public bool IsInline => true;
|
||||
|
||||
public string CreateSerializationCondition(string argName, JsonSchemaAttribute t)
|
||||
{
|
||||
return $"{argName}.HasValue";
|
||||
}
|
||||
|
||||
public string GenerateSerializerCall(string callName, string argName)
|
||||
{
|
||||
return $"f.Value({argName}.Value)";
|
||||
}
|
||||
|
||||
public void GenerateSerializer(StreamWriter writer, string callName)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public string GenerateDeserializerCall(string callName, string argName)
|
||||
{
|
||||
return argName + ".GetInt32()";
|
||||
}
|
||||
|
||||
public void GenerateDeserializer(StreamWriter writer, string callName)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 84c7673bb94af9f419ca9839910fd8be
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -272,14 +272,14 @@ public static void Serialize_gltf_accessors_ITEM(JsonFormatter f, glTFAccessor v
|
|||
f.BeginMap();
|
||||
|
||||
|
||||
if(value.bufferView>=0){
|
||||
if(value.bufferView.HasValue){
|
||||
f.Key("bufferView");
|
||||
f.Value(value.bufferView);
|
||||
f.Value(value.bufferView.Value);
|
||||
}
|
||||
|
||||
if(value.byteOffset>=0){
|
||||
if(value.byteOffset.HasValue){
|
||||
f.Key("byteOffset");
|
||||
f.Value(value.byteOffset);
|
||||
f.Value(value.byteOffset.Value);
|
||||
}
|
||||
|
||||
if(!string.IsNullOrEmpty(value.type)){
|
||||
|
|
|
|||
|
|
@ -93,10 +93,10 @@ namespace UniGLTF
|
|||
public class glTFAccessor
|
||||
{
|
||||
[JsonSchema(Minimum = 0)]
|
||||
public int bufferView = -1;
|
||||
public int? bufferView;
|
||||
|
||||
[JsonSchema(Minimum = 0, Dependencies = new string[] { "bufferView" })]
|
||||
public int byteOffset;
|
||||
public int? byteOffset;
|
||||
|
||||
[JsonSchema(Required = true, EnumValues = new object[] { "SCALAR", "VEC2", "VEC3", "VEC4", "MAT2", "MAT3", "MAT4" }, EnumSerializationType = EnumSerializationType.AsString)]
|
||||
public string type;
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ namespace UniGLTF
|
|||
var accessorIndex = Gltf.accessors.Count;
|
||||
Gltf.accessors.Add(new glTFAccessor
|
||||
{
|
||||
byteOffset = 0,
|
||||
byteOffset = default,
|
||||
componentType = glTFExtensions.GetComponentType<T>(),
|
||||
type = glTFExtensions.GetAccessorType<T>(),
|
||||
count = accessorCount,
|
||||
|
|
|
|||
|
|
@ -166,7 +166,7 @@ namespace UniGLTF
|
|||
NativeArray<T> GetTypedFromAccessor<T>(glTFAccessor accessor, glTFBufferView view) where T : struct
|
||||
{
|
||||
var bytes = GetBytesFromBufferView(view);
|
||||
return bytes.GetSubArray(accessor.byteOffset, bytes.Length - accessor.byteOffset).Reinterpret<T>(1).GetSubArray(0, accessor.count);
|
||||
return bytes.GetSubArray(accessor.byteOffset.GetValueOrDefault(), bytes.Length - accessor.byteOffset.GetValueOrDefault()).Reinterpret<T>(1).GetSubArray(0, accessor.count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -208,8 +208,8 @@ namespace UniGLTF
|
|||
public BufferAccessor GetIndicesFromAccessorIndex(int accessorIndex)
|
||||
{
|
||||
var accessor = GLTF.accessors[accessorIndex];
|
||||
var view = GLTF.bufferViews[accessor.bufferView];
|
||||
return GetIntIndicesFromView(view, accessor.count, accessor.byteOffset, accessor.componentType);
|
||||
var view = GLTF.bufferViews[accessor.bufferView.Value];
|
||||
return GetIntIndicesFromView(view, accessor.count, accessor.byteOffset.GetValueOrDefault(), accessor.componentType);
|
||||
}
|
||||
|
||||
public NativeArray<T> GetArrayFromAccessor<T>(int accessorIndex) where T : struct
|
||||
|
|
@ -218,8 +218,8 @@ namespace UniGLTF
|
|||
|
||||
if (vertexAccessor.count <= 0) return NativeArrayManager.CreateNativeArray<T>(0);
|
||||
|
||||
var result = (vertexAccessor.bufferView != -1)
|
||||
? GetTypedFromAccessor<T>(vertexAccessor, GLTF.bufferViews[vertexAccessor.bufferView])
|
||||
var result = (vertexAccessor.bufferView.HasValue)
|
||||
? GetTypedFromAccessor<T>(vertexAccessor, GLTF.bufferViews[vertexAccessor.bufferView.Value])
|
||||
: NativeArrayManager.CreateNativeArray<T>(vertexAccessor.count)
|
||||
;
|
||||
|
||||
|
|
@ -277,11 +277,11 @@ namespace UniGLTF
|
|||
var bufferCount = vertexAccessor.count * vertexAccessor.TypeCount;
|
||||
|
||||
NativeArray<float> result = default;
|
||||
if (vertexAccessor.bufferView != -1)
|
||||
if (vertexAccessor.bufferView.HasValue)
|
||||
{
|
||||
var view = GLTF.bufferViews[vertexAccessor.bufferView];
|
||||
var view = GLTF.bufferViews[vertexAccessor.bufferView.Value];
|
||||
var segment = GetBytesFromBuffer(view.buffer);
|
||||
result = segment.GetSubArray(view.byteOffset + vertexAccessor.byteOffset, vertexAccessor.count * 4 * vertexAccessor.TypeCount).Reinterpret<float>(1);
|
||||
result = segment.GetSubArray(view.byteOffset + vertexAccessor.byteOffset.GetValueOrDefault(), vertexAccessor.count * 4 * vertexAccessor.TypeCount).Reinterpret<float>(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ namespace UniGLTF
|
|||
{
|
||||
public static class GltfJsonUtil
|
||||
{
|
||||
const string EXTENSION_USED_KEY = "extensionUsed";
|
||||
public const string EXTENSION_USED_KEY = "extensionsUsed";
|
||||
|
||||
/// <summary>
|
||||
/// JsonPath を 再帰的に列挙する
|
||||
|
|
@ -96,14 +96,14 @@ namespace UniGLTF
|
|||
return false;
|
||||
}
|
||||
|
||||
static void CopyJson(IReadOnlyList<string> extensionUsed, JsonFormatter dst, JsonNode src, int level)
|
||||
static void CopyJson(IReadOnlyList<string> extensionsUsed, JsonFormatter dst, JsonNode src, int level)
|
||||
{
|
||||
if (src.IsArray())
|
||||
{
|
||||
dst.BeginList();
|
||||
foreach (var v in src.ArrayItems())
|
||||
{
|
||||
CopyJson(extensionUsed, dst, v, level + 1);
|
||||
CopyJson(extensionsUsed, dst, v, level + 1);
|
||||
}
|
||||
dst.EndList();
|
||||
}
|
||||
|
|
@ -119,7 +119,7 @@ namespace UniGLTF
|
|||
var key = kv.Key.GetString();
|
||||
if (key == EXTENSION_USED_KEY)
|
||||
{
|
||||
if (extensionUsed.Count == 0)
|
||||
if (extensionsUsed.Count == 0)
|
||||
{
|
||||
// skip
|
||||
}
|
||||
|
|
@ -128,7 +128,7 @@ namespace UniGLTF
|
|||
dst.Key(key);
|
||||
// replace
|
||||
dst.BeginList();
|
||||
foreach (var ex in extensionUsed)
|
||||
foreach (var ex in extensionsUsed)
|
||||
{
|
||||
dst.Value(ex);
|
||||
}
|
||||
|
|
@ -140,15 +140,15 @@ namespace UniGLTF
|
|||
else
|
||||
{
|
||||
dst.Key(key);
|
||||
CopyJson(extensionUsed, dst, kv.Value, level + 1);
|
||||
CopyJson(extensionsUsed, dst, kv.Value, level + 1);
|
||||
}
|
||||
}
|
||||
if (!done && level == 0 && extensionUsed.Count > 0)
|
||||
if (!done && level == 0 && extensionsUsed.Count > 0)
|
||||
{
|
||||
// add
|
||||
dst.Key(EXTENSION_USED_KEY);
|
||||
dst.BeginList();
|
||||
foreach (var ex in extensionUsed)
|
||||
foreach (var ex in extensionsUsed)
|
||||
{
|
||||
dst.Value(ex);
|
||||
}
|
||||
|
|
@ -162,7 +162,7 @@ namespace UniGLTF
|
|||
foreach (var kv in src.ObjectItems())
|
||||
{
|
||||
dst.Key(kv.Key.GetUtf8String());
|
||||
CopyJson(extensionUsed, dst, kv.Value, level + 1);
|
||||
CopyJson(extensionsUsed, dst, kv.Value, level + 1);
|
||||
}
|
||||
dst.EndMap();
|
||||
}
|
||||
|
|
@ -177,7 +177,7 @@ namespace UniGLTF
|
|||
/// <summary>
|
||||
/// https://github.com/KhronosGroup/glTF/blob/main/specification/2.0/schema/glTF.schema.json
|
||||
///
|
||||
/// extensionUsed の更新を各拡張自身にやらせるのは無駄だし、手動でコントロールするのも間違いの元である。
|
||||
/// extensionsUsed の更新を各拡張自身にやらせるのは無駄だし、手動でコントロールするのも間違いの元である。
|
||||
/// 完成品の JSON から後付けで作ることにした。
|
||||
///
|
||||
/// * Exporter しか使わない処理なので、GC, 処理速度は気にしてない
|
||||
|
|
|
|||
|
|
@ -48,6 +48,8 @@ namespace UniGLTF
|
|||
positionAccessorIndex = data.ExtendSparseBufferAndGetAccessorIndex(accessorCount,
|
||||
sparseIndices.Select(x => positions[x]).ToArray(), sparseIndices, sparseIndicesViewIndex,
|
||||
glBufferTarget.NONE);
|
||||
data.Gltf.accessors[positionAccessorIndex].min = positions.Aggregate(positions[0], (a, b) => new Vector3(Mathf.Min(a.x, b.x), Math.Min(a.y, b.y), Mathf.Min(a.z, b.z))).ToArray();
|
||||
data.Gltf.accessors[positionAccessorIndex].max = positions.Aggregate(positions[0], (a, b) => new Vector3(Mathf.Max(a.x, b.x), Math.Max(a.y, b.y), Mathf.Max(a.z, b.z))).ToArray();
|
||||
}
|
||||
|
||||
// normals
|
||||
|
|
|
|||
|
|
@ -51,18 +51,6 @@ namespace UniGLTF
|
|||
return new MaterialExporter();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// このエクスポーターがサポートするExtension
|
||||
/// </summary>
|
||||
protected virtual IEnumerable<string> ExtensionUsed
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return glTF_KHR_materials_unlit.ExtensionName;
|
||||
yield return glTF_KHR_texture_transform.ExtensionName;
|
||||
}
|
||||
}
|
||||
|
||||
protected ITextureExporter TextureExporter => _textureExporter;
|
||||
private TextureExporter _textureExporter;
|
||||
|
||||
|
|
@ -86,8 +74,6 @@ namespace UniGLTF
|
|||
{
|
||||
_data = data;
|
||||
|
||||
_gltf.extensionsUsed.AddRange(ExtensionUsed);
|
||||
|
||||
_gltf.asset = new glTFAssets
|
||||
{
|
||||
generator = "UniGLTF-" + UniGLTFVersion.VERSION,
|
||||
|
|
@ -353,7 +339,7 @@ namespace UniGLTF
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// GlbLowPevelParser.FixNameUnique で付与した Suffix を remove
|
||||
/// GlbLowLevelParser.FixNameUnique で付与した Suffix を remove
|
||||
/// </summary>
|
||||
public static void FixName(glTF gltf)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ namespace UniGLTF
|
|||
public class GltfJsonUtilTests
|
||||
{
|
||||
[Test]
|
||||
public void Update_extensionUsed()
|
||||
public void Update_extensionsUsed()
|
||||
{
|
||||
var dst = GltfJsonUtil.FindUsedExtensionsAndUpdateJson(@"{
|
||||
""asset"": {
|
||||
|
|
@ -44,11 +44,11 @@ namespace UniGLTF
|
|||
var parsed = dst.ParseAsJson();
|
||||
|
||||
Assert.AreEqual(new string[] { "KHR_materials_unlit" },
|
||||
parsed["extensionUsed"].ArrayItems().Select(x => x.GetString()).ToArray());
|
||||
parsed[GltfJsonUtil.EXTENSION_USED_KEY].ArrayItems().Select(x => x.GetString()).ToArray());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Replace_extensionUsed()
|
||||
public void Replace_extensionsUsed()
|
||||
{
|
||||
var dst = GltfJsonUtil.FindUsedExtensionsAndUpdateJson(@"{
|
||||
""asset"": {
|
||||
|
|
@ -63,7 +63,7 @@ namespace UniGLTF
|
|||
]
|
||||
}
|
||||
],
|
||||
""extensionUsed"": [""dummy""],
|
||||
""extensionsUsed"": [""dummy""],
|
||||
""materials"": [
|
||||
{
|
||||
""pbrMetallicRoughness"": {
|
||||
|
|
@ -86,11 +86,11 @@ namespace UniGLTF
|
|||
var parsed = dst.ParseAsJson();
|
||||
|
||||
Assert.AreEqual(new string[] { "KHR_materials_unlit" },
|
||||
parsed["extensionUsed"].ArrayItems().Select(x => x.GetString()).ToArray());
|
||||
parsed[GltfJsonUtil.EXTENSION_USED_KEY].ArrayItems().Select(x => x.GetString()).ToArray());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Empty_extensionUsed()
|
||||
public void Empty_extensionsUsed()
|
||||
{
|
||||
var dst = GltfJsonUtil.FindUsedExtensionsAndUpdateJson(@"{
|
||||
""asset"": {
|
||||
|
|
@ -105,7 +105,7 @@ namespace UniGLTF
|
|||
]
|
||||
}
|
||||
],
|
||||
""extensionUsed"": [""dummy""] ,
|
||||
""extensionsUsed"": [""dummy""] ,
|
||||
""materials"": [
|
||||
{
|
||||
""pbrMetallicRoughness"": {
|
||||
|
|
@ -123,11 +123,11 @@ namespace UniGLTF
|
|||
}");
|
||||
|
||||
var parsed = dst.ParseAsJson();
|
||||
Assert.False(parsed.ContainsKey("extensionUsed"));
|
||||
Assert.False(parsed.ContainsKey(GltfJsonUtil.EXTENSION_USED_KEY));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Empty2_extensionUsed()
|
||||
public void Empty2_extensionsUsed()
|
||||
{
|
||||
var dst = GltfJsonUtil.FindUsedExtensionsAndUpdateJson(@"{
|
||||
""asset"": {
|
||||
|
|
@ -156,12 +156,11 @@ namespace UniGLTF
|
|||
""name"": ""Red""
|
||||
}
|
||||
],
|
||||
""extensionUsed"": [""dummy""]
|
||||
""extensionsUsed"": [""dummy""]
|
||||
}");
|
||||
|
||||
var parsed = dst.ParseAsJson();
|
||||
Assert.False(parsed.ContainsKey("extensionUsed"));
|
||||
Assert.False(parsed.ContainsKey(GltfJsonUtil.EXTENSION_USED_KEY));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,5 +18,27 @@ namespace UniVRM10
|
|||
index = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool TryGetValidIndex(this int? value, int count, out int index)
|
||||
{
|
||||
if (!value.HasValue)
|
||||
{
|
||||
index = -1;
|
||||
return false;
|
||||
}
|
||||
if (value < 0)
|
||||
{
|
||||
index = -1;
|
||||
return false;
|
||||
}
|
||||
if (value >= count)
|
||||
{
|
||||
index = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
index = value.Value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ namespace UniVRM10
|
|||
{
|
||||
var buffer = m_data.Bin;
|
||||
var byteSize = accessor.CalcByteSize();
|
||||
bytes = m_data.Bin.GetSubArray(view.byteOffset, view.byteLength).GetSubArray(accessor.byteOffset, byteSize);
|
||||
bytes = m_data.Bin.GetSubArray(view.byteOffset, view.byteLength).GetSubArray(accessor.byteOffset.GetValueOrDefault(), byteSize);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -226,7 +226,7 @@ namespace UniVRM10
|
|||
bool AccessorsIsContinuous(int[] accessorIndices)
|
||||
{
|
||||
var firstAccessor = Gltf.accessors[accessorIndices[0]];
|
||||
var firstView = Gltf.bufferViews[firstAccessor.bufferView];
|
||||
var firstView = Gltf.bufferViews[firstAccessor.bufferView.Value];
|
||||
var start = firstView.byteOffset + firstAccessor.byteOffset;
|
||||
var pos = start;
|
||||
foreach (var i in accessorIndices)
|
||||
|
|
@ -241,7 +241,7 @@ namespace UniVRM10
|
|||
return false;
|
||||
}
|
||||
|
||||
var view = Gltf.bufferViews[current.bufferView];
|
||||
var view = Gltf.bufferViews[current.bufferView.Value];
|
||||
if (pos != view.byteOffset + current.byteOffset)
|
||||
{
|
||||
return false;
|
||||
|
|
@ -267,8 +267,8 @@ namespace UniVRM10
|
|||
{
|
||||
// IndexBufferが連続して格納されている => Slice でいける
|
||||
var firstAccessor = Gltf.accessors[accessorIndices[0]];
|
||||
var firstView = Gltf.bufferViews[firstAccessor.bufferView];
|
||||
var start = firstView.byteOffset + firstAccessor.byteOffset;
|
||||
var firstView = Gltf.bufferViews[firstAccessor.bufferView.Value];
|
||||
var start = firstView.byteOffset + firstAccessor.byteOffset.GetValueOrDefault();
|
||||
if (!firstView.buffer.TryGetValidIndex(Gltf.buffers.Count, out int firstViewBufferIndex))
|
||||
{
|
||||
throw new Exception();
|
||||
|
|
@ -295,14 +295,14 @@ namespace UniVRM10
|
|||
{
|
||||
throw new ArgumentException($"accessor.type: {accessor.type}");
|
||||
}
|
||||
var view = Gltf.bufferViews[accessor.bufferView];
|
||||
var view = Gltf.bufferViews[accessor.bufferView.Value];
|
||||
if (!view.buffer.TryGetValidIndex(Gltf.buffers.Count, out int viewBufferIndex))
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
var buffer = Gltf.buffers[viewBufferIndex];
|
||||
var bin = GetBufferBytes(buffer);
|
||||
var start = view.byteOffset + accessor.byteOffset;
|
||||
var start = view.byteOffset + accessor.byteOffset.GetValueOrDefault();
|
||||
var bytes = bin.GetSubArray(start, accessor.count * accessor.GetStride());
|
||||
var dst = indices.Reinterpret<Int32>(1).GetSubArray(offset, accessor.count);
|
||||
offset += accessor.count;
|
||||
|
|
|
|||
|
|
@ -41,17 +41,45 @@ namespace UniVRM10
|
|||
return new MeshUpdater(data).Update(model);
|
||||
}
|
||||
|
||||
int AddBuffer(NativeArray<byte> bytes)
|
||||
int AddBuffer(NativeArray<byte> bytes, glBufferTarget target)
|
||||
{
|
||||
var bufferView = _buffer.Extend(bytes);
|
||||
var bufferView = _buffer.Extend(bytes, target);
|
||||
var index = _bufferViews.Count;
|
||||
_bufferViews.Add(bufferView);
|
||||
|
||||
// padding for 4byte alignment
|
||||
var mod = bytes.Length % 4;
|
||||
if (mod != 0)
|
||||
{
|
||||
_buffer.Extend(new ArraySegment<byte>(new byte[4 - mod]));
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
int AddAccessor<T>(NativeArray<T> span) where T : struct
|
||||
static (float[], float[]) GetMinMax(NativeArray<Vector3> v)
|
||||
{
|
||||
var bufferViewIndex = AddBuffer(span.Reinterpret<byte>(Marshal.SizeOf<T>()));
|
||||
var minX = float.PositiveInfinity;
|
||||
var minY = float.PositiveInfinity;
|
||||
var minZ = float.PositiveInfinity;
|
||||
var maxX = float.NegativeInfinity;
|
||||
var maxY = float.NegativeInfinity;
|
||||
var maxZ = float.NegativeInfinity;
|
||||
for (int i = 0; i < v.Length; ++i)
|
||||
{
|
||||
if (v[i].x < minX) minX = v[i].x;
|
||||
if (v[i].y < minY) minY = v[i].y;
|
||||
if (v[i].z < minZ) minZ = v[i].z;
|
||||
if (v[i].x > maxX) maxX = v[i].x;
|
||||
if (v[i].y > maxY) maxY = v[i].y;
|
||||
if (v[i].z > maxZ) maxZ = v[i].z;
|
||||
}
|
||||
return (new float[] { minX, minY, minZ }, new float[] { maxX, maxY, maxZ });
|
||||
}
|
||||
|
||||
int AddAccessor<T>(NativeArray<T> span, glBufferTarget target, bool minMaxBounds) where T : struct
|
||||
{
|
||||
var bufferViewIndex = AddBuffer(span.Reinterpret<byte>(Marshal.SizeOf<T>()), target);
|
||||
var accessor = new glTFAccessor
|
||||
{
|
||||
bufferView = bufferViewIndex,
|
||||
|
|
@ -60,18 +88,27 @@ namespace UniVRM10
|
|||
componentType = glTFExtensions.GetComponentType<T>(),
|
||||
type = glTFExtensions.GetAccessorType<T>(),
|
||||
};
|
||||
if (minMaxBounds)
|
||||
{
|
||||
if (span is NativeArray<Vector3> positions)
|
||||
{
|
||||
var (min, max) = GetMinMax(positions);
|
||||
accessor.min = min;
|
||||
accessor.max = max;
|
||||
}
|
||||
}
|
||||
var index = _accessors.Count;
|
||||
_accessors.Add(accessor);
|
||||
return index;
|
||||
}
|
||||
|
||||
int? AddAccessor<T>(BufferAccessor buffer) where T : struct
|
||||
int? AddAccessor<T>(BufferAccessor buffer, glBufferTarget target, bool minMaxBounds) where T : struct
|
||||
{
|
||||
if (buffer == null)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
return AddAccessor(buffer.GetSpan<T>());
|
||||
return AddAccessor(buffer.GetSpan<T>(), target, minMaxBounds);
|
||||
}
|
||||
|
||||
struct MorphAccessor
|
||||
|
|
@ -93,7 +130,7 @@ namespace UniVRM10
|
|||
foreach (var image in gltf.images)
|
||||
{
|
||||
var bytes = _data.GetBytesFromBufferView(image.bufferView);
|
||||
image.bufferView = AddBuffer(bytes);
|
||||
image.bufferView = AddBuffer(bytes, default);
|
||||
}
|
||||
|
||||
// copy mesh
|
||||
|
|
@ -130,7 +167,7 @@ namespace UniVRM10
|
|||
if (skinIndex == -1)
|
||||
{
|
||||
skinIndex = gltf.skins.Count;
|
||||
gltfSkin.inverseBindMatrices = AddAccessor(node.MeshGroup.Skin.InverseMatrices.GetSpan<Matrix4x4>());
|
||||
gltfSkin.inverseBindMatrices = AddAccessor(node.MeshGroup.Skin.InverseMatrices.GetSpan<Matrix4x4>(), default, false);
|
||||
gltf.skins.Add(gltfSkin);
|
||||
}
|
||||
else
|
||||
|
|
@ -169,6 +206,7 @@ namespace UniVRM10
|
|||
}
|
||||
|
||||
// replace
|
||||
gltf.buffers[0].byteLength = _buffer.Bytes.Count;
|
||||
gltf.bufferViews = _bufferViews;
|
||||
gltf.accessors = _accessors;
|
||||
|
||||
|
|
@ -216,20 +254,20 @@ namespace UniVRM10
|
|||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
var position = AddAccessor<Vector3>(mesh.VertexBuffer.Positions);
|
||||
var normal = AddAccessor<Vector3>(mesh.VertexBuffer.Normals);
|
||||
var uv = AddAccessor<Vector2>(mesh.VertexBuffer.TexCoords);
|
||||
var weights = AddAccessor<Vector4>(mesh.VertexBuffer.Weights);
|
||||
var joints = AddAccessor<UShort4>(mesh.VertexBuffer.Joints);
|
||||
var color = AddAccessor<Vector4>(mesh.VertexBuffer.Colors);
|
||||
var position = AddAccessor<Vector3>(mesh.VertexBuffer.Positions, glBufferTarget.ARRAY_BUFFER, true);
|
||||
var normal = AddAccessor<Vector3>(mesh.VertexBuffer.Normals, glBufferTarget.ARRAY_BUFFER, false);
|
||||
var uv = AddAccessor<Vector2>(mesh.VertexBuffer.TexCoords, glBufferTarget.ARRAY_BUFFER, false);
|
||||
var weights = AddAccessor<Vector4>(mesh.VertexBuffer.Weights, glBufferTarget.ARRAY_BUFFER, false);
|
||||
var joints = AddAccessor<UShort4>(mesh.VertexBuffer.Joints, glBufferTarget.ARRAY_BUFFER, false);
|
||||
var color = AddAccessor<Vector4>(mesh.VertexBuffer.Colors, glBufferTarget.ARRAY_BUFFER, false);
|
||||
|
||||
var morphTargets = new MorphAccessor[] { };
|
||||
if (mesh.MorphTargets != null)
|
||||
{
|
||||
morphTargets = mesh.MorphTargets.Select(x => new MorphAccessor
|
||||
{
|
||||
Position = AddAccessor<Vector3>(x.VertexBuffer.Positions),
|
||||
Normal = AddAccessor<Vector3>(x.VertexBuffer.Normals),
|
||||
Position = AddAccessor<Vector3>(x.VertexBuffer.Positions, glBufferTarget.ARRAY_BUFFER, true),
|
||||
Normal = AddAccessor<Vector3>(x.VertexBuffer.Normals, glBufferTarget.ARRAY_BUFFER, false),
|
||||
}).ToArray();
|
||||
}
|
||||
|
||||
|
|
@ -237,7 +275,7 @@ namespace UniVRM10
|
|||
foreach (var (gltfPrim, submesh) in Enumerable.Zip(gltfMesh.primitives, mesh.Submeshes, (l, r) => (l, r)))
|
||||
{
|
||||
var subIndices = indices.GetSubArray(submesh.Offset, submesh.DrawCount);
|
||||
gltfPrim.indices = AddAccessor(subIndices);
|
||||
gltfPrim.indices = AddAccessor(subIndices, glBufferTarget.ELEMENT_ARRAY_BUFFER, false);
|
||||
gltfPrim.attributes.POSITION = position.Value;
|
||||
gltfPrim.attributes.NORMAL = normal.GetValueOrDefault(-1); // たぶん、ありえる
|
||||
gltfPrim.attributes.TANGENT = -1;
|
||||
|
|
@ -300,24 +338,24 @@ namespace UniVRM10
|
|||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
var position = AddAccessor<Vector3>(mesh.VertexBuffer.Positions);
|
||||
var normal = AddAccessor<Vector3>(mesh.VertexBuffer.Normals);
|
||||
var uv = AddAccessor<Vector2>(mesh.VertexBuffer.TexCoords);
|
||||
var weights = AddAccessor<Vector4>(mesh.VertexBuffer.Weights);
|
||||
var joints = AddAccessor<UShort4>(mesh.VertexBuffer.Joints);
|
||||
var color = AddAccessor<Vector4>(mesh.VertexBuffer.Colors);
|
||||
var position = AddAccessor<Vector3>(mesh.VertexBuffer.Positions, glBufferTarget.ARRAY_BUFFER, true);
|
||||
var normal = AddAccessor<Vector3>(mesh.VertexBuffer.Normals, glBufferTarget.ARRAY_BUFFER, false);
|
||||
var uv = AddAccessor<Vector2>(mesh.VertexBuffer.TexCoords, glBufferTarget.ARRAY_BUFFER, false);
|
||||
var weights = AddAccessor<Vector4>(mesh.VertexBuffer.Weights, glBufferTarget.ARRAY_BUFFER, false);
|
||||
var joints = AddAccessor<UShort4>(mesh.VertexBuffer.Joints, glBufferTarget.ARRAY_BUFFER, false);
|
||||
var color = AddAccessor<Vector4>(mesh.VertexBuffer.Colors, glBufferTarget.ARRAY_BUFFER, false);
|
||||
|
||||
var morphTargets = new MorphAccessor[] { };
|
||||
if (mesh.MorphTargets != null)
|
||||
{
|
||||
morphTargets = mesh.MorphTargets.Select(x => new MorphAccessor
|
||||
{
|
||||
Position = AddAccessor<Vector3>(x.VertexBuffer.Positions),
|
||||
Normal = AddAccessor<Vector3>(x.VertexBuffer.Normals),
|
||||
Position = AddAccessor<Vector3>(x.VertexBuffer.Positions, glBufferTarget.ARRAY_BUFFER, true),
|
||||
Normal = AddAccessor<Vector3>(x.VertexBuffer.Normals, glBufferTarget.ARRAY_BUFFER, false),
|
||||
}).ToArray();
|
||||
}
|
||||
|
||||
gltfPrim.indices = AddAccessor(indices);
|
||||
gltfPrim.indices = AddAccessor(indices, glBufferTarget.ELEMENT_ARRAY_BUFFER, false);
|
||||
gltfPrim.attributes.POSITION = position.Value;
|
||||
gltfPrim.attributes.NORMAL = normal.GetValueOrDefault(-1); // たぶん、ありえる
|
||||
gltfPrim.attributes.TANGENT = -1;
|
||||
|
|
|
|||
|
|
@ -61,9 +61,9 @@ namespace UniVRM10
|
|||
|
||||
var accessor = data.GLTF.accessors[accessorIndex];
|
||||
var bufferViewIndex = -1;
|
||||
if (accessor.bufferView != -1)
|
||||
if (accessor.bufferView.HasValue)
|
||||
{
|
||||
bufferViewIndex = accessor.bufferView;
|
||||
bufferViewIndex = accessor.bufferView.Value;
|
||||
}
|
||||
else if (accessor.sparse?.values != null && accessor.sparse.values.bufferView != -1)
|
||||
{
|
||||
|
|
@ -113,7 +113,7 @@ namespace UniVRM10
|
|||
if (used.Add(skin.inverseBindMatrices))
|
||||
{
|
||||
var accessor = data.GLTF.accessors[skin.inverseBindMatrices];
|
||||
var buffer = data.GetBytesFromBufferView(accessor.bufferView);
|
||||
var buffer = data.GetBytesFromBufferView(accessor.bufferView.Value);
|
||||
var span = buffer.Reinterpret<UnityEngine.Matrix4x4>(1);
|
||||
for (int i = 0; i < span.Length; ++i)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -257,11 +257,70 @@ namespace UniVRM10
|
|||
[Test]
|
||||
public void MigrateMeta()
|
||||
{
|
||||
using (var data = new GlbFileParser(AliciaPath).Parse())
|
||||
{
|
||||
using (var migrated = Vrm10Data.Migrate(data, out Vrm10Data vrm, out MigrationData migration))
|
||||
{
|
||||
Assert.NotNull(vrm);
|
||||
Assert.NotNull(migration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class TempFile : IDisposable
|
||||
{
|
||||
public string Path { get; }
|
||||
|
||||
TempFile(string path)
|
||||
{
|
||||
Path = path;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// File.Delete(Path);
|
||||
}
|
||||
|
||||
public static TempFile Create(string path, byte[] bytes)
|
||||
{
|
||||
File.WriteAllBytes(path, bytes);
|
||||
return new TempFile(path);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GltfValidator()
|
||||
{
|
||||
if (!VRMShaders.PathObject.TryGetFromEnvironmentVariable("GLTF_VALIDATOR", out var exe))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!exe.Exists)
|
||||
{
|
||||
return;
|
||||
}
|
||||
using (var data = new GlbFileParser(AliciaPath).Parse())
|
||||
using (var migrated = Vrm10Data.Migrate(data, out Vrm10Data vrm, out MigrationData migration))
|
||||
{
|
||||
Assert.NotNull(vrm);
|
||||
Assert.NotNull(migration);
|
||||
var json = GltfJsonUtil.FindUsedExtensionsAndUpdateJson(migrated.Json);
|
||||
var glb = Glb.Create(json, new ArraySegment<byte>(migrated.Bin.ToArray())).ToBytes();
|
||||
using (var tmp = TempFile.Create("GltfValidator_tmp.glb", glb))
|
||||
{
|
||||
var processStartInfo = new System.Diagnostics.ProcessStartInfo(exe.FullPath, $"{tmp.Path} -o")
|
||||
{
|
||||
CreateNoWindow = true,
|
||||
UseShellExecute = false,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
};
|
||||
|
||||
var process = System.Diagnostics.Process.Start(processStartInfo);
|
||||
string standardOutput = process.StandardOutput.ReadToEnd();
|
||||
string standardError = process.StandardError.ReadToEnd();
|
||||
int exitCode = process.ExitCode;
|
||||
Debug.Log($"{exitCode}\n{standardOutput}\n{standardError}\n");
|
||||
Assert.AreEqual(0, exitCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@ namespace VRMShaders
|
|||
|
||||
public bool IsUnderAsset => IsDescendantOf(UnityAssets);
|
||||
|
||||
public bool Exists => System.IO.File.Exists(FullPath);
|
||||
|
||||
/// <summary>
|
||||
/// AssetDatabase の引き数になるパスを想定。
|
||||
/// Assets のひとつ上を 基準とする相対パス。
|
||||
|
|
@ -136,6 +138,18 @@ namespace VRMShaders
|
|||
return true;
|
||||
}
|
||||
|
||||
public static bool TryGetFromEnvironmentVariable(string key, out PathObject dst)
|
||||
{
|
||||
var value = System.Environment.GetEnvironmentVariable(key);
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
dst = default;
|
||||
return false;
|
||||
}
|
||||
dst = PathObject.FromFullPath(value);
|
||||
return true;
|
||||
}
|
||||
|
||||
public PathObject Child(string child)
|
||||
{
|
||||
return FromFullPath(Path.Combine(FullPath, child));
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user