mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-05-14 14:29:52 -05:00
Change directory structures: Move UniGLTF/Core/* -> UniGLTF/*. Remove UniGLTF/Core
This commit is contained in:
parent
f9e0e26786
commit
216ef2f867
|
|
@ -1,10 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d2d37db807d5f0946b5d264a870ac053
|
||||
folderAsset: yes
|
||||
timeCreated: 1517139118
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,180 +1,180 @@
|
|||
using NUnit.Framework;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public class MaterialTests
|
||||
{
|
||||
[Test]
|
||||
public void UnlitShaderImportTest()
|
||||
{
|
||||
var shaderStore = new ShaderStore(null);
|
||||
|
||||
{
|
||||
// OPAQUE/Color
|
||||
var shader = shaderStore.GetShader(new glTFMaterial
|
||||
{
|
||||
alphaMode = "OPAQUE",
|
||||
pbrMetallicRoughness = new glTFPbrMetallicRoughness
|
||||
{
|
||||
baseColorFactor = new float[] { 1, 0, 0, 1 },
|
||||
},
|
||||
extensions = new glTFMaterial_extensions
|
||||
{
|
||||
KHR_materials_unlit = new glTF_KHR_materials_unlit { }
|
||||
}
|
||||
});
|
||||
Assert.AreEqual("UniGLTF/UniUnlit", shader.name);
|
||||
}
|
||||
|
||||
{
|
||||
// OPAQUE/Texture
|
||||
var shader = shaderStore.GetShader(new glTFMaterial
|
||||
{
|
||||
alphaMode = "OPAQUE",
|
||||
pbrMetallicRoughness = new glTFPbrMetallicRoughness
|
||||
{
|
||||
baseColorTexture = new glTFMaterialBaseColorTextureInfo(),
|
||||
},
|
||||
extensions = new glTFMaterial_extensions
|
||||
{
|
||||
KHR_materials_unlit = new glTF_KHR_materials_unlit { }
|
||||
}
|
||||
});
|
||||
Assert.AreEqual("UniGLTF/UniUnlit", shader.name);
|
||||
}
|
||||
|
||||
{
|
||||
// OPAQUE/Color/Texture
|
||||
var shader = shaderStore.GetShader(new glTFMaterial
|
||||
{
|
||||
alphaMode = "OPAQUE",
|
||||
pbrMetallicRoughness = new glTFPbrMetallicRoughness
|
||||
{
|
||||
baseColorFactor = new float[] { 1, 0, 0, 1 },
|
||||
baseColorTexture = new glTFMaterialBaseColorTextureInfo(),
|
||||
},
|
||||
extensions = new glTFMaterial_extensions
|
||||
{
|
||||
KHR_materials_unlit = new glTF_KHR_materials_unlit { }
|
||||
}
|
||||
});
|
||||
Assert.AreEqual("UniGLTF/UniUnlit", shader.name);
|
||||
}
|
||||
|
||||
{
|
||||
// BLEND/Color
|
||||
var shader = shaderStore.GetShader(new glTFMaterial
|
||||
{
|
||||
alphaMode = "BLEND",
|
||||
pbrMetallicRoughness = new glTFPbrMetallicRoughness
|
||||
{
|
||||
baseColorFactor = new float[] { 1, 0, 0, 1 },
|
||||
},
|
||||
extensions = new glTFMaterial_extensions
|
||||
{
|
||||
KHR_materials_unlit = new glTF_KHR_materials_unlit { }
|
||||
}
|
||||
});
|
||||
Assert.AreEqual("UniGLTF/UniUnlit", shader.name);
|
||||
}
|
||||
|
||||
{
|
||||
// BLEND/Texture
|
||||
var shader = shaderStore.GetShader(new glTFMaterial
|
||||
{
|
||||
alphaMode = "BLEND",
|
||||
pbrMetallicRoughness = new glTFPbrMetallicRoughness
|
||||
{
|
||||
baseColorTexture = new glTFMaterialBaseColorTextureInfo(),
|
||||
},
|
||||
extensions = new glTFMaterial_extensions
|
||||
{
|
||||
KHR_materials_unlit = new glTF_KHR_materials_unlit { }
|
||||
}
|
||||
});
|
||||
Assert.AreEqual("UniGLTF/UniUnlit", shader.name);
|
||||
}
|
||||
|
||||
{
|
||||
// BLEND/Color/Texture
|
||||
var shader = shaderStore.GetShader(new glTFMaterial
|
||||
{
|
||||
alphaMode = "BLEND",
|
||||
pbrMetallicRoughness = new glTFPbrMetallicRoughness
|
||||
{
|
||||
baseColorFactor = new float[] { 1, 0, 0, 1 },
|
||||
baseColorTexture = new glTFMaterialBaseColorTextureInfo(),
|
||||
},
|
||||
extensions = new glTFMaterial_extensions
|
||||
{
|
||||
KHR_materials_unlit = new glTF_KHR_materials_unlit { }
|
||||
}
|
||||
});
|
||||
Assert.AreEqual("UniGLTF/UniUnlit", shader.name);
|
||||
}
|
||||
|
||||
{
|
||||
// MASK/Texture
|
||||
var shader = shaderStore.GetShader(new glTFMaterial
|
||||
{
|
||||
alphaMode = "MASK",
|
||||
pbrMetallicRoughness = new glTFPbrMetallicRoughness
|
||||
{
|
||||
baseColorTexture = new glTFMaterialBaseColorTextureInfo(),
|
||||
},
|
||||
extensions = new glTFMaterial_extensions
|
||||
{
|
||||
KHR_materials_unlit = new glTF_KHR_materials_unlit { }
|
||||
}
|
||||
});
|
||||
Assert.AreEqual("UniGLTF/UniUnlit", shader.name);
|
||||
}
|
||||
|
||||
{
|
||||
// MASK/Color/Texture
|
||||
var shader = shaderStore.GetShader(new glTFMaterial
|
||||
{
|
||||
alphaMode = "MASK",
|
||||
pbrMetallicRoughness = new glTFPbrMetallicRoughness
|
||||
{
|
||||
baseColorFactor = new float[] { 1, 0, 0, 1 },
|
||||
baseColorTexture = new glTFMaterialBaseColorTextureInfo(),
|
||||
},
|
||||
extensions = new glTFMaterial_extensions
|
||||
{
|
||||
KHR_materials_unlit = new glTF_KHR_materials_unlit { }
|
||||
}
|
||||
});
|
||||
Assert.AreEqual("UniGLTF/UniUnlit", shader.name);
|
||||
}
|
||||
|
||||
{
|
||||
// default
|
||||
var shader = shaderStore.GetShader(new glTFMaterial
|
||||
{
|
||||
extensions = new glTFMaterial_extensions
|
||||
{
|
||||
KHR_materials_unlit = new glTF_KHR_materials_unlit { }
|
||||
}
|
||||
});
|
||||
Assert.AreEqual("UniGLTF/UniUnlit", shader.name);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MaterialImportTest()
|
||||
{
|
||||
var shaderStore = new ShaderStore(null);
|
||||
var materialImporter = new MaterialImporter(shaderStore, null);
|
||||
|
||||
{
|
||||
var material = materialImporter.CreateMaterial(0, new glTFMaterial
|
||||
{
|
||||
|
||||
});
|
||||
Assert.AreEqual("Standard", material.shader.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using NUnit.Framework;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public class MaterialTests
|
||||
{
|
||||
[Test]
|
||||
public void UnlitShaderImportTest()
|
||||
{
|
||||
var shaderStore = new ShaderStore(null);
|
||||
|
||||
{
|
||||
// OPAQUE/Color
|
||||
var shader = shaderStore.GetShader(new glTFMaterial
|
||||
{
|
||||
alphaMode = "OPAQUE",
|
||||
pbrMetallicRoughness = new glTFPbrMetallicRoughness
|
||||
{
|
||||
baseColorFactor = new float[] { 1, 0, 0, 1 },
|
||||
},
|
||||
extensions = new glTFMaterial_extensions
|
||||
{
|
||||
KHR_materials_unlit = new glTF_KHR_materials_unlit { }
|
||||
}
|
||||
});
|
||||
Assert.AreEqual("UniGLTF/UniUnlit", shader.name);
|
||||
}
|
||||
|
||||
{
|
||||
// OPAQUE/Texture
|
||||
var shader = shaderStore.GetShader(new glTFMaterial
|
||||
{
|
||||
alphaMode = "OPAQUE",
|
||||
pbrMetallicRoughness = new glTFPbrMetallicRoughness
|
||||
{
|
||||
baseColorTexture = new glTFMaterialBaseColorTextureInfo(),
|
||||
},
|
||||
extensions = new glTFMaterial_extensions
|
||||
{
|
||||
KHR_materials_unlit = new glTF_KHR_materials_unlit { }
|
||||
}
|
||||
});
|
||||
Assert.AreEqual("UniGLTF/UniUnlit", shader.name);
|
||||
}
|
||||
|
||||
{
|
||||
// OPAQUE/Color/Texture
|
||||
var shader = shaderStore.GetShader(new glTFMaterial
|
||||
{
|
||||
alphaMode = "OPAQUE",
|
||||
pbrMetallicRoughness = new glTFPbrMetallicRoughness
|
||||
{
|
||||
baseColorFactor = new float[] { 1, 0, 0, 1 },
|
||||
baseColorTexture = new glTFMaterialBaseColorTextureInfo(),
|
||||
},
|
||||
extensions = new glTFMaterial_extensions
|
||||
{
|
||||
KHR_materials_unlit = new glTF_KHR_materials_unlit { }
|
||||
}
|
||||
});
|
||||
Assert.AreEqual("UniGLTF/UniUnlit", shader.name);
|
||||
}
|
||||
|
||||
{
|
||||
// BLEND/Color
|
||||
var shader = shaderStore.GetShader(new glTFMaterial
|
||||
{
|
||||
alphaMode = "BLEND",
|
||||
pbrMetallicRoughness = new glTFPbrMetallicRoughness
|
||||
{
|
||||
baseColorFactor = new float[] { 1, 0, 0, 1 },
|
||||
},
|
||||
extensions = new glTFMaterial_extensions
|
||||
{
|
||||
KHR_materials_unlit = new glTF_KHR_materials_unlit { }
|
||||
}
|
||||
});
|
||||
Assert.AreEqual("UniGLTF/UniUnlit", shader.name);
|
||||
}
|
||||
|
||||
{
|
||||
// BLEND/Texture
|
||||
var shader = shaderStore.GetShader(new glTFMaterial
|
||||
{
|
||||
alphaMode = "BLEND",
|
||||
pbrMetallicRoughness = new glTFPbrMetallicRoughness
|
||||
{
|
||||
baseColorTexture = new glTFMaterialBaseColorTextureInfo(),
|
||||
},
|
||||
extensions = new glTFMaterial_extensions
|
||||
{
|
||||
KHR_materials_unlit = new glTF_KHR_materials_unlit { }
|
||||
}
|
||||
});
|
||||
Assert.AreEqual("UniGLTF/UniUnlit", shader.name);
|
||||
}
|
||||
|
||||
{
|
||||
// BLEND/Color/Texture
|
||||
var shader = shaderStore.GetShader(new glTFMaterial
|
||||
{
|
||||
alphaMode = "BLEND",
|
||||
pbrMetallicRoughness = new glTFPbrMetallicRoughness
|
||||
{
|
||||
baseColorFactor = new float[] { 1, 0, 0, 1 },
|
||||
baseColorTexture = new glTFMaterialBaseColorTextureInfo(),
|
||||
},
|
||||
extensions = new glTFMaterial_extensions
|
||||
{
|
||||
KHR_materials_unlit = new glTF_KHR_materials_unlit { }
|
||||
}
|
||||
});
|
||||
Assert.AreEqual("UniGLTF/UniUnlit", shader.name);
|
||||
}
|
||||
|
||||
{
|
||||
// MASK/Texture
|
||||
var shader = shaderStore.GetShader(new glTFMaterial
|
||||
{
|
||||
alphaMode = "MASK",
|
||||
pbrMetallicRoughness = new glTFPbrMetallicRoughness
|
||||
{
|
||||
baseColorTexture = new glTFMaterialBaseColorTextureInfo(),
|
||||
},
|
||||
extensions = new glTFMaterial_extensions
|
||||
{
|
||||
KHR_materials_unlit = new glTF_KHR_materials_unlit { }
|
||||
}
|
||||
});
|
||||
Assert.AreEqual("UniGLTF/UniUnlit", shader.name);
|
||||
}
|
||||
|
||||
{
|
||||
// MASK/Color/Texture
|
||||
var shader = shaderStore.GetShader(new glTFMaterial
|
||||
{
|
||||
alphaMode = "MASK",
|
||||
pbrMetallicRoughness = new glTFPbrMetallicRoughness
|
||||
{
|
||||
baseColorFactor = new float[] { 1, 0, 0, 1 },
|
||||
baseColorTexture = new glTFMaterialBaseColorTextureInfo(),
|
||||
},
|
||||
extensions = new glTFMaterial_extensions
|
||||
{
|
||||
KHR_materials_unlit = new glTF_KHR_materials_unlit { }
|
||||
}
|
||||
});
|
||||
Assert.AreEqual("UniGLTF/UniUnlit", shader.name);
|
||||
}
|
||||
|
||||
{
|
||||
// default
|
||||
var shader = shaderStore.GetShader(new glTFMaterial
|
||||
{
|
||||
extensions = new glTFMaterial_extensions
|
||||
{
|
||||
KHR_materials_unlit = new glTF_KHR_materials_unlit { }
|
||||
}
|
||||
});
|
||||
Assert.AreEqual("UniGLTF/UniUnlit", shader.name);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MaterialImportTest()
|
||||
{
|
||||
var shaderStore = new ShaderStore(null);
|
||||
var materialImporter = new MaterialImporter(shaderStore, null);
|
||||
|
||||
{
|
||||
var material = materialImporter.CreateMaterial(0, new glTFMaterial
|
||||
{
|
||||
|
||||
});
|
||||
Assert.AreEqual("Standard", material.shader.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,195 +1,195 @@
|
|||
using NUnit.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UniJSON;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public class UniGLTFTests
|
||||
{
|
||||
static GameObject CreateSimpelScene()
|
||||
{
|
||||
var root = new GameObject("gltfRoot").transform;
|
||||
|
||||
var scene = new GameObject("scene0").transform;
|
||||
scene.SetParent(root, false);
|
||||
scene.localPosition = new Vector3(1, 2, 3);
|
||||
|
||||
return root.gameObject;
|
||||
}
|
||||
|
||||
void AssertAreEqual(Transform go, Transform other)
|
||||
{
|
||||
var lt = go.Traverse().GetEnumerator();
|
||||
var rt = go.Traverse().GetEnumerator();
|
||||
|
||||
while (lt.MoveNext())
|
||||
{
|
||||
if (!rt.MoveNext())
|
||||
{
|
||||
throw new Exception("rt shorter");
|
||||
}
|
||||
|
||||
MonoBehaviourComparator.AssertAreEquals(lt.Current.gameObject, rt.Current.gameObject);
|
||||
}
|
||||
|
||||
if (rt.MoveNext())
|
||||
{
|
||||
throw new Exception("rt longer");
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UniGLTFSimpleSceneTest()
|
||||
{
|
||||
var go = CreateSimpelScene();
|
||||
var context = new ImporterContext();
|
||||
|
||||
try
|
||||
{
|
||||
// export
|
||||
var gltf = new glTF();
|
||||
|
||||
string json = null;
|
||||
using (var exporter = new gltfExporter(gltf))
|
||||
{
|
||||
exporter.Prepare(go);
|
||||
exporter.Export();
|
||||
|
||||
// remove empty buffer
|
||||
gltf.buffers.Clear();
|
||||
|
||||
json = gltf.ToJson();
|
||||
}
|
||||
|
||||
// import
|
||||
context.ParseJson(json, new SimpleStorage(new ArraySegment<byte>()));
|
||||
//Debug.LogFormat("{0}", context.Json);
|
||||
context.Load();
|
||||
|
||||
AssertAreEqual(go.transform, context.Root.transform);
|
||||
}
|
||||
finally
|
||||
{
|
||||
//Debug.LogFormat("Destory, {0}", go.name);
|
||||
GameObject.DestroyImmediate(go);
|
||||
context.EditorDestroyRootAndAssets();
|
||||
}
|
||||
}
|
||||
|
||||
void BufferTest(int init, params int[] size)
|
||||
{
|
||||
var initBytes = init == 0 ? null : new byte[init];
|
||||
var storage = new ArrayByteBuffer(initBytes);
|
||||
var buffer = new glTFBuffer(storage);
|
||||
|
||||
var values = new List<byte>();
|
||||
int offset = 0;
|
||||
foreach (var x in size)
|
||||
{
|
||||
var nums = Enumerable.Range(offset, x).Select(y => (Byte)y).ToArray();
|
||||
values.AddRange(nums);
|
||||
var bytes = new ArraySegment<Byte>(nums);
|
||||
offset += x;
|
||||
buffer.Append(bytes, glBufferTarget.NONE);
|
||||
}
|
||||
|
||||
Assert.AreEqual(values.Count, buffer.byteLength);
|
||||
Assert.True(Enumerable.SequenceEqual(values, buffer.GetBytes().ToArray()));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BufferTest()
|
||||
{
|
||||
BufferTest(0, 0, 100, 200);
|
||||
BufferTest(0, 128);
|
||||
BufferTest(0, 256);
|
||||
|
||||
BufferTest(1024, 0);
|
||||
BufferTest(1024, 128);
|
||||
BufferTest(1024, 2048);
|
||||
BufferTest(1024, 900, 900);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UnityPathTest()
|
||||
{
|
||||
var root = UnityPath.FromUnityPath(".");
|
||||
Assert.IsFalse(root.IsNull);
|
||||
Assert.IsFalse(root.IsUnderAssetsFolder);
|
||||
Assert.AreEqual(UnityPath.FromUnityPath("."), root);
|
||||
|
||||
var assets = UnityPath.FromUnityPath("Assets");
|
||||
Assert.IsFalse(assets.IsNull);
|
||||
Assert.IsTrue(assets.IsUnderAssetsFolder);
|
||||
|
||||
var rootChild = root.Child("Assets");
|
||||
Assert.AreEqual(assets, rootChild);
|
||||
|
||||
var assetsChild = assets.Child("Hoge");
|
||||
var hoge = UnityPath.FromUnityPath("Assets/Hoge");
|
||||
Assert.AreEqual(assetsChild, hoge);
|
||||
|
||||
//var children = root.TravserseDir().ToArray();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void VersionChecker()
|
||||
{
|
||||
Assert.False(ImporterContext.IsGeneratedUniGLTFAndOlderThan("hoge", 1, 16));
|
||||
Assert.False(ImporterContext.IsGeneratedUniGLTFAndOlderThan("UniGLTF-1.16", 1, 16));
|
||||
Assert.True(ImporterContext.IsGeneratedUniGLTFAndOlderThan("UniGLTF-1.15", 1, 16));
|
||||
Assert.False(ImporterContext.IsGeneratedUniGLTFAndOlderThan("UniGLTF-11.16", 1, 16));
|
||||
Assert.True(ImporterContext.IsGeneratedUniGLTFAndOlderThan("UniGLTF-0.16", 1, 16));
|
||||
Assert.True(ImporterContext.IsGeneratedUniGLTFAndOlderThan("UniGLTF", 1, 16));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MeshTest()
|
||||
{
|
||||
var mesh = new glTFMesh("mesh")
|
||||
{
|
||||
primitives = new List<glTFPrimitives>
|
||||
{
|
||||
new glTFPrimitives
|
||||
{
|
||||
attributes=new glTFAttributes
|
||||
{
|
||||
POSITION=0,
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var f = new JsonFormatter();
|
||||
f.Serialize(mesh);
|
||||
|
||||
var json = new Utf8String(f.GetStoreBytes()).ToString();
|
||||
Debug.Log(json);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PrimitiveTest()
|
||||
{
|
||||
var prims = new List<glTFPrimitives> {
|
||||
new glTFPrimitives
|
||||
{
|
||||
attributes = new glTFAttributes
|
||||
{
|
||||
POSITION = 0,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var f = new JsonFormatter();
|
||||
f.Serialize(prims);
|
||||
|
||||
var json = new Utf8String(f.GetStoreBytes()).ToString();
|
||||
Debug.Log(json);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
using NUnit.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UniJSON;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public class UniGLTFTests
|
||||
{
|
||||
static GameObject CreateSimpelScene()
|
||||
{
|
||||
var root = new GameObject("gltfRoot").transform;
|
||||
|
||||
var scene = new GameObject("scene0").transform;
|
||||
scene.SetParent(root, false);
|
||||
scene.localPosition = new Vector3(1, 2, 3);
|
||||
|
||||
return root.gameObject;
|
||||
}
|
||||
|
||||
void AssertAreEqual(Transform go, Transform other)
|
||||
{
|
||||
var lt = go.Traverse().GetEnumerator();
|
||||
var rt = go.Traverse().GetEnumerator();
|
||||
|
||||
while (lt.MoveNext())
|
||||
{
|
||||
if (!rt.MoveNext())
|
||||
{
|
||||
throw new Exception("rt shorter");
|
||||
}
|
||||
|
||||
MonoBehaviourComparator.AssertAreEquals(lt.Current.gameObject, rt.Current.gameObject);
|
||||
}
|
||||
|
||||
if (rt.MoveNext())
|
||||
{
|
||||
throw new Exception("rt longer");
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UniGLTFSimpleSceneTest()
|
||||
{
|
||||
var go = CreateSimpelScene();
|
||||
var context = new ImporterContext();
|
||||
|
||||
try
|
||||
{
|
||||
// export
|
||||
var gltf = new glTF();
|
||||
|
||||
string json = null;
|
||||
using (var exporter = new gltfExporter(gltf))
|
||||
{
|
||||
exporter.Prepare(go);
|
||||
exporter.Export();
|
||||
|
||||
// remove empty buffer
|
||||
gltf.buffers.Clear();
|
||||
|
||||
json = gltf.ToJson();
|
||||
}
|
||||
|
||||
// import
|
||||
context.ParseJson(json, new SimpleStorage(new ArraySegment<byte>()));
|
||||
//Debug.LogFormat("{0}", context.Json);
|
||||
context.Load();
|
||||
|
||||
AssertAreEqual(go.transform, context.Root.transform);
|
||||
}
|
||||
finally
|
||||
{
|
||||
//Debug.LogFormat("Destory, {0}", go.name);
|
||||
GameObject.DestroyImmediate(go);
|
||||
context.EditorDestroyRootAndAssets();
|
||||
}
|
||||
}
|
||||
|
||||
void BufferTest(int init, params int[] size)
|
||||
{
|
||||
var initBytes = init == 0 ? null : new byte[init];
|
||||
var storage = new ArrayByteBuffer(initBytes);
|
||||
var buffer = new glTFBuffer(storage);
|
||||
|
||||
var values = new List<byte>();
|
||||
int offset = 0;
|
||||
foreach (var x in size)
|
||||
{
|
||||
var nums = Enumerable.Range(offset, x).Select(y => (Byte)y).ToArray();
|
||||
values.AddRange(nums);
|
||||
var bytes = new ArraySegment<Byte>(nums);
|
||||
offset += x;
|
||||
buffer.Append(bytes, glBufferTarget.NONE);
|
||||
}
|
||||
|
||||
Assert.AreEqual(values.Count, buffer.byteLength);
|
||||
Assert.True(Enumerable.SequenceEqual(values, buffer.GetBytes().ToArray()));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BufferTest()
|
||||
{
|
||||
BufferTest(0, 0, 100, 200);
|
||||
BufferTest(0, 128);
|
||||
BufferTest(0, 256);
|
||||
|
||||
BufferTest(1024, 0);
|
||||
BufferTest(1024, 128);
|
||||
BufferTest(1024, 2048);
|
||||
BufferTest(1024, 900, 900);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UnityPathTest()
|
||||
{
|
||||
var root = UnityPath.FromUnityPath(".");
|
||||
Assert.IsFalse(root.IsNull);
|
||||
Assert.IsFalse(root.IsUnderAssetsFolder);
|
||||
Assert.AreEqual(UnityPath.FromUnityPath("."), root);
|
||||
|
||||
var assets = UnityPath.FromUnityPath("Assets");
|
||||
Assert.IsFalse(assets.IsNull);
|
||||
Assert.IsTrue(assets.IsUnderAssetsFolder);
|
||||
|
||||
var rootChild = root.Child("Assets");
|
||||
Assert.AreEqual(assets, rootChild);
|
||||
|
||||
var assetsChild = assets.Child("Hoge");
|
||||
var hoge = UnityPath.FromUnityPath("Assets/Hoge");
|
||||
Assert.AreEqual(assetsChild, hoge);
|
||||
|
||||
//var children = root.TravserseDir().ToArray();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void VersionChecker()
|
||||
{
|
||||
Assert.False(ImporterContext.IsGeneratedUniGLTFAndOlderThan("hoge", 1, 16));
|
||||
Assert.False(ImporterContext.IsGeneratedUniGLTFAndOlderThan("UniGLTF-1.16", 1, 16));
|
||||
Assert.True(ImporterContext.IsGeneratedUniGLTFAndOlderThan("UniGLTF-1.15", 1, 16));
|
||||
Assert.False(ImporterContext.IsGeneratedUniGLTFAndOlderThan("UniGLTF-11.16", 1, 16));
|
||||
Assert.True(ImporterContext.IsGeneratedUniGLTFAndOlderThan("UniGLTF-0.16", 1, 16));
|
||||
Assert.True(ImporterContext.IsGeneratedUniGLTFAndOlderThan("UniGLTF", 1, 16));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MeshTest()
|
||||
{
|
||||
var mesh = new glTFMesh("mesh")
|
||||
{
|
||||
primitives = new List<glTFPrimitives>
|
||||
{
|
||||
new glTFPrimitives
|
||||
{
|
||||
attributes=new glTFAttributes
|
||||
{
|
||||
POSITION=0,
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var f = new JsonFormatter();
|
||||
f.Serialize(mesh);
|
||||
|
||||
var json = new Utf8String(f.GetStoreBytes()).ToString();
|
||||
Debug.Log(json);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PrimitiveTest()
|
||||
{
|
||||
var prims = new List<glTFPrimitives> {
|
||||
new glTFPrimitives
|
||||
{
|
||||
attributes = new glTFAttributes
|
||||
{
|
||||
POSITION = 0,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var f = new JsonFormatter();
|
||||
f.Serialize(prims);
|
||||
|
||||
var json = new Utf8String(f.GetStoreBytes()).ToString();
|
||||
Debug.Log(json);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,51 +1,51 @@
|
|||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public static class ImporterMenu
|
||||
{
|
||||
[MenuItem(UniGLTFVersion.UNIGLTF_VERSION + "/Import", priority = 1)]
|
||||
public static void ImportMenu()
|
||||
{
|
||||
var path = EditorUtility.OpenFilePanel("open gltf", "", "gltf,glb,zip");
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
//
|
||||
// load into scene
|
||||
//
|
||||
var context = new ImporterContext();
|
||||
context.Load(path);
|
||||
context.ShowMeshes();
|
||||
Selection.activeGameObject = context.Root;
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// save as asset
|
||||
//
|
||||
if (path.StartsWithUnityAssetPath())
|
||||
{
|
||||
Debug.LogWarningFormat("disallow import from folder under the Assets");
|
||||
return;
|
||||
}
|
||||
|
||||
var assetPath = EditorUtility.SaveFilePanel("save prefab", "Assets", Path.GetFileNameWithoutExtension(path), "prefab");
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// import as asset
|
||||
gltfAssetPostprocessor.ImportAsset(path, Path.GetExtension(path).ToLower(), UnityPath.FromFullpath(assetPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public static class ImporterMenu
|
||||
{
|
||||
[MenuItem(UniGLTFVersion.UNIGLTF_VERSION + "/Import", priority = 1)]
|
||||
public static void ImportMenu()
|
||||
{
|
||||
var path = EditorUtility.OpenFilePanel("open gltf", "", "gltf,glb,zip");
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
//
|
||||
// load into scene
|
||||
//
|
||||
var context = new ImporterContext();
|
||||
context.Load(path);
|
||||
context.ShowMeshes();
|
||||
Selection.activeGameObject = context.Root;
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// save as asset
|
||||
//
|
||||
if (path.StartsWithUnityAssetPath())
|
||||
{
|
||||
Debug.LogWarningFormat("disallow import from folder under the Assets");
|
||||
return;
|
||||
}
|
||||
|
||||
var assetPath = EditorUtility.SaveFilePanel("save prefab", "Assets", Path.GetFileNameWithoutExtension(path), "prefab");
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// import as asset
|
||||
gltfAssetPostprocessor.ImportAsset(path, Path.GetExtension(path).ToLower(), UnityPath.FromFullpath(assetPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,45 +1,45 @@
|
|||
#if UNIGLTF_DEVELOP
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public static class UniGLTFVersionMenu
|
||||
{
|
||||
public const int MENU_PRIORITY = 99;
|
||||
static string path = "Assets/UniGLTF/Core/Scripts/UniGLTFVersion.cs";
|
||||
|
||||
const string template = @"
|
||||
namespace UniGLTF
|
||||
{{
|
||||
public static partial class UniGLTFVersion
|
||||
{{
|
||||
public const int MAJOR = {0};
|
||||
public const int MINOR = {1};
|
||||
|
||||
public const string VERSION = ""{0}.{1}"";
|
||||
}}
|
||||
}}
|
||||
";
|
||||
|
||||
[MenuItem(UniGLTFVersion.UNIGLTF_VERSION + "/Increment", priority = MENU_PRIORITY)]
|
||||
public static void IncrementVersion()
|
||||
{
|
||||
var source = string.Format(template, UniGLTFVersion.MAJOR, UniGLTFVersion.MINOR + 1);
|
||||
File.WriteAllText(path, source);
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
|
||||
[MenuItem(UniGLTFVersion.UNIGLTF_VERSION + "/Decrement", priority = MENU_PRIORITY)]
|
||||
public static void DecrementVersion()
|
||||
{
|
||||
var source = string.Format(template, UniGLTFVersion.MAJOR, UniGLTFVersion.MINOR - 1);
|
||||
File.WriteAllText(path, source);
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if UNIGLTF_DEVELOP
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public static class UniGLTFVersionMenu
|
||||
{
|
||||
public const int MENU_PRIORITY = 99;
|
||||
static string path = "Assets/UniGLTF/Core/Scripts/UniGLTFVersion.cs";
|
||||
|
||||
const string template = @"
|
||||
namespace UniGLTF
|
||||
{{
|
||||
public static partial class UniGLTFVersion
|
||||
{{
|
||||
public const int MAJOR = {0};
|
||||
public const int MINOR = {1};
|
||||
|
||||
public const string VERSION = ""{0}.{1}"";
|
||||
}}
|
||||
}}
|
||||
";
|
||||
|
||||
[MenuItem(UniGLTFVersion.UNIGLTF_VERSION + "/Increment", priority = MENU_PRIORITY)]
|
||||
public static void IncrementVersion()
|
||||
{
|
||||
var source = string.Format(template, UniGLTFVersion.MAJOR, UniGLTFVersion.MINOR + 1);
|
||||
File.WriteAllText(path, source);
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
|
||||
[MenuItem(UniGLTFVersion.UNIGLTF_VERSION + "/Decrement", priority = MENU_PRIORITY)]
|
||||
public static void DecrementVersion()
|
||||
{
|
||||
var source = string.Format(template, UniGLTFVersion.MAJOR, UniGLTFVersion.MINOR - 1);
|
||||
File.WriteAllText(path, source);
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1,80 +1,80 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public class gltfAssetPostprocessor : AssetPostprocessor
|
||||
{
|
||||
static void OnPostprocessAllAssets(string[] importedAssets,
|
||||
string[] deletedAssets,
|
||||
string[] movedAssets,
|
||||
string[] movedFromAssetPaths)
|
||||
{
|
||||
foreach (string path in importedAssets)
|
||||
{
|
||||
var ext = Path.GetExtension(path).ToLower();
|
||||
switch (ext)
|
||||
{
|
||||
case ".gltf":
|
||||
case ".glb":
|
||||
{
|
||||
var gltfPath = UnityPath.FromUnityPath(path);
|
||||
var prefabPath = gltfPath.Parent.Child(gltfPath.FileNameWithoutExtension + ".prefab");
|
||||
ImportAsset(UnityPath.FromUnityPath(path).FullPath, ext, prefabPath);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void ImportAsset(string src, string ext, UnityPath prefabPath)
|
||||
{
|
||||
if (!prefabPath.IsUnderAssetsFolder)
|
||||
{
|
||||
Debug.LogWarningFormat("out of asset path: {0}", prefabPath);
|
||||
return;
|
||||
}
|
||||
|
||||
var context = new ImporterContext();
|
||||
context.Parse(src);
|
||||
|
||||
// Extract textures to assets folder
|
||||
context.ExtranctImages(prefabPath);
|
||||
|
||||
ImportDelayed(src, prefabPath, context);
|
||||
}
|
||||
|
||||
static void ImportDelayed(string src, UnityPath prefabPath, ImporterContext context)
|
||||
{
|
||||
EditorApplication.delayCall += () =>
|
||||
{
|
||||
//
|
||||
// After textures imported(To ensure TextureImporter be accessible).
|
||||
//
|
||||
try
|
||||
{
|
||||
context.Load();
|
||||
context.SaveAsAsset(prefabPath);
|
||||
context.EditorDestroyRoot();
|
||||
}
|
||||
catch (UniGLTFNotSupportedException ex)
|
||||
{
|
||||
Debug.LogWarningFormat("{0}: {1}",
|
||||
src,
|
||||
ex.Message
|
||||
);
|
||||
context.EditorDestroyRootAndAssets();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogErrorFormat("import error: {0}", src);
|
||||
Debug.LogErrorFormat("{0}", ex);
|
||||
context.EditorDestroyRootAndAssets();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public class gltfAssetPostprocessor : AssetPostprocessor
|
||||
{
|
||||
static void OnPostprocessAllAssets(string[] importedAssets,
|
||||
string[] deletedAssets,
|
||||
string[] movedAssets,
|
||||
string[] movedFromAssetPaths)
|
||||
{
|
||||
foreach (string path in importedAssets)
|
||||
{
|
||||
var ext = Path.GetExtension(path).ToLower();
|
||||
switch (ext)
|
||||
{
|
||||
case ".gltf":
|
||||
case ".glb":
|
||||
{
|
||||
var gltfPath = UnityPath.FromUnityPath(path);
|
||||
var prefabPath = gltfPath.Parent.Child(gltfPath.FileNameWithoutExtension + ".prefab");
|
||||
ImportAsset(UnityPath.FromUnityPath(path).FullPath, ext, prefabPath);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void ImportAsset(string src, string ext, UnityPath prefabPath)
|
||||
{
|
||||
if (!prefabPath.IsUnderAssetsFolder)
|
||||
{
|
||||
Debug.LogWarningFormat("out of asset path: {0}", prefabPath);
|
||||
return;
|
||||
}
|
||||
|
||||
var context = new ImporterContext();
|
||||
context.Parse(src);
|
||||
|
||||
// Extract textures to assets folder
|
||||
context.ExtranctImages(prefabPath);
|
||||
|
||||
ImportDelayed(src, prefabPath, context);
|
||||
}
|
||||
|
||||
static void ImportDelayed(string src, UnityPath prefabPath, ImporterContext context)
|
||||
{
|
||||
EditorApplication.delayCall += () =>
|
||||
{
|
||||
//
|
||||
// After textures imported(To ensure TextureImporter be accessible).
|
||||
//
|
||||
try
|
||||
{
|
||||
context.Load();
|
||||
context.SaveAsAsset(prefabPath);
|
||||
context.EditorDestroyRoot();
|
||||
}
|
||||
catch (UniGLTFNotSupportedException ex)
|
||||
{
|
||||
Debug.LogWarningFormat("{0}: {1}",
|
||||
src,
|
||||
ex.Message
|
||||
);
|
||||
context.EditorDestroyRootAndAssets();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogErrorFormat("import error: {0}", src);
|
||||
Debug.LogErrorFormat("{0}", ex);
|
||||
context.EditorDestroyRootAndAssets();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,127 +1,127 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public static class Pin
|
||||
{
|
||||
public static Pin<T> Create<T>(ArraySegment<T> src) where T : struct
|
||||
{
|
||||
return new Pin<T>(src);
|
||||
}
|
||||
public static Pin<T> Create<T>(T[] src) where T : struct
|
||||
{
|
||||
return Create(new ArraySegment<T>(src));
|
||||
}
|
||||
}
|
||||
public class Pin<T> : IDisposable
|
||||
where T : struct
|
||||
{
|
||||
GCHandle m_pinnedArray;
|
||||
|
||||
ArraySegment<T> m_src;
|
||||
|
||||
public int Length
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_src.Count * Marshal.SizeOf(typeof(T));
|
||||
}
|
||||
}
|
||||
|
||||
public Pin(ArraySegment<T> src)
|
||||
{
|
||||
m_src = src;
|
||||
m_pinnedArray = GCHandle.Alloc(src.Array, GCHandleType.Pinned);
|
||||
}
|
||||
|
||||
public IntPtr Ptr
|
||||
{
|
||||
get
|
||||
{
|
||||
var ptr = m_pinnedArray.AddrOfPinnedObject();
|
||||
return new IntPtr(ptr.ToInt64() + m_src.Offset);
|
||||
}
|
||||
}
|
||||
|
||||
#region IDisposable Support
|
||||
private bool disposedValue = false; // 重複する呼び出しを検出するには
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
// TODO: マネージ状態を破棄します (マネージ オブジェクト)。
|
||||
}
|
||||
|
||||
// TODO: アンマネージ リソース (アンマネージ オブジェクト) を解放し、下のファイナライザーをオーバーライドします。
|
||||
// TODO: 大きなフィールドを null に設定します。
|
||||
if (m_pinnedArray.IsAllocated)
|
||||
{
|
||||
m_pinnedArray.Free();
|
||||
}
|
||||
|
||||
disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: 上の Dispose(bool disposing) にアンマネージ リソースを解放するコードが含まれる場合にのみ、ファイナライザーをオーバーライドします。
|
||||
// ~Pin() {
|
||||
// // このコードを変更しないでください。クリーンアップ コードを上の Dispose(bool disposing) に記述します。
|
||||
// Dispose(false);
|
||||
// }
|
||||
|
||||
// このコードは、破棄可能なパターンを正しく実装できるように追加されました。
|
||||
public void Dispose()
|
||||
{
|
||||
// このコードを変更しないでください。クリーンアップ コードを上の Dispose(bool disposing) に記述します。
|
||||
Dispose(true);
|
||||
// TODO: 上のファイナライザーがオーバーライドされる場合は、次の行のコメントを解除してください。
|
||||
// GC.SuppressFinalize(this);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
public static class ArrayExtensions
|
||||
{
|
||||
public static int MarshalCoyTo<T>(this ArraySegment<byte> src, T[] dst) where T : struct
|
||||
{
|
||||
var size = dst.Length * Marshal.SizeOf(typeof(T));
|
||||
using (var pin = Pin.Create(dst))
|
||||
{
|
||||
Marshal.Copy(src.Array, src.Offset, pin.Ptr, size);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
public static Byte[] ToArray(this ArraySegment<byte> src)
|
||||
{
|
||||
var dst = new byte[src.Count];
|
||||
Array.Copy(src.Array, src.Offset, dst, 0, src.Count);
|
||||
return dst;
|
||||
}
|
||||
|
||||
public static T[] SelectInplace<T>(this T[] src, Func<T, T> pred)
|
||||
{
|
||||
for (int i = 0; i < src.Length; ++i)
|
||||
{
|
||||
src[i] = pred(src[i]);
|
||||
}
|
||||
return src;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ListExtensions
|
||||
{
|
||||
public static void Assign<T>(this List<T> dst, T[] src, Func<T, T> pred)
|
||||
{
|
||||
dst.Capacity = src.Length;
|
||||
dst.AddRange(src.Select(pred));
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public static class Pin
|
||||
{
|
||||
public static Pin<T> Create<T>(ArraySegment<T> src) where T : struct
|
||||
{
|
||||
return new Pin<T>(src);
|
||||
}
|
||||
public static Pin<T> Create<T>(T[] src) where T : struct
|
||||
{
|
||||
return Create(new ArraySegment<T>(src));
|
||||
}
|
||||
}
|
||||
public class Pin<T> : IDisposable
|
||||
where T : struct
|
||||
{
|
||||
GCHandle m_pinnedArray;
|
||||
|
||||
ArraySegment<T> m_src;
|
||||
|
||||
public int Length
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_src.Count * Marshal.SizeOf(typeof(T));
|
||||
}
|
||||
}
|
||||
|
||||
public Pin(ArraySegment<T> src)
|
||||
{
|
||||
m_src = src;
|
||||
m_pinnedArray = GCHandle.Alloc(src.Array, GCHandleType.Pinned);
|
||||
}
|
||||
|
||||
public IntPtr Ptr
|
||||
{
|
||||
get
|
||||
{
|
||||
var ptr = m_pinnedArray.AddrOfPinnedObject();
|
||||
return new IntPtr(ptr.ToInt64() + m_src.Offset);
|
||||
}
|
||||
}
|
||||
|
||||
#region IDisposable Support
|
||||
private bool disposedValue = false; // 重複する呼び出しを検出するには
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
// TODO: マネージ状態を破棄します (マネージ オブジェクト)。
|
||||
}
|
||||
|
||||
// TODO: アンマネージ リソース (アンマネージ オブジェクト) を解放し、下のファイナライザーをオーバーライドします。
|
||||
// TODO: 大きなフィールドを null に設定します。
|
||||
if (m_pinnedArray.IsAllocated)
|
||||
{
|
||||
m_pinnedArray.Free();
|
||||
}
|
||||
|
||||
disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: 上の Dispose(bool disposing) にアンマネージ リソースを解放するコードが含まれる場合にのみ、ファイナライザーをオーバーライドします。
|
||||
// ~Pin() {
|
||||
// // このコードを変更しないでください。クリーンアップ コードを上の Dispose(bool disposing) に記述します。
|
||||
// Dispose(false);
|
||||
// }
|
||||
|
||||
// このコードは、破棄可能なパターンを正しく実装できるように追加されました。
|
||||
public void Dispose()
|
||||
{
|
||||
// このコードを変更しないでください。クリーンアップ コードを上の Dispose(bool disposing) に記述します。
|
||||
Dispose(true);
|
||||
// TODO: 上のファイナライザーがオーバーライドされる場合は、次の行のコメントを解除してください。
|
||||
// GC.SuppressFinalize(this);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
public static class ArrayExtensions
|
||||
{
|
||||
public static int MarshalCoyTo<T>(this ArraySegment<byte> src, T[] dst) where T : struct
|
||||
{
|
||||
var size = dst.Length * Marshal.SizeOf(typeof(T));
|
||||
using (var pin = Pin.Create(dst))
|
||||
{
|
||||
Marshal.Copy(src.Array, src.Offset, pin.Ptr, size);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
public static Byte[] ToArray(this ArraySegment<byte> src)
|
||||
{
|
||||
var dst = new byte[src.Count];
|
||||
Array.Copy(src.Array, src.Offset, dst, 0, src.Count);
|
||||
return dst;
|
||||
}
|
||||
|
||||
public static T[] SelectInplace<T>(this T[] src, Func<T, T> pred)
|
||||
{
|
||||
for (int i = 0; i < src.Length; ++i)
|
||||
{
|
||||
src[i] = pred(src[i]);
|
||||
}
|
||||
return src;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ListExtensions
|
||||
{
|
||||
public static void Assign<T>(this List<T> dst, T[] src, Func<T, T> pred)
|
||||
{
|
||||
dst.Capacity = src.Length;
|
||||
dst.AddRange(src.Select(pred));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,19 +1,19 @@
|
|||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
||||
namespace UniJSON
|
||||
{
|
||||
public static class JsonParserExtensions
|
||||
{
|
||||
public static List<T> DeserializeList<T>(this ListTreeNode<JsonValue> jsonList)
|
||||
{
|
||||
return jsonList.ArrayItems().Select(x => {
|
||||
|
||||
return JsonUtility.FromJson<T>(new Utf8String(x.Value.Bytes).ToString());
|
||||
|
||||
}).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
||||
namespace UniJSON
|
||||
{
|
||||
public static class JsonParserExtensions
|
||||
{
|
||||
public static List<T> DeserializeList<T>(this ListTreeNode<JsonValue> jsonList)
|
||||
{
|
||||
return jsonList.ArrayItems().Select(x => {
|
||||
|
||||
return JsonUtility.FromJson<T>(new Utf8String(x.Value.Bytes).ToString());
|
||||
|
||||
}).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,73 +1,73 @@
|
|||
using System.IO;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public static class StringExtensions
|
||||
{
|
||||
public static string ToLowerCamelCase(this string lower)
|
||||
{
|
||||
return lower.Substring(0, 1).ToLower() + lower.Substring(1);
|
||||
}
|
||||
public static string ToUpperCamelCase(this string lower)
|
||||
{
|
||||
return lower.Substring(0, 1).ToUpper() + lower.Substring(1);
|
||||
}
|
||||
|
||||
static string m_unityBasePath;
|
||||
public static string UnityBasePath
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_unityBasePath == null)
|
||||
{
|
||||
m_unityBasePath = Path.GetFullPath(Application.dataPath + "/..").Replace("\\", "/");
|
||||
}
|
||||
return m_unityBasePath;
|
||||
}
|
||||
}
|
||||
|
||||
public static string AssetPathToFullPath(this string path)
|
||||
{
|
||||
return UnityBasePath + "/" + path;
|
||||
}
|
||||
|
||||
public static bool StartsWithUnityAssetPath(this string path)
|
||||
{
|
||||
return path.Replace("\\", "/").StartsWith(UnityBasePath + "/Assets");
|
||||
}
|
||||
|
||||
public static string ToUnityRelativePath(this string path)
|
||||
{
|
||||
path = path.Replace("\\", "/");
|
||||
if (path.StartsWith(UnityBasePath))
|
||||
{
|
||||
return path.Substring(UnityBasePath.Length + 1);
|
||||
}
|
||||
|
||||
//Debug.LogWarningFormat("{0} is starts with {1}", path, basePath);
|
||||
return path;
|
||||
}
|
||||
|
||||
static readonly char[] EscapeChars = new char[]
|
||||
{
|
||||
'\\',
|
||||
'/',
|
||||
':',
|
||||
'*',
|
||||
'?',
|
||||
'"',
|
||||
'<',
|
||||
'>',
|
||||
'|',
|
||||
};
|
||||
public static string EscapeFilePath(this string path)
|
||||
{
|
||||
foreach(var x in EscapeChars)
|
||||
{
|
||||
path = path.Replace(x, '+');
|
||||
}
|
||||
return path;
|
||||
}
|
||||
}
|
||||
}
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public static class StringExtensions
|
||||
{
|
||||
public static string ToLowerCamelCase(this string lower)
|
||||
{
|
||||
return lower.Substring(0, 1).ToLower() + lower.Substring(1);
|
||||
}
|
||||
public static string ToUpperCamelCase(this string lower)
|
||||
{
|
||||
return lower.Substring(0, 1).ToUpper() + lower.Substring(1);
|
||||
}
|
||||
|
||||
static string m_unityBasePath;
|
||||
public static string UnityBasePath
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_unityBasePath == null)
|
||||
{
|
||||
m_unityBasePath = Path.GetFullPath(Application.dataPath + "/..").Replace("\\", "/");
|
||||
}
|
||||
return m_unityBasePath;
|
||||
}
|
||||
}
|
||||
|
||||
public static string AssetPathToFullPath(this string path)
|
||||
{
|
||||
return UnityBasePath + "/" + path;
|
||||
}
|
||||
|
||||
public static bool StartsWithUnityAssetPath(this string path)
|
||||
{
|
||||
return path.Replace("\\", "/").StartsWith(UnityBasePath + "/Assets");
|
||||
}
|
||||
|
||||
public static string ToUnityRelativePath(this string path)
|
||||
{
|
||||
path = path.Replace("\\", "/");
|
||||
if (path.StartsWith(UnityBasePath))
|
||||
{
|
||||
return path.Substring(UnityBasePath.Length + 1);
|
||||
}
|
||||
|
||||
//Debug.LogWarningFormat("{0} is starts with {1}", path, basePath);
|
||||
return path;
|
||||
}
|
||||
|
||||
static readonly char[] EscapeChars = new char[]
|
||||
{
|
||||
'\\',
|
||||
'/',
|
||||
':',
|
||||
'*',
|
||||
'?',
|
||||
'"',
|
||||
'<',
|
||||
'>',
|
||||
'|',
|
||||
};
|
||||
public static string EscapeFilePath(this string path)
|
||||
{
|
||||
foreach(var x in EscapeChars)
|
||||
{
|
||||
path = path.Replace(x, '+');
|
||||
}
|
||||
return path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,313 +1,313 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public struct PosRot
|
||||
{
|
||||
public Vector3 Position;
|
||||
public Quaternion Rotation;
|
||||
|
||||
public static PosRot FromGlobalTransform(Transform t)
|
||||
{
|
||||
return new PosRot
|
||||
{
|
||||
Position = t.position,
|
||||
Rotation = t.rotation,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public class BlendShape
|
||||
{
|
||||
public string Name;
|
||||
|
||||
public BlendShape(string name)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public List<Vector3> Positions = new List<Vector3>();
|
||||
public List<Vector3> Normals = new List<Vector3>();
|
||||
public List<Vector3> Tangents = new List<Vector3>();
|
||||
}
|
||||
|
||||
public static class UnityExtensions
|
||||
{
|
||||
public static Vector4 ReverseZ(this Vector4 v)
|
||||
{
|
||||
return new Vector4(v.x, v.y, -v.z, v.w);
|
||||
}
|
||||
|
||||
public static Vector3 ReverseZ(this Vector3 v)
|
||||
{
|
||||
return new Vector3(v.x, v.y, -v.z);
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
public static Vector2 ReverseY(this Vector2 v)
|
||||
{
|
||||
return new Vector2(v.x, -v.y);
|
||||
}
|
||||
|
||||
public static Vector2 ReverseUV(this Vector2 v)
|
||||
{
|
||||
return new Vector2(v.x, 1.0f - v.y);
|
||||
}
|
||||
|
||||
public static Quaternion ReverseZ(this Quaternion q)
|
||||
{
|
||||
float angle;
|
||||
Vector3 axis;
|
||||
q.ToAngleAxis(out angle, out axis);
|
||||
return Quaternion.AngleAxis(-angle, ReverseZ(axis));
|
||||
}
|
||||
|
||||
public static Matrix4x4 Matrix4x4FromColumns(Vector4 c0, Vector4 c1, Vector4 c2, Vector4 c3)
|
||||
{
|
||||
#if UNITY_2017_1_OR_NEWER
|
||||
return new Matrix4x4(c0, c1, c2, c3);
|
||||
#else
|
||||
var m = default(Matrix4x4);
|
||||
m.SetColumn(0, c0);
|
||||
m.SetColumn(1, c1);
|
||||
m.SetColumn(2, c2);
|
||||
m.SetColumn(3, c3);
|
||||
return m;
|
||||
#endif
|
||||
}
|
||||
|
||||
public static Matrix4x4 Matrix4x4FromRotation(Quaternion q)
|
||||
{
|
||||
#if UNITY_2017_1_OR_NEWER
|
||||
return Matrix4x4.Rotate(q);
|
||||
#else
|
||||
var m = default(Matrix4x4);
|
||||
m.SetTRS(Vector3.zero, q, Vector3.one);
|
||||
return m;
|
||||
#endif
|
||||
}
|
||||
|
||||
public static Matrix4x4 ReverseZ(this Matrix4x4 m)
|
||||
{
|
||||
m.SetTRS(m.ExtractPosition().ReverseZ(), m.ExtractRotation().ReverseZ(), m.ExtractScale());
|
||||
return m;
|
||||
}
|
||||
|
||||
public static Matrix4x4 MatrixFromArray(float[] values)
|
||||
{
|
||||
var m = new Matrix4x4();
|
||||
m.m00 = values[0];
|
||||
m.m10 = values[1];
|
||||
m.m20 = values[2];
|
||||
m.m30 = values[3];
|
||||
m.m01 = values[4];
|
||||
m.m11 = values[5];
|
||||
m.m21 = values[6];
|
||||
m.m31 = values[7];
|
||||
m.m02 = values[8];
|
||||
m.m12 = values[9];
|
||||
m.m22 = values[10];
|
||||
m.m32 = values[11];
|
||||
m.m03 = values[12];
|
||||
m.m13 = values[13];
|
||||
m.m23 = values[14];
|
||||
m.m33 = values[15];
|
||||
return m;
|
||||
}
|
||||
|
||||
// https://forum.unity.com/threads/how-to-assign-matrix4x4-to-transform.121966/
|
||||
public static Quaternion ExtractRotation(this Matrix4x4 matrix)
|
||||
{
|
||||
Vector3 forward;
|
||||
forward.x = matrix.m02;
|
||||
forward.y = matrix.m12;
|
||||
forward.z = matrix.m22;
|
||||
|
||||
Vector3 upwards;
|
||||
upwards.x = matrix.m01;
|
||||
upwards.y = matrix.m11;
|
||||
upwards.z = matrix.m21;
|
||||
|
||||
return Quaternion.LookRotation(forward, upwards);
|
||||
}
|
||||
|
||||
public static Vector3 ExtractPosition(this Matrix4x4 matrix)
|
||||
{
|
||||
Vector3 position;
|
||||
position.x = matrix.m03;
|
||||
position.y = matrix.m13;
|
||||
position.z = matrix.m23;
|
||||
return position;
|
||||
}
|
||||
|
||||
public static Vector3 ExtractScale(this Matrix4x4 matrix)
|
||||
{
|
||||
Vector3 scale;
|
||||
scale.x = new Vector4(matrix.m00, matrix.m10, matrix.m20, matrix.m30).magnitude;
|
||||
scale.y = new Vector4(matrix.m01, matrix.m11, matrix.m21, matrix.m31).magnitude;
|
||||
scale.z = new Vector4(matrix.m02, matrix.m12, matrix.m22, matrix.m32).magnitude;
|
||||
return scale;
|
||||
}
|
||||
|
||||
public static string RelativePathFrom(this Transform self, Transform root)
|
||||
{
|
||||
var path = new List<String>();
|
||||
for (var current = self; current != null; current = current.parent)
|
||||
{
|
||||
if (current == root)
|
||||
{
|
||||
return String.Join("/", path.ToArray());
|
||||
}
|
||||
|
||||
path.Insert(0, current.name);
|
||||
}
|
||||
|
||||
throw new Exception("no RelativePath");
|
||||
}
|
||||
|
||||
public static Transform GetChildByName(this Transform self, string childName)
|
||||
{
|
||||
foreach (Transform child in self)
|
||||
{
|
||||
if (child.name == childName)
|
||||
{
|
||||
return child;
|
||||
}
|
||||
}
|
||||
|
||||
throw new KeyNotFoundException();
|
||||
}
|
||||
|
||||
public static Transform GetFromPath(this Transform self, string path)
|
||||
{
|
||||
var current = self;
|
||||
|
||||
var splited = path.Split('/');
|
||||
|
||||
foreach (var childName in splited)
|
||||
{
|
||||
current = current.GetChildByName(childName);
|
||||
}
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
public static IEnumerable<Transform> GetChildren(this Transform self)
|
||||
{
|
||||
foreach (Transform child in self)
|
||||
{
|
||||
yield return child;
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<Transform> Traverse(this Transform t)
|
||||
{
|
||||
yield return t;
|
||||
foreach (Transform x in t)
|
||||
{
|
||||
foreach (Transform y in x.Traverse())
|
||||
{
|
||||
yield return y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Transform FindDescenedant(this Transform t, string name)
|
||||
{
|
||||
return t.Traverse().First(x => x.name == name);
|
||||
}
|
||||
|
||||
public static IEnumerable<Transform> Ancestors(this Transform t)
|
||||
{
|
||||
yield return t;
|
||||
if (t.parent != null)
|
||||
{
|
||||
foreach (Transform x in t.parent.Ancestors())
|
||||
{
|
||||
yield return x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static float[] ToArray(this Quaternion q)
|
||||
{
|
||||
return new float[] { q.x, q.y, q.z, q.w };
|
||||
}
|
||||
|
||||
public static float[] ToArray(this Vector3 v)
|
||||
{
|
||||
return new float[] { v.x, v.y, v.z };
|
||||
}
|
||||
|
||||
public static float[] ToArray(this Vector4 v)
|
||||
{
|
||||
return new float[] { v.x, v.y, v.z, v.w };
|
||||
}
|
||||
|
||||
public static float[] ToArray(this Color c)
|
||||
{
|
||||
return new float[] { c.r, c.g, c.b, c.a };
|
||||
}
|
||||
|
||||
public static void ReverseZRecursive(this Transform root)
|
||||
{
|
||||
var globalMap = root.Traverse().ToDictionary(x => x, x => PosRot.FromGlobalTransform(x));
|
||||
|
||||
foreach (var x in root.Traverse())
|
||||
{
|
||||
x.position = globalMap[x].Position.ReverseZ();
|
||||
x.rotation = globalMap[x].Rotation.ReverseZ();
|
||||
}
|
||||
}
|
||||
|
||||
public static Mesh GetSharedMesh(this Transform t)
|
||||
{
|
||||
var meshFilter = t.GetComponent<MeshFilter>();
|
||||
if (meshFilter != null)
|
||||
{
|
||||
return meshFilter.sharedMesh;
|
||||
}
|
||||
|
||||
var skinnedMeshRenderer = t.GetComponent<SkinnedMeshRenderer>();
|
||||
if (skinnedMeshRenderer != null)
|
||||
{
|
||||
return skinnedMeshRenderer.sharedMesh;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Material[] GetSharedMaterials(this Transform t)
|
||||
{
|
||||
var renderer = t.GetComponent<Renderer>();
|
||||
if (renderer != null)
|
||||
{
|
||||
return renderer.sharedMaterials;
|
||||
}
|
||||
|
||||
return new Material[] { };
|
||||
}
|
||||
|
||||
public static bool Has<T>(this Transform transform, T t) where T : Component
|
||||
{
|
||||
return transform.GetComponent<T>() == t;
|
||||
}
|
||||
|
||||
public static T GetOrAddComponent<T>(this GameObject go) where T : Component
|
||||
{
|
||||
var c = go.GetComponent<T>();
|
||||
if (c != null)
|
||||
{
|
||||
return c;
|
||||
}
|
||||
return go.AddComponent<T>();
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public struct PosRot
|
||||
{
|
||||
public Vector3 Position;
|
||||
public Quaternion Rotation;
|
||||
|
||||
public static PosRot FromGlobalTransform(Transform t)
|
||||
{
|
||||
return new PosRot
|
||||
{
|
||||
Position = t.position,
|
||||
Rotation = t.rotation,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public class BlendShape
|
||||
{
|
||||
public string Name;
|
||||
|
||||
public BlendShape(string name)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public List<Vector3> Positions = new List<Vector3>();
|
||||
public List<Vector3> Normals = new List<Vector3>();
|
||||
public List<Vector3> Tangents = new List<Vector3>();
|
||||
}
|
||||
|
||||
public static class UnityExtensions
|
||||
{
|
||||
public static Vector4 ReverseZ(this Vector4 v)
|
||||
{
|
||||
return new Vector4(v.x, v.y, -v.z, v.w);
|
||||
}
|
||||
|
||||
public static Vector3 ReverseZ(this Vector3 v)
|
||||
{
|
||||
return new Vector3(v.x, v.y, -v.z);
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
public static Vector2 ReverseY(this Vector2 v)
|
||||
{
|
||||
return new Vector2(v.x, -v.y);
|
||||
}
|
||||
|
||||
public static Vector2 ReverseUV(this Vector2 v)
|
||||
{
|
||||
return new Vector2(v.x, 1.0f - v.y);
|
||||
}
|
||||
|
||||
public static Quaternion ReverseZ(this Quaternion q)
|
||||
{
|
||||
float angle;
|
||||
Vector3 axis;
|
||||
q.ToAngleAxis(out angle, out axis);
|
||||
return Quaternion.AngleAxis(-angle, ReverseZ(axis));
|
||||
}
|
||||
|
||||
public static Matrix4x4 Matrix4x4FromColumns(Vector4 c0, Vector4 c1, Vector4 c2, Vector4 c3)
|
||||
{
|
||||
#if UNITY_2017_1_OR_NEWER
|
||||
return new Matrix4x4(c0, c1, c2, c3);
|
||||
#else
|
||||
var m = default(Matrix4x4);
|
||||
m.SetColumn(0, c0);
|
||||
m.SetColumn(1, c1);
|
||||
m.SetColumn(2, c2);
|
||||
m.SetColumn(3, c3);
|
||||
return m;
|
||||
#endif
|
||||
}
|
||||
|
||||
public static Matrix4x4 Matrix4x4FromRotation(Quaternion q)
|
||||
{
|
||||
#if UNITY_2017_1_OR_NEWER
|
||||
return Matrix4x4.Rotate(q);
|
||||
#else
|
||||
var m = default(Matrix4x4);
|
||||
m.SetTRS(Vector3.zero, q, Vector3.one);
|
||||
return m;
|
||||
#endif
|
||||
}
|
||||
|
||||
public static Matrix4x4 ReverseZ(this Matrix4x4 m)
|
||||
{
|
||||
m.SetTRS(m.ExtractPosition().ReverseZ(), m.ExtractRotation().ReverseZ(), m.ExtractScale());
|
||||
return m;
|
||||
}
|
||||
|
||||
public static Matrix4x4 MatrixFromArray(float[] values)
|
||||
{
|
||||
var m = new Matrix4x4();
|
||||
m.m00 = values[0];
|
||||
m.m10 = values[1];
|
||||
m.m20 = values[2];
|
||||
m.m30 = values[3];
|
||||
m.m01 = values[4];
|
||||
m.m11 = values[5];
|
||||
m.m21 = values[6];
|
||||
m.m31 = values[7];
|
||||
m.m02 = values[8];
|
||||
m.m12 = values[9];
|
||||
m.m22 = values[10];
|
||||
m.m32 = values[11];
|
||||
m.m03 = values[12];
|
||||
m.m13 = values[13];
|
||||
m.m23 = values[14];
|
||||
m.m33 = values[15];
|
||||
return m;
|
||||
}
|
||||
|
||||
// https://forum.unity.com/threads/how-to-assign-matrix4x4-to-transform.121966/
|
||||
public static Quaternion ExtractRotation(this Matrix4x4 matrix)
|
||||
{
|
||||
Vector3 forward;
|
||||
forward.x = matrix.m02;
|
||||
forward.y = matrix.m12;
|
||||
forward.z = matrix.m22;
|
||||
|
||||
Vector3 upwards;
|
||||
upwards.x = matrix.m01;
|
||||
upwards.y = matrix.m11;
|
||||
upwards.z = matrix.m21;
|
||||
|
||||
return Quaternion.LookRotation(forward, upwards);
|
||||
}
|
||||
|
||||
public static Vector3 ExtractPosition(this Matrix4x4 matrix)
|
||||
{
|
||||
Vector3 position;
|
||||
position.x = matrix.m03;
|
||||
position.y = matrix.m13;
|
||||
position.z = matrix.m23;
|
||||
return position;
|
||||
}
|
||||
|
||||
public static Vector3 ExtractScale(this Matrix4x4 matrix)
|
||||
{
|
||||
Vector3 scale;
|
||||
scale.x = new Vector4(matrix.m00, matrix.m10, matrix.m20, matrix.m30).magnitude;
|
||||
scale.y = new Vector4(matrix.m01, matrix.m11, matrix.m21, matrix.m31).magnitude;
|
||||
scale.z = new Vector4(matrix.m02, matrix.m12, matrix.m22, matrix.m32).magnitude;
|
||||
return scale;
|
||||
}
|
||||
|
||||
public static string RelativePathFrom(this Transform self, Transform root)
|
||||
{
|
||||
var path = new List<String>();
|
||||
for (var current = self; current != null; current = current.parent)
|
||||
{
|
||||
if (current == root)
|
||||
{
|
||||
return String.Join("/", path.ToArray());
|
||||
}
|
||||
|
||||
path.Insert(0, current.name);
|
||||
}
|
||||
|
||||
throw new Exception("no RelativePath");
|
||||
}
|
||||
|
||||
public static Transform GetChildByName(this Transform self, string childName)
|
||||
{
|
||||
foreach (Transform child in self)
|
||||
{
|
||||
if (child.name == childName)
|
||||
{
|
||||
return child;
|
||||
}
|
||||
}
|
||||
|
||||
throw new KeyNotFoundException();
|
||||
}
|
||||
|
||||
public static Transform GetFromPath(this Transform self, string path)
|
||||
{
|
||||
var current = self;
|
||||
|
||||
var splited = path.Split('/');
|
||||
|
||||
foreach (var childName in splited)
|
||||
{
|
||||
current = current.GetChildByName(childName);
|
||||
}
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
public static IEnumerable<Transform> GetChildren(this Transform self)
|
||||
{
|
||||
foreach (Transform child in self)
|
||||
{
|
||||
yield return child;
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<Transform> Traverse(this Transform t)
|
||||
{
|
||||
yield return t;
|
||||
foreach (Transform x in t)
|
||||
{
|
||||
foreach (Transform y in x.Traverse())
|
||||
{
|
||||
yield return y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Transform FindDescenedant(this Transform t, string name)
|
||||
{
|
||||
return t.Traverse().First(x => x.name == name);
|
||||
}
|
||||
|
||||
public static IEnumerable<Transform> Ancestors(this Transform t)
|
||||
{
|
||||
yield return t;
|
||||
if (t.parent != null)
|
||||
{
|
||||
foreach (Transform x in t.parent.Ancestors())
|
||||
{
|
||||
yield return x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static float[] ToArray(this Quaternion q)
|
||||
{
|
||||
return new float[] { q.x, q.y, q.z, q.w };
|
||||
}
|
||||
|
||||
public static float[] ToArray(this Vector3 v)
|
||||
{
|
||||
return new float[] { v.x, v.y, v.z };
|
||||
}
|
||||
|
||||
public static float[] ToArray(this Vector4 v)
|
||||
{
|
||||
return new float[] { v.x, v.y, v.z, v.w };
|
||||
}
|
||||
|
||||
public static float[] ToArray(this Color c)
|
||||
{
|
||||
return new float[] { c.r, c.g, c.b, c.a };
|
||||
}
|
||||
|
||||
public static void ReverseZRecursive(this Transform root)
|
||||
{
|
||||
var globalMap = root.Traverse().ToDictionary(x => x, x => PosRot.FromGlobalTransform(x));
|
||||
|
||||
foreach (var x in root.Traverse())
|
||||
{
|
||||
x.position = globalMap[x].Position.ReverseZ();
|
||||
x.rotation = globalMap[x].Rotation.ReverseZ();
|
||||
}
|
||||
}
|
||||
|
||||
public static Mesh GetSharedMesh(this Transform t)
|
||||
{
|
||||
var meshFilter = t.GetComponent<MeshFilter>();
|
||||
if (meshFilter != null)
|
||||
{
|
||||
return meshFilter.sharedMesh;
|
||||
}
|
||||
|
||||
var skinnedMeshRenderer = t.GetComponent<SkinnedMeshRenderer>();
|
||||
if (skinnedMeshRenderer != null)
|
||||
{
|
||||
return skinnedMeshRenderer.sharedMesh;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Material[] GetSharedMaterials(this Transform t)
|
||||
{
|
||||
var renderer = t.GetComponent<Renderer>();
|
||||
if (renderer != null)
|
||||
{
|
||||
return renderer.sharedMaterials;
|
||||
}
|
||||
|
||||
return new Material[] { };
|
||||
}
|
||||
|
||||
public static bool Has<T>(this Transform transform, T t) where T : Component
|
||||
{
|
||||
return transform.GetComponent<T>() == t;
|
||||
}
|
||||
|
||||
public static T GetOrAddComponent<T>(this GameObject go) where T : Component
|
||||
{
|
||||
var c = go.GetComponent<T>();
|
||||
if (c != null)
|
||||
{
|
||||
return c;
|
||||
}
|
||||
return go.AddComponent<T>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,203 +1,203 @@
|
|||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,187 +1,187 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
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
|
||||
{
|
||||
return buffer.Extend(new ArraySegment<T>(array), target);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// for buffer with uri read
|
||||
/// </summary>
|
||||
public class UriByteBuffer : IBytesBuffer
|
||||
{
|
||||
public string Uri
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
Byte[] m_bytes;
|
||||
public ArraySegment<byte> GetBytes()
|
||||
{
|
||||
return new ArraySegment<byte>(m_bytes);
|
||||
}
|
||||
|
||||
public UriByteBuffer(string baseDir, string uri)
|
||||
{
|
||||
Uri = uri;
|
||||
m_bytes = ReadFromUri(baseDir, uri);
|
||||
}
|
||||
|
||||
const string DataPrefix = "data:application/octet-stream;base64,";
|
||||
|
||||
const string DataPrefix2 = "data:application/gltf-buffer;base64,";
|
||||
|
||||
const string DataPrefix3 = "data:image/jpeg;base64,";
|
||||
|
||||
public static Byte[] ReadEmbeded(string uri)
|
||||
{
|
||||
var pos = uri.IndexOf(";base64,");
|
||||
if (pos < 0)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
else
|
||||
{
|
||||
return Convert.FromBase64String(uri.Substring(pos + 8));
|
||||
}
|
||||
}
|
||||
|
||||
Byte[] ReadFromUri(string baseDir, string uri)
|
||||
{
|
||||
var bytes = ReadEmbeded(uri);
|
||||
if (bytes != null)
|
||||
{
|
||||
return bytes;
|
||||
}
|
||||
else
|
||||
{
|
||||
// as local file path
|
||||
return File.ReadAllBytes(Path.Combine(baseDir, uri));
|
||||
}
|
||||
}
|
||||
|
||||
public glTFBufferView Extend<T>(ArraySegment<T> array, glBufferTarget target) where T : struct
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <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
|
||||
/// </summary>
|
||||
public class ArrayByteBuffer : IBytesBuffer
|
||||
{
|
||||
public string Uri
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
Byte[] m_bytes;
|
||||
int m_used;
|
||||
|
||||
public ArrayByteBuffer(Byte[] bytes = null)
|
||||
{
|
||||
Uri = "";
|
||||
m_bytes = bytes;
|
||||
}
|
||||
|
||||
public glTFBufferView Extend<T>(ArraySegment<T> array, glBufferTarget target) where T : struct
|
||||
{
|
||||
using (var pin = Pin.Create(array))
|
||||
{
|
||||
var elementSize = Marshal.SizeOf(typeof(T));
|
||||
var view = Extend(pin.Ptr, array.Count * elementSize, elementSize, target);
|
||||
return view;
|
||||
}
|
||||
}
|
||||
|
||||
public glTFBufferView Extend(IntPtr p, int bytesLength, int stride, glBufferTarget target)
|
||||
{
|
||||
var tmp = m_bytes;
|
||||
// alignment
|
||||
var padding = m_used % stride == 0 ? 0 : stride - m_used % stride;
|
||||
|
||||
if (m_bytes == null || m_used + padding + bytesLength > m_bytes.Length)
|
||||
{
|
||||
// recreate buffer
|
||||
m_bytes = new Byte[m_used + padding + bytesLength];
|
||||
if (m_used > 0)
|
||||
{
|
||||
Buffer.BlockCopy(tmp, 0, m_bytes, 0, m_used);
|
||||
}
|
||||
}
|
||||
if (m_used + padding + bytesLength > m_bytes.Length)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
Marshal.Copy(p, m_bytes, m_used + padding, bytesLength);
|
||||
var result=new glTFBufferView
|
||||
{
|
||||
buffer = 0,
|
||||
byteLength = bytesLength,
|
||||
byteOffset = m_used + padding,
|
||||
byteStride = stride,
|
||||
target = target,
|
||||
};
|
||||
m_used = m_used + padding + bytesLength;
|
||||
return result;
|
||||
}
|
||||
|
||||
public ArraySegment<byte> GetBytes()
|
||||
{
|
||||
if (m_bytes == null)
|
||||
{
|
||||
return new ArraySegment<byte>();
|
||||
}
|
||||
|
||||
return new ArraySegment<byte>(m_bytes, 0, m_used);
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.IO;
|
||||
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
|
||||
{
|
||||
return buffer.Extend(new ArraySegment<T>(array), target);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// for buffer with uri read
|
||||
/// </summary>
|
||||
public class UriByteBuffer : IBytesBuffer
|
||||
{
|
||||
public string Uri
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
Byte[] m_bytes;
|
||||
public ArraySegment<byte> GetBytes()
|
||||
{
|
||||
return new ArraySegment<byte>(m_bytes);
|
||||
}
|
||||
|
||||
public UriByteBuffer(string baseDir, string uri)
|
||||
{
|
||||
Uri = uri;
|
||||
m_bytes = ReadFromUri(baseDir, uri);
|
||||
}
|
||||
|
||||
const string DataPrefix = "data:application/octet-stream;base64,";
|
||||
|
||||
const string DataPrefix2 = "data:application/gltf-buffer;base64,";
|
||||
|
||||
const string DataPrefix3 = "data:image/jpeg;base64,";
|
||||
|
||||
public static Byte[] ReadEmbeded(string uri)
|
||||
{
|
||||
var pos = uri.IndexOf(";base64,");
|
||||
if (pos < 0)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
else
|
||||
{
|
||||
return Convert.FromBase64String(uri.Substring(pos + 8));
|
||||
}
|
||||
}
|
||||
|
||||
Byte[] ReadFromUri(string baseDir, string uri)
|
||||
{
|
||||
var bytes = ReadEmbeded(uri);
|
||||
if (bytes != null)
|
||||
{
|
||||
return bytes;
|
||||
}
|
||||
else
|
||||
{
|
||||
// as local file path
|
||||
return File.ReadAllBytes(Path.Combine(baseDir, uri));
|
||||
}
|
||||
}
|
||||
|
||||
public glTFBufferView Extend<T>(ArraySegment<T> array, glBufferTarget target) where T : struct
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <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
|
||||
/// </summary>
|
||||
public class ArrayByteBuffer : IBytesBuffer
|
||||
{
|
||||
public string Uri
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
Byte[] m_bytes;
|
||||
int m_used;
|
||||
|
||||
public ArrayByteBuffer(Byte[] bytes = null)
|
||||
{
|
||||
Uri = "";
|
||||
m_bytes = bytes;
|
||||
}
|
||||
|
||||
public glTFBufferView Extend<T>(ArraySegment<T> array, glBufferTarget target) where T : struct
|
||||
{
|
||||
using (var pin = Pin.Create(array))
|
||||
{
|
||||
var elementSize = Marshal.SizeOf(typeof(T));
|
||||
var view = Extend(pin.Ptr, array.Count * elementSize, elementSize, target);
|
||||
return view;
|
||||
}
|
||||
}
|
||||
|
||||
public glTFBufferView Extend(IntPtr p, int bytesLength, int stride, glBufferTarget target)
|
||||
{
|
||||
var tmp = m_bytes;
|
||||
// alignment
|
||||
var padding = m_used % stride == 0 ? 0 : stride - m_used % stride;
|
||||
|
||||
if (m_bytes == null || m_used + padding + bytesLength > m_bytes.Length)
|
||||
{
|
||||
// recreate buffer
|
||||
m_bytes = new Byte[m_used + padding + bytesLength];
|
||||
if (m_used > 0)
|
||||
{
|
||||
Buffer.BlockCopy(tmp, 0, m_bytes, 0, m_used);
|
||||
}
|
||||
}
|
||||
if (m_used + padding + bytesLength > m_bytes.Length)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
Marshal.Copy(p, m_bytes, m_used + padding, bytesLength);
|
||||
var result=new glTFBufferView
|
||||
{
|
||||
buffer = 0,
|
||||
byteLength = bytesLength,
|
||||
byteOffset = m_used + padding,
|
||||
byteStride = stride,
|
||||
target = target,
|
||||
};
|
||||
m_used = m_used + padding + bytesLength;
|
||||
return result;
|
||||
}
|
||||
|
||||
public ArraySegment<byte> GetBytes()
|
||||
{
|
||||
if (m_bytes == null)
|
||||
{
|
||||
return new ArraySegment<byte>();
|
||||
}
|
||||
|
||||
return new ArraySegment<byte>(m_bytes, 0, m_used);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,32 +1,32 @@
|
|||
using System;
|
||||
using UniJSON;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
[Serializable]
|
||||
public class glTF_KHR_draco_mesh_compression : JsonSerializableBase
|
||||
{
|
||||
[JsonSchema(Required = true, Minimum = 0)]
|
||||
public int bufferView = -1;
|
||||
public glTFAttributes attributes;
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
//throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public partial class glTFPrimitives_extensions : ExtensionsBase<glTFPrimitives_extensions>
|
||||
{
|
||||
[JsonSchema(Required = true)]
|
||||
public glTF_KHR_draco_mesh_compression KHR_draco_mesh_compression;
|
||||
|
||||
[JsonSerializeMembers]
|
||||
void SerializeMembers_draco(GLTFJsonFormatter f)
|
||||
{
|
||||
//throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using UniJSON;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
[Serializable]
|
||||
public class glTF_KHR_draco_mesh_compression : JsonSerializableBase
|
||||
{
|
||||
[JsonSchema(Required = true, Minimum = 0)]
|
||||
public int bufferView = -1;
|
||||
public glTFAttributes attributes;
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
//throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public partial class glTFPrimitives_extensions : ExtensionsBase<glTFPrimitives_extensions>
|
||||
{
|
||||
[JsonSchema(Required = true)]
|
||||
public glTF_KHR_draco_mesh_compression KHR_draco_mesh_compression;
|
||||
|
||||
[JsonSerializeMembers]
|
||||
void SerializeMembers_draco(GLTFJsonFormatter f)
|
||||
{
|
||||
//throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,55 +1,55 @@
|
|||
using System;
|
||||
using UniJSON;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
[Serializable]
|
||||
public class glTF_KHR_materials_unlit : JsonSerializableBase
|
||||
{
|
||||
public static string ExtensionName
|
||||
{
|
||||
get
|
||||
{
|
||||
return "KHR_materials_unlit";
|
||||
}
|
||||
}
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
//throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public static glTFMaterial CreateDefault()
|
||||
{
|
||||
return new glTFMaterial
|
||||
{
|
||||
pbrMetallicRoughness = new glTFPbrMetallicRoughness
|
||||
{
|
||||
baseColorFactor = new float[] { 1.0f, 1.0f, 1.0f, 1.0f },
|
||||
roughnessFactor = 0.9f,
|
||||
metallicFactor = 0.0f,
|
||||
},
|
||||
extensions = new glTFMaterial_extensions
|
||||
{
|
||||
KHR_materials_unlit = new glTF_KHR_materials_unlit(),
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public partial class glTFMaterial_extensions : ExtensionsBase<glTFMaterial_extensions>
|
||||
{
|
||||
[JsonSchema(Required = true)]
|
||||
public glTF_KHR_materials_unlit KHR_materials_unlit;
|
||||
|
||||
[JsonSerializeMembers]
|
||||
void SerializeMembers_unlit(GLTFJsonFormatter f)
|
||||
{
|
||||
if (KHR_materials_unlit != null)
|
||||
{
|
||||
f.KeyValue(() => KHR_materials_unlit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using UniJSON;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
[Serializable]
|
||||
public class glTF_KHR_materials_unlit : JsonSerializableBase
|
||||
{
|
||||
public static string ExtensionName
|
||||
{
|
||||
get
|
||||
{
|
||||
return "KHR_materials_unlit";
|
||||
}
|
||||
}
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
//throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public static glTFMaterial CreateDefault()
|
||||
{
|
||||
return new glTFMaterial
|
||||
{
|
||||
pbrMetallicRoughness = new glTFPbrMetallicRoughness
|
||||
{
|
||||
baseColorFactor = new float[] { 1.0f, 1.0f, 1.0f, 1.0f },
|
||||
roughnessFactor = 0.9f,
|
||||
metallicFactor = 0.0f,
|
||||
},
|
||||
extensions = new glTFMaterial_extensions
|
||||
{
|
||||
KHR_materials_unlit = new glTF_KHR_materials_unlit(),
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public partial class glTFMaterial_extensions : ExtensionsBase<glTFMaterial_extensions>
|
||||
{
|
||||
[JsonSchema(Required = true)]
|
||||
public glTF_KHR_materials_unlit KHR_materials_unlit;
|
||||
|
||||
[JsonSerializeMembers]
|
||||
void SerializeMembers_unlit(GLTFJsonFormatter f)
|
||||
{
|
||||
if (KHR_materials_unlit != null)
|
||||
{
|
||||
f.KeyValue(() => KHR_materials_unlit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,27 +1,27 @@
|
|||
using System;
|
||||
using UniJSON;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
[Serializable]
|
||||
[ItemJsonSchema(ValueType = ValueNodeType.Object)]
|
||||
public partial class glTFOrthographic_extensions : ExtensionsBase<glTFOrthographic_extensions> { }
|
||||
|
||||
[Serializable]
|
||||
public partial class glTFOrthographic_extras : ExtraBase<glTFOrthographic_extras> { }
|
||||
|
||||
[Serializable]
|
||||
[ItemJsonSchema(ValueType = ValueNodeType.Object)]
|
||||
public partial class glTFPerspective_extensions : ExtensionsBase<glTFPerspective_extensions> { }
|
||||
|
||||
[Serializable]
|
||||
public partial class glTFPerspective_extras : ExtraBase<glTFPerspective_extras> { }
|
||||
|
||||
[Serializable]
|
||||
[ItemJsonSchema(ValueType = ValueNodeType.Object)]
|
||||
public partial class glTFCamera_extensions : ExtensionsBase<glTFCamera_extensions> { }
|
||||
|
||||
[Serializable]
|
||||
public partial class glTFCamera_extras : ExtraBase<glTFCamera_extras> { }
|
||||
}
|
||||
using System;
|
||||
using UniJSON;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
[Serializable]
|
||||
[ItemJsonSchema(ValueType = ValueNodeType.Object)]
|
||||
public partial class glTFOrthographic_extensions : ExtensionsBase<glTFOrthographic_extensions> { }
|
||||
|
||||
[Serializable]
|
||||
public partial class glTFOrthographic_extras : ExtraBase<glTFOrthographic_extras> { }
|
||||
|
||||
[Serializable]
|
||||
[ItemJsonSchema(ValueType = ValueNodeType.Object)]
|
||||
public partial class glTFPerspective_extensions : ExtensionsBase<glTFPerspective_extensions> { }
|
||||
|
||||
[Serializable]
|
||||
public partial class glTFPerspective_extras : ExtraBase<glTFPerspective_extras> { }
|
||||
|
||||
[Serializable]
|
||||
[ItemJsonSchema(ValueType = ValueNodeType.Object)]
|
||||
public partial class glTFCamera_extensions : ExtensionsBase<glTFCamera_extensions> { }
|
||||
|
||||
[Serializable]
|
||||
public partial class glTFCamera_extras : ExtraBase<glTFCamera_extras> { }
|
||||
}
|
||||
|
|
@ -1,54 +1,54 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UniJSON;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
#region Base
|
||||
public class JsonSerializeMembersAttribute : Attribute { }
|
||||
|
||||
public class PartialExtensionBase<T> : JsonSerializableBase
|
||||
{
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
foreach (var method in this.GetType().GetMethods(BindingFlags.Instance |
|
||||
BindingFlags.Public | BindingFlags.NonPublic))
|
||||
{
|
||||
if (method.GetCustomAttributes(typeof(JsonSerializeMembersAttribute), true).Any())
|
||||
{
|
||||
method.Invoke(this, new[] { f });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int __count
|
||||
{
|
||||
get
|
||||
{
|
||||
return typeof(T).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
|
||||
.Where(x => x.GetCustomAttributes(typeof(JsonSerializeMembersAttribute), true).Any())
|
||||
.Count();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[ItemJsonSchema(ValueType = ValueNodeType.Object)]
|
||||
[JsonSchema(MinProperties = 1)]
|
||||
public partial class ExtensionsBase<T> : PartialExtensionBase<T>
|
||||
{
|
||||
}
|
||||
|
||||
[JsonSchema(MinProperties = 1)]
|
||||
public partial class ExtraBase<T> : PartialExtensionBase<T>
|
||||
{
|
||||
}
|
||||
#endregion
|
||||
|
||||
[Serializable]
|
||||
public partial class glTF_extensions : ExtensionsBase<glTF_extensions> { }
|
||||
|
||||
[Serializable]
|
||||
public partial class gltf_extras : ExtraBase<gltf_extras> { }
|
||||
}
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UniJSON;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
#region Base
|
||||
public class JsonSerializeMembersAttribute : Attribute { }
|
||||
|
||||
public class PartialExtensionBase<T> : JsonSerializableBase
|
||||
{
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
foreach (var method in this.GetType().GetMethods(BindingFlags.Instance |
|
||||
BindingFlags.Public | BindingFlags.NonPublic))
|
||||
{
|
||||
if (method.GetCustomAttributes(typeof(JsonSerializeMembersAttribute), true).Any())
|
||||
{
|
||||
method.Invoke(this, new[] { f });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int __count
|
||||
{
|
||||
get
|
||||
{
|
||||
return typeof(T).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
|
||||
.Where(x => x.GetCustomAttributes(typeof(JsonSerializeMembersAttribute), true).Any())
|
||||
.Count();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[ItemJsonSchema(ValueType = ValueNodeType.Object)]
|
||||
[JsonSchema(MinProperties = 1)]
|
||||
public partial class ExtensionsBase<T> : PartialExtensionBase<T>
|
||||
{
|
||||
}
|
||||
|
||||
[JsonSchema(MinProperties = 1)]
|
||||
public partial class ExtraBase<T> : PartialExtensionBase<T>
|
||||
{
|
||||
}
|
||||
#endregion
|
||||
|
||||
[Serializable]
|
||||
public partial class glTF_extensions : ExtensionsBase<glTF_extensions> { }
|
||||
|
||||
[Serializable]
|
||||
public partial class gltf_extras : ExtraBase<gltf_extras> { }
|
||||
}
|
||||
|
|
@ -1,32 +1,32 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UniJSON;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
/// <summary>
|
||||
/// https://github.com/KhronosGroup/glTF/issues/1036
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public partial class glTFPrimitives_extras : ExtraBase<glTFPrimitives_extras>
|
||||
{
|
||||
[JsonSchema(Required = true, MinItems = 1)]
|
||||
public List<string> targetNames = new List<string>();
|
||||
|
||||
[JsonSerializeMembers]
|
||||
void PrimitiveMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
if (targetNames.Count > 0)
|
||||
{
|
||||
f.Key("targetNames");
|
||||
f.BeginList();
|
||||
foreach (var x in targetNames)
|
||||
{
|
||||
f.Value(x);
|
||||
}
|
||||
f.EndList();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UniJSON;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
/// <summary>
|
||||
/// https://github.com/KhronosGroup/glTF/issues/1036
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public partial class glTFPrimitives_extras : ExtraBase<glTFPrimitives_extras>
|
||||
{
|
||||
[JsonSchema(Required = true, MinItems = 1)]
|
||||
public List<string> targetNames = new List<string>();
|
||||
|
||||
[JsonSerializeMembers]
|
||||
void PrimitiveMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
if (targetNames.Count > 0)
|
||||
{
|
||||
f.Key("targetNames");
|
||||
f.BeginList();
|
||||
foreach (var x in targetNames)
|
||||
{
|
||||
f.Value(x);
|
||||
}
|
||||
f.EndList();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
using System;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
[Serializable]
|
||||
public partial class glTFNode_extensions : ExtensionsBase<glTFNode_extensions> { }
|
||||
|
||||
[Serializable]
|
||||
public partial class glTFNode_extra : ExtraBase<glTFNode_extra> { }
|
||||
}
|
||||
using System;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
[Serializable]
|
||||
public partial class glTFNode_extensions : ExtensionsBase<glTFNode_extensions> { }
|
||||
|
||||
[Serializable]
|
||||
public partial class glTFNode_extra : ExtraBase<glTFNode_extra> { }
|
||||
}
|
||||
|
|
@ -1,35 +1,35 @@
|
|||
using System.Collections.Generic;
|
||||
using UniJSON;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public class GLTFJsonFormatter: UniJSON.JsonFormatter
|
||||
{
|
||||
public void GLTFValue(JsonSerializableBase s)
|
||||
{
|
||||
CommaCheck();
|
||||
Store.Write(s.ToJson());
|
||||
}
|
||||
|
||||
public void GLTFValue<T>(IEnumerable<T> values) where T : JsonSerializableBase
|
||||
{
|
||||
BeginList();
|
||||
foreach (var value in values)
|
||||
{
|
||||
GLTFValue(value);
|
||||
}
|
||||
EndList();
|
||||
}
|
||||
|
||||
public void GLTFValue(List<string> values)
|
||||
{
|
||||
BeginList();
|
||||
foreach (var value in values)
|
||||
{
|
||||
this.Value(value);
|
||||
}
|
||||
EndList();
|
||||
}
|
||||
}
|
||||
}
|
||||
using System.Collections.Generic;
|
||||
using UniJSON;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public class GLTFJsonFormatter: UniJSON.JsonFormatter
|
||||
{
|
||||
public void GLTFValue(JsonSerializableBase s)
|
||||
{
|
||||
CommaCheck();
|
||||
Store.Write(s.ToJson());
|
||||
}
|
||||
|
||||
public void GLTFValue<T>(IEnumerable<T> values) where T : JsonSerializableBase
|
||||
{
|
||||
BeginList();
|
||||
foreach (var value in values)
|
||||
{
|
||||
GLTFValue(value);
|
||||
}
|
||||
EndList();
|
||||
}
|
||||
|
||||
public void GLTFValue(List<string> values)
|
||||
{
|
||||
BeginList();
|
||||
foreach (var value in values)
|
||||
{
|
||||
this.Value(value);
|
||||
}
|
||||
EndList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,22 +1,22 @@
|
|||
using System;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
[Serializable]
|
||||
public abstract class JsonSerializableBase
|
||||
{
|
||||
protected abstract void SerializeMembers(GLTFJsonFormatter f);
|
||||
|
||||
public string ToJson()
|
||||
{
|
||||
var f = new GLTFJsonFormatter();
|
||||
f.BeginMap();
|
||||
|
||||
SerializeMembers(f);
|
||||
|
||||
f.EndMap();
|
||||
return f.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
[Serializable]
|
||||
public abstract class JsonSerializableBase
|
||||
{
|
||||
protected abstract void SerializeMembers(GLTFJsonFormatter f);
|
||||
|
||||
public string ToJson()
|
||||
{
|
||||
var f = new GLTFJsonFormatter();
|
||||
f.BeginMap();
|
||||
|
||||
SerializeMembers(f);
|
||||
|
||||
f.EndMap();
|
||||
return f.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,68 +1,68 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public static class MonoBehaviourComparator
|
||||
{
|
||||
public static bool AssertAreEquals(GameObject l, GameObject r)
|
||||
{
|
||||
return
|
||||
l.name == r.name
|
||||
&& AssertAreEquals<Transform>(l, r,
|
||||
(x, y) => AssertAreEquals(x[0], y[0]))
|
||||
&& AssertAreEquals<MeshFilter>(l, r,
|
||||
(x, y) => AssertAreEquals(x[0], y[0]))
|
||||
&& AssertAreEquals<MeshRenderer>(l, r,
|
||||
(x, y) => AssertAreEquals(x[0], y[0]))
|
||||
&& AssertAreEquals<SkinnedMeshRenderer>(l, r,
|
||||
(x, y) => AssertAreEquals(x[0], y[0]))
|
||||
;
|
||||
}
|
||||
|
||||
public static bool AssertAreEquals<T>(GameObject l, GameObject r, Func<T[], T[], bool> pred) where T : Component
|
||||
{
|
||||
var ll = l.GetComponents<T>();
|
||||
var rr = r.GetComponents<T>();
|
||||
if (ll.Length != rr.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (ll.Length == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return pred(ll, rr);
|
||||
}
|
||||
|
||||
public static bool AssertAreEquals(Transform l, Transform r)
|
||||
{
|
||||
return
|
||||
(l.localPosition == r.localPosition)
|
||||
&& (l.localRotation == r.localRotation)
|
||||
&& (l.localScale == r.localScale)
|
||||
;
|
||||
}
|
||||
|
||||
public static bool AssertAreEquals(MeshFilter l, MeshFilter r)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public static bool AssertAreEquals(MeshRenderer l, MeshRenderer r)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public static bool AssertAreEquals(SkinnedMeshRenderer l, SkinnedMeshRenderer r)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public static bool AssetAreEquals(Texture2D l, Texture2D r)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public static class MonoBehaviourComparator
|
||||
{
|
||||
public static bool AssertAreEquals(GameObject l, GameObject r)
|
||||
{
|
||||
return
|
||||
l.name == r.name
|
||||
&& AssertAreEquals<Transform>(l, r,
|
||||
(x, y) => AssertAreEquals(x[0], y[0]))
|
||||
&& AssertAreEquals<MeshFilter>(l, r,
|
||||
(x, y) => AssertAreEquals(x[0], y[0]))
|
||||
&& AssertAreEquals<MeshRenderer>(l, r,
|
||||
(x, y) => AssertAreEquals(x[0], y[0]))
|
||||
&& AssertAreEquals<SkinnedMeshRenderer>(l, r,
|
||||
(x, y) => AssertAreEquals(x[0], y[0]))
|
||||
;
|
||||
}
|
||||
|
||||
public static bool AssertAreEquals<T>(GameObject l, GameObject r, Func<T[], T[], bool> pred) where T : Component
|
||||
{
|
||||
var ll = l.GetComponents<T>();
|
||||
var rr = r.GetComponents<T>();
|
||||
if (ll.Length != rr.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (ll.Length == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return pred(ll, rr);
|
||||
}
|
||||
|
||||
public static bool AssertAreEquals(Transform l, Transform r)
|
||||
{
|
||||
return
|
||||
(l.localPosition == r.localPosition)
|
||||
&& (l.localRotation == r.localRotation)
|
||||
&& (l.localScale == r.localScale)
|
||||
;
|
||||
}
|
||||
|
||||
public static bool AssertAreEquals(MeshFilter l, MeshFilter r)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public static bool AssertAreEquals(MeshRenderer l, MeshRenderer r)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public static bool AssertAreEquals(SkinnedMeshRenderer l, SkinnedMeshRenderer r)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public static bool AssetAreEquals(Texture2D l, Texture2D r)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,48 +1,48 @@
|
|||
/// <summary>
|
||||
/// https://gist.github.com/szimek/763999
|
||||
/// </summary>
|
||||
namespace UniGLTF
|
||||
{
|
||||
public enum glComponentType : int
|
||||
{
|
||||
BYTE = 5120, // signed ?
|
||||
UNSIGNED_BYTE = 5121,
|
||||
|
||||
SHORT = 5122,
|
||||
UNSIGNED_SHORT = 5123,
|
||||
|
||||
//INT = 5124,
|
||||
UNSIGNED_INT = 5125,
|
||||
|
||||
FLOAT = 5126,
|
||||
}
|
||||
|
||||
public enum glBufferTarget : int
|
||||
{
|
||||
NONE = 0,
|
||||
ARRAY_BUFFER = 34962,
|
||||
ELEMENT_ARRAY_BUFFER = 34963,
|
||||
}
|
||||
|
||||
public enum glFilter : int
|
||||
{
|
||||
NONE = 0,
|
||||
NEAREST = 9728,
|
||||
LINEAR = 9729,
|
||||
|
||||
#region for minFilter only
|
||||
NEAREST_MIPMAP_NEAREST = 9984,
|
||||
LINEAR_MIPMAP_NEAREST = 9985,
|
||||
NEAREST_MIPMAP_LINEAR = 9986,
|
||||
LINEAR_MIPMAP_LINEAR = 9987,
|
||||
#endregion
|
||||
}
|
||||
|
||||
public enum glWrap : int
|
||||
{
|
||||
NONE = 0,
|
||||
CLAMP_TO_EDGE = 33071,
|
||||
REPEAT = 10497,
|
||||
MIRRORED_REPEAT = 33648,
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// https://gist.github.com/szimek/763999
|
||||
/// </summary>
|
||||
namespace UniGLTF
|
||||
{
|
||||
public enum glComponentType : int
|
||||
{
|
||||
BYTE = 5120, // signed ?
|
||||
UNSIGNED_BYTE = 5121,
|
||||
|
||||
SHORT = 5122,
|
||||
UNSIGNED_SHORT = 5123,
|
||||
|
||||
//INT = 5124,
|
||||
UNSIGNED_INT = 5125,
|
||||
|
||||
FLOAT = 5126,
|
||||
}
|
||||
|
||||
public enum glBufferTarget : int
|
||||
{
|
||||
NONE = 0,
|
||||
ARRAY_BUFFER = 34962,
|
||||
ELEMENT_ARRAY_BUFFER = 34963,
|
||||
}
|
||||
|
||||
public enum glFilter : int
|
||||
{
|
||||
NONE = 0,
|
||||
NEAREST = 9728,
|
||||
LINEAR = 9729,
|
||||
|
||||
#region for minFilter only
|
||||
NEAREST_MIPMAP_NEAREST = 9984,
|
||||
LINEAR_MIPMAP_NEAREST = 9985,
|
||||
NEAREST_MIPMAP_LINEAR = 9986,
|
||||
LINEAR_MIPMAP_LINEAR = 9987,
|
||||
#endregion
|
||||
}
|
||||
|
||||
public enum glWrap : int
|
||||
{
|
||||
NONE = 0,
|
||||
CLAMP_TO_EDGE = 33071,
|
||||
REPEAT = 10497,
|
||||
MIRRORED_REPEAT = 33648,
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,210 +1,210 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using UniJSON;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
[Serializable]
|
||||
public class glTFAnimationTarget : JsonSerializableBase
|
||||
{
|
||||
[JsonSchema(Minimum = 0)]
|
||||
public int node;
|
||||
|
||||
[JsonSchema(Required = true, EnumValues = new object[] { "translation", "rotation", "scale", "weights" }, EnumSerializationType = EnumSerializationType.AsString)]
|
||||
public string path;
|
||||
|
||||
// empty schemas
|
||||
public object extensions;
|
||||
public object extras;
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
f.KeyValue(() => node);
|
||||
if (!string.IsNullOrEmpty(path))
|
||||
{
|
||||
f.KeyValue(() => path);
|
||||
}
|
||||
}
|
||||
|
||||
public enum Interpolations
|
||||
{
|
||||
LINEAR,
|
||||
STEP,
|
||||
CUBICSPLINE
|
||||
}
|
||||
|
||||
public const string PATH_TRANSLATION = "translation";
|
||||
public const string PATH_EULER_ROTATION = "rotation";
|
||||
public const string PATH_ROTATION = "rotation";
|
||||
public const string PATH_SCALE = "scale";
|
||||
public const string PATH_WEIGHT = "weights";
|
||||
public const string NOT_IMPLEMENTED = "NotImplemented";
|
||||
|
||||
public enum AnimationPropertys
|
||||
{
|
||||
Translation,
|
||||
EulerRotation,
|
||||
Rotation,
|
||||
Scale,
|
||||
Weight,
|
||||
BlendShape,
|
||||
|
||||
NotImplemented
|
||||
}
|
||||
|
||||
public static string GetPathName(AnimationPropertys property)
|
||||
{
|
||||
switch (property)
|
||||
{
|
||||
case AnimationPropertys.Translation:
|
||||
return PATH_TRANSLATION;
|
||||
case AnimationPropertys.EulerRotation:
|
||||
case AnimationPropertys.Rotation:
|
||||
return PATH_ROTATION;
|
||||
case AnimationPropertys.Scale:
|
||||
return PATH_SCALE;
|
||||
case AnimationPropertys.BlendShape:
|
||||
return PATH_WEIGHT;
|
||||
default: throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public static AnimationPropertys GetAnimationProperty(string path)
|
||||
{
|
||||
switch (path)
|
||||
{
|
||||
case PATH_TRANSLATION:
|
||||
return AnimationPropertys.Translation;
|
||||
case PATH_ROTATION:
|
||||
return AnimationPropertys.Rotation;
|
||||
case PATH_SCALE:
|
||||
return AnimationPropertys.Scale;
|
||||
case PATH_WEIGHT:
|
||||
return AnimationPropertys.BlendShape;
|
||||
default: throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetElementCount(AnimationPropertys property)
|
||||
{
|
||||
switch (property)
|
||||
{
|
||||
case AnimationPropertys.Translation: return 3;
|
||||
case AnimationPropertys.EulerRotation: return 3;
|
||||
case AnimationPropertys.Rotation: return 4;
|
||||
case AnimationPropertys.Scale: return 3;
|
||||
case AnimationPropertys.BlendShape: return 1;
|
||||
default: throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetElementCount(string path)
|
||||
{
|
||||
return GetElementCount(GetAnimationProperty(path));
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class glTFAnimationChannel : JsonSerializableBase
|
||||
{
|
||||
[JsonSchema(Required = true, Minimum = 0)]
|
||||
public int sampler = -1;
|
||||
|
||||
[JsonSchema(Required = true)]
|
||||
public glTFAnimationTarget target;
|
||||
|
||||
// empty schemas
|
||||
public object extensions;
|
||||
public object extras;
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
f.KeyValue(() => sampler);
|
||||
f.KeyValue(() => target);
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class glTFAnimationSampler : JsonSerializableBase
|
||||
{
|
||||
[JsonSchema(Required = true, Minimum = 0)]
|
||||
public int input = -1;
|
||||
|
||||
[JsonSchema(EnumValues = new object[] { "LINEAR", "STEP", "CUBICSPLINE" }, EnumSerializationType = EnumSerializationType.AsString)]
|
||||
public string interpolation;
|
||||
|
||||
[JsonSchema(Required = true, Minimum = 0)]
|
||||
public int output = -1;
|
||||
|
||||
// empty schemas
|
||||
public object extensions;
|
||||
public object extras;
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
f.KeyValue(() => input);
|
||||
if (!string.IsNullOrEmpty(interpolation))
|
||||
{
|
||||
f.KeyValue(() => interpolation);
|
||||
}
|
||||
f.KeyValue(() => output);
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class glTFAnimation : JsonSerializableBase
|
||||
{
|
||||
public string name = "";
|
||||
|
||||
[JsonSchema(Required = true, MinItems = 1)]
|
||||
public List<glTFAnimationChannel> channels = new List<glTFAnimationChannel>();
|
||||
|
||||
[JsonSchema(Required = true, MinItems = 1)]
|
||||
public List<glTFAnimationSampler> samplers = new List<glTFAnimationSampler>();
|
||||
|
||||
// empty schemas
|
||||
public object extensions;
|
||||
public object extras;
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(name))
|
||||
{
|
||||
f.KeyValue(() => name);
|
||||
}
|
||||
|
||||
f.KeyValue(() => channels);
|
||||
f.KeyValue(() => samplers);
|
||||
}
|
||||
|
||||
public int AddChannelAndGetSampler(int nodeIndex, glTFAnimationTarget.AnimationPropertys property)
|
||||
{
|
||||
// find channel
|
||||
var channel = channels.FirstOrDefault(x => x.target.node == nodeIndex && x.target.path == glTFAnimationTarget.GetPathName(property));
|
||||
if (channel != null)
|
||||
{
|
||||
return channel.sampler;
|
||||
}
|
||||
|
||||
// not found. create new
|
||||
var samplerIndex = samplers.Count;
|
||||
var sampler = new glTFAnimationSampler();
|
||||
samplers.Add(sampler);
|
||||
|
||||
channel = new glTFAnimationChannel
|
||||
{
|
||||
sampler = samplerIndex,
|
||||
target = new glTFAnimationTarget
|
||||
{
|
||||
node = nodeIndex,
|
||||
path = glTFAnimationTarget.GetPathName(property),
|
||||
},
|
||||
};
|
||||
channels.Add(channel);
|
||||
|
||||
return samplerIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using UniJSON;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
[Serializable]
|
||||
public class glTFAnimationTarget : JsonSerializableBase
|
||||
{
|
||||
[JsonSchema(Minimum = 0)]
|
||||
public int node;
|
||||
|
||||
[JsonSchema(Required = true, EnumValues = new object[] { "translation", "rotation", "scale", "weights" }, EnumSerializationType = EnumSerializationType.AsString)]
|
||||
public string path;
|
||||
|
||||
// empty schemas
|
||||
public object extensions;
|
||||
public object extras;
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
f.KeyValue(() => node);
|
||||
if (!string.IsNullOrEmpty(path))
|
||||
{
|
||||
f.KeyValue(() => path);
|
||||
}
|
||||
}
|
||||
|
||||
public enum Interpolations
|
||||
{
|
||||
LINEAR,
|
||||
STEP,
|
||||
CUBICSPLINE
|
||||
}
|
||||
|
||||
public const string PATH_TRANSLATION = "translation";
|
||||
public const string PATH_EULER_ROTATION = "rotation";
|
||||
public const string PATH_ROTATION = "rotation";
|
||||
public const string PATH_SCALE = "scale";
|
||||
public const string PATH_WEIGHT = "weights";
|
||||
public const string NOT_IMPLEMENTED = "NotImplemented";
|
||||
|
||||
public enum AnimationPropertys
|
||||
{
|
||||
Translation,
|
||||
EulerRotation,
|
||||
Rotation,
|
||||
Scale,
|
||||
Weight,
|
||||
BlendShape,
|
||||
|
||||
NotImplemented
|
||||
}
|
||||
|
||||
public static string GetPathName(AnimationPropertys property)
|
||||
{
|
||||
switch (property)
|
||||
{
|
||||
case AnimationPropertys.Translation:
|
||||
return PATH_TRANSLATION;
|
||||
case AnimationPropertys.EulerRotation:
|
||||
case AnimationPropertys.Rotation:
|
||||
return PATH_ROTATION;
|
||||
case AnimationPropertys.Scale:
|
||||
return PATH_SCALE;
|
||||
case AnimationPropertys.BlendShape:
|
||||
return PATH_WEIGHT;
|
||||
default: throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public static AnimationPropertys GetAnimationProperty(string path)
|
||||
{
|
||||
switch (path)
|
||||
{
|
||||
case PATH_TRANSLATION:
|
||||
return AnimationPropertys.Translation;
|
||||
case PATH_ROTATION:
|
||||
return AnimationPropertys.Rotation;
|
||||
case PATH_SCALE:
|
||||
return AnimationPropertys.Scale;
|
||||
case PATH_WEIGHT:
|
||||
return AnimationPropertys.BlendShape;
|
||||
default: throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetElementCount(AnimationPropertys property)
|
||||
{
|
||||
switch (property)
|
||||
{
|
||||
case AnimationPropertys.Translation: return 3;
|
||||
case AnimationPropertys.EulerRotation: return 3;
|
||||
case AnimationPropertys.Rotation: return 4;
|
||||
case AnimationPropertys.Scale: return 3;
|
||||
case AnimationPropertys.BlendShape: return 1;
|
||||
default: throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetElementCount(string path)
|
||||
{
|
||||
return GetElementCount(GetAnimationProperty(path));
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class glTFAnimationChannel : JsonSerializableBase
|
||||
{
|
||||
[JsonSchema(Required = true, Minimum = 0)]
|
||||
public int sampler = -1;
|
||||
|
||||
[JsonSchema(Required = true)]
|
||||
public glTFAnimationTarget target;
|
||||
|
||||
// empty schemas
|
||||
public object extensions;
|
||||
public object extras;
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
f.KeyValue(() => sampler);
|
||||
f.KeyValue(() => target);
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class glTFAnimationSampler : JsonSerializableBase
|
||||
{
|
||||
[JsonSchema(Required = true, Minimum = 0)]
|
||||
public int input = -1;
|
||||
|
||||
[JsonSchema(EnumValues = new object[] { "LINEAR", "STEP", "CUBICSPLINE" }, EnumSerializationType = EnumSerializationType.AsString)]
|
||||
public string interpolation;
|
||||
|
||||
[JsonSchema(Required = true, Minimum = 0)]
|
||||
public int output = -1;
|
||||
|
||||
// empty schemas
|
||||
public object extensions;
|
||||
public object extras;
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
f.KeyValue(() => input);
|
||||
if (!string.IsNullOrEmpty(interpolation))
|
||||
{
|
||||
f.KeyValue(() => interpolation);
|
||||
}
|
||||
f.KeyValue(() => output);
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class glTFAnimation : JsonSerializableBase
|
||||
{
|
||||
public string name = "";
|
||||
|
||||
[JsonSchema(Required = true, MinItems = 1)]
|
||||
public List<glTFAnimationChannel> channels = new List<glTFAnimationChannel>();
|
||||
|
||||
[JsonSchema(Required = true, MinItems = 1)]
|
||||
public List<glTFAnimationSampler> samplers = new List<glTFAnimationSampler>();
|
||||
|
||||
// empty schemas
|
||||
public object extensions;
|
||||
public object extras;
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(name))
|
||||
{
|
||||
f.KeyValue(() => name);
|
||||
}
|
||||
|
||||
f.KeyValue(() => channels);
|
||||
f.KeyValue(() => samplers);
|
||||
}
|
||||
|
||||
public int AddChannelAndGetSampler(int nodeIndex, glTFAnimationTarget.AnimationPropertys property)
|
||||
{
|
||||
// find channel
|
||||
var channel = channels.FirstOrDefault(x => x.target.node == nodeIndex && x.target.path == glTFAnimationTarget.GetPathName(property));
|
||||
if (channel != null)
|
||||
{
|
||||
return channel.sampler;
|
||||
}
|
||||
|
||||
// not found. create new
|
||||
var samplerIndex = samplers.Count;
|
||||
var sampler = new glTFAnimationSampler();
|
||||
samplers.Add(sampler);
|
||||
|
||||
channel = new glTFAnimationChannel
|
||||
{
|
||||
sampler = samplerIndex,
|
||||
target = new glTFAnimationTarget
|
||||
{
|
||||
node = nodeIndex,
|
||||
path = glTFAnimationTarget.GetPathName(property),
|
||||
},
|
||||
};
|
||||
channels.Add(channel);
|
||||
|
||||
return samplerIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,34 +1,34 @@
|
|||
using System;
|
||||
using UniJSON;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
[Serializable]
|
||||
public class glTFAssets : JsonSerializableBase
|
||||
{
|
||||
public string generator;
|
||||
|
||||
[JsonSchema(Required = true, Pattern = "^[0-9]+\\.[0-9]+$")]
|
||||
public string version;
|
||||
|
||||
public string copyright;
|
||||
|
||||
[JsonSchema(Pattern = "^[0-9]+\\.[0-9]+$")]
|
||||
public string minVersion;
|
||||
|
||||
// empty schemas
|
||||
public object extensions;
|
||||
public object extras;
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
f.Key("generator"); f.Value(generator);
|
||||
f.Key("version"); f.Value(version);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("GLTF-{0} generated by {1}", version, generator);
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using UniJSON;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
[Serializable]
|
||||
public class glTFAssets : JsonSerializableBase
|
||||
{
|
||||
public string generator;
|
||||
|
||||
[JsonSchema(Required = true, Pattern = "^[0-9]+\\.[0-9]+$")]
|
||||
public string version;
|
||||
|
||||
public string copyright;
|
||||
|
||||
[JsonSchema(Pattern = "^[0-9]+\\.[0-9]+$")]
|
||||
public string minVersion;
|
||||
|
||||
// empty schemas
|
||||
public object extensions;
|
||||
public object extras;
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
f.Key("generator"); f.Value(generator);
|
||||
f.Key("version"); f.Value(version);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("GLTF-{0} generated by {1}", version, generator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,261 +1,261 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using UniJSON;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
[Serializable]
|
||||
public class glTFBuffer : JsonSerializableBase
|
||||
{
|
||||
IBytesBuffer Storage;
|
||||
|
||||
public void OpenStorage(IStorage storage)
|
||||
{
|
||||
Storage = new ArraySegmentByteBuffer(storage.Get(uri));
|
||||
/*
|
||||
if (string.IsNullOrEmpty(uri))
|
||||
{
|
||||
Storage = (glbDataBytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
Storage = new UriByteBuffer(baseDir, uri);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
public glTFBuffer(IBytesBuffer storage)
|
||||
{
|
||||
Storage = storage;
|
||||
}
|
||||
|
||||
public string uri;
|
||||
|
||||
[JsonSchema(Required = true, Minimum = 1)]
|
||||
public int byteLength;
|
||||
|
||||
// empty schemas
|
||||
public object extensions;
|
||||
public object extras;
|
||||
public string name;
|
||||
|
||||
public glTFBufferView Append<T>(T[] array, glBufferTarget target) where T : struct
|
||||
{
|
||||
return Append(new ArraySegment<T>(array), target);
|
||||
}
|
||||
public glTFBufferView Append<T>(ArraySegment<T> segment, glBufferTarget target) where T : struct
|
||||
{
|
||||
var view = Storage.Extend(segment, target);
|
||||
byteLength = Storage.GetBytes().Count;
|
||||
return view;
|
||||
}
|
||||
|
||||
public ArraySegment<Byte> GetBytes()
|
||||
{
|
||||
return Storage.GetBytes();
|
||||
}
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(uri))
|
||||
{
|
||||
f.KeyValue(() => uri);
|
||||
}
|
||||
f.KeyValue(() => byteLength);
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class glTFBufferView : JsonSerializableBase
|
||||
{
|
||||
[JsonSchema(Required = true, Minimum = 0)]
|
||||
public int buffer;
|
||||
|
||||
[JsonSchema(Minimum = 0)]
|
||||
public int byteOffset;
|
||||
|
||||
[JsonSchema(Required = true, Minimum = 1)]
|
||||
public int byteLength;
|
||||
|
||||
[JsonSchema(Minimum = 4, Maximum = 252, MultipleOf = 4)]
|
||||
public int byteStride;
|
||||
|
||||
[JsonSchema(EnumSerializationType = EnumSerializationType.AsInt, EnumExcludes = new object[] { glBufferTarget.NONE })]
|
||||
public glBufferTarget target;
|
||||
|
||||
// empty schemas
|
||||
public object extensions;
|
||||
public object extras;
|
||||
public string name;
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
f.KeyValue(() => buffer);
|
||||
f.KeyValue(() => byteOffset);
|
||||
f.KeyValue(() => byteLength);
|
||||
if (target != glBufferTarget.NONE)
|
||||
{
|
||||
f.Key("target"); f.Value((int)target);
|
||||
}
|
||||
/* When this is not defined, data is tightly packed. When two or more accessors use the same bufferView, this field must be defined.
|
||||
if (byteStride >= 4)
|
||||
{
|
||||
f.KeyValue(() => byteStride);
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class glTFSparseIndices : JsonSerializableBase
|
||||
{
|
||||
[JsonSchema(Required = true, Minimum = 0)]
|
||||
public int bufferView = -1;
|
||||
|
||||
[JsonSchema(Minimum = 0)]
|
||||
public int byteOffset;
|
||||
|
||||
[JsonSchema(Required = true, EnumValues = new object[] { 5121, 5123, 5125 })]
|
||||
public glComponentType componentType;
|
||||
|
||||
// empty schemas
|
||||
public object extensions;
|
||||
public object extras;
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
f.KeyValue(() => bufferView);
|
||||
f.KeyValue(() => byteOffset);
|
||||
f.Key("componentType"); f.Value((int)componentType);
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class glTFSparseValues : JsonSerializableBase
|
||||
{
|
||||
[JsonSchema(Required = true, Minimum = 0)]
|
||||
public int bufferView = -1;
|
||||
|
||||
[JsonSchema(Minimum = 0)]
|
||||
public int byteOffset;
|
||||
|
||||
// empty schemas
|
||||
public object extensions;
|
||||
public object extras;
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
f.KeyValue(() => bufferView);
|
||||
f.KeyValue(() => byteOffset);
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class glTFSparse : JsonSerializableBase
|
||||
{
|
||||
[JsonSchema(Required = true, Minimum = 1)]
|
||||
public int count;
|
||||
|
||||
[JsonSchema(Required = true)]
|
||||
public glTFSparseIndices indices;
|
||||
|
||||
[JsonSchema(Required = true)]
|
||||
public glTFSparseValues values;
|
||||
|
||||
// empty schemas
|
||||
public object extensions;
|
||||
public object extras;
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
f.KeyValue(() => count);
|
||||
f.KeyValue(() => indices);
|
||||
f.KeyValue(() => values);
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class glTFAccessor : JsonSerializableBase
|
||||
{
|
||||
[JsonSchema(Minimum = 0)]
|
||||
public int bufferView = -1;
|
||||
|
||||
[JsonSchema(Minimum = 0, Dependencies = new string[] { "bufferView" })]
|
||||
public int byteOffset;
|
||||
|
||||
[JsonSchema(Required = true, EnumValues = new object[] { "SCALAR", "VEC2", "VEC3", "VEC4", "MAT2", "MAT3", "MAT4" }, EnumSerializationType = EnumSerializationType.AsString)]
|
||||
public string type;
|
||||
|
||||
public int TypeCount
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case "SCALAR":
|
||||
return 1;
|
||||
case "VEC2":
|
||||
return 2;
|
||||
case "VEC3":
|
||||
return 3;
|
||||
case "VEC4":
|
||||
case "MAT2":
|
||||
return 4;
|
||||
case "MAT3":
|
||||
return 9;
|
||||
case "MAT4":
|
||||
return 16;
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[JsonSchema(Required = true, EnumSerializationType = EnumSerializationType.AsInt)]
|
||||
public glComponentType componentType;
|
||||
|
||||
[JsonSchema(Required = true, Minimum = 1)]
|
||||
public int count;
|
||||
|
||||
[JsonSchema(MinItems = 1, MaxItems = 16)]
|
||||
public float[] max;
|
||||
|
||||
[JsonSchema(MinItems = 1, MaxItems = 16)]
|
||||
public float[] min;
|
||||
|
||||
public bool normalized;
|
||||
public glTFSparse sparse;
|
||||
|
||||
// empty schemas
|
||||
public string name;
|
||||
|
||||
public object extensions;
|
||||
|
||||
public object extras;
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
f.KeyValue(() => bufferView);
|
||||
f.KeyValue(() => byteOffset);
|
||||
f.KeyValue(() => type);
|
||||
f.Key("componentType"); f.Value((int)componentType);
|
||||
f.KeyValue(() => count);
|
||||
if (max != null && max.Any())
|
||||
{
|
||||
f.KeyValue(() => max);
|
||||
}
|
||||
if (min != null && min.Any())
|
||||
{
|
||||
f.KeyValue(() => min);
|
||||
}
|
||||
|
||||
if (sparse != null && sparse.count > 0)
|
||||
{
|
||||
f.KeyValue(() => sparse);
|
||||
}
|
||||
|
||||
f.KeyValue(() => normalized);
|
||||
f.KeyValue(() => name);
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Linq;
|
||||
using UniJSON;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
[Serializable]
|
||||
public class glTFBuffer : JsonSerializableBase
|
||||
{
|
||||
IBytesBuffer Storage;
|
||||
|
||||
public void OpenStorage(IStorage storage)
|
||||
{
|
||||
Storage = new ArraySegmentByteBuffer(storage.Get(uri));
|
||||
/*
|
||||
if (string.IsNullOrEmpty(uri))
|
||||
{
|
||||
Storage = (glbDataBytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
Storage = new UriByteBuffer(baseDir, uri);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
public glTFBuffer(IBytesBuffer storage)
|
||||
{
|
||||
Storage = storage;
|
||||
}
|
||||
|
||||
public string uri;
|
||||
|
||||
[JsonSchema(Required = true, Minimum = 1)]
|
||||
public int byteLength;
|
||||
|
||||
// empty schemas
|
||||
public object extensions;
|
||||
public object extras;
|
||||
public string name;
|
||||
|
||||
public glTFBufferView Append<T>(T[] array, glBufferTarget target) where T : struct
|
||||
{
|
||||
return Append(new ArraySegment<T>(array), target);
|
||||
}
|
||||
public glTFBufferView Append<T>(ArraySegment<T> segment, glBufferTarget target) where T : struct
|
||||
{
|
||||
var view = Storage.Extend(segment, target);
|
||||
byteLength = Storage.GetBytes().Count;
|
||||
return view;
|
||||
}
|
||||
|
||||
public ArraySegment<Byte> GetBytes()
|
||||
{
|
||||
return Storage.GetBytes();
|
||||
}
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(uri))
|
||||
{
|
||||
f.KeyValue(() => uri);
|
||||
}
|
||||
f.KeyValue(() => byteLength);
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class glTFBufferView : JsonSerializableBase
|
||||
{
|
||||
[JsonSchema(Required = true, Minimum = 0)]
|
||||
public int buffer;
|
||||
|
||||
[JsonSchema(Minimum = 0)]
|
||||
public int byteOffset;
|
||||
|
||||
[JsonSchema(Required = true, Minimum = 1)]
|
||||
public int byteLength;
|
||||
|
||||
[JsonSchema(Minimum = 4, Maximum = 252, MultipleOf = 4)]
|
||||
public int byteStride;
|
||||
|
||||
[JsonSchema(EnumSerializationType = EnumSerializationType.AsInt, EnumExcludes = new object[] { glBufferTarget.NONE })]
|
||||
public glBufferTarget target;
|
||||
|
||||
// empty schemas
|
||||
public object extensions;
|
||||
public object extras;
|
||||
public string name;
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
f.KeyValue(() => buffer);
|
||||
f.KeyValue(() => byteOffset);
|
||||
f.KeyValue(() => byteLength);
|
||||
if (target != glBufferTarget.NONE)
|
||||
{
|
||||
f.Key("target"); f.Value((int)target);
|
||||
}
|
||||
/* When this is not defined, data is tightly packed. When two or more accessors use the same bufferView, this field must be defined.
|
||||
if (byteStride >= 4)
|
||||
{
|
||||
f.KeyValue(() => byteStride);
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class glTFSparseIndices : JsonSerializableBase
|
||||
{
|
||||
[JsonSchema(Required = true, Minimum = 0)]
|
||||
public int bufferView = -1;
|
||||
|
||||
[JsonSchema(Minimum = 0)]
|
||||
public int byteOffset;
|
||||
|
||||
[JsonSchema(Required = true, EnumValues = new object[] { 5121, 5123, 5125 })]
|
||||
public glComponentType componentType;
|
||||
|
||||
// empty schemas
|
||||
public object extensions;
|
||||
public object extras;
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
f.KeyValue(() => bufferView);
|
||||
f.KeyValue(() => byteOffset);
|
||||
f.Key("componentType"); f.Value((int)componentType);
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class glTFSparseValues : JsonSerializableBase
|
||||
{
|
||||
[JsonSchema(Required = true, Minimum = 0)]
|
||||
public int bufferView = -1;
|
||||
|
||||
[JsonSchema(Minimum = 0)]
|
||||
public int byteOffset;
|
||||
|
||||
// empty schemas
|
||||
public object extensions;
|
||||
public object extras;
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
f.KeyValue(() => bufferView);
|
||||
f.KeyValue(() => byteOffset);
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class glTFSparse : JsonSerializableBase
|
||||
{
|
||||
[JsonSchema(Required = true, Minimum = 1)]
|
||||
public int count;
|
||||
|
||||
[JsonSchema(Required = true)]
|
||||
public glTFSparseIndices indices;
|
||||
|
||||
[JsonSchema(Required = true)]
|
||||
public glTFSparseValues values;
|
||||
|
||||
// empty schemas
|
||||
public object extensions;
|
||||
public object extras;
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
f.KeyValue(() => count);
|
||||
f.KeyValue(() => indices);
|
||||
f.KeyValue(() => values);
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class glTFAccessor : JsonSerializableBase
|
||||
{
|
||||
[JsonSchema(Minimum = 0)]
|
||||
public int bufferView = -1;
|
||||
|
||||
[JsonSchema(Minimum = 0, Dependencies = new string[] { "bufferView" })]
|
||||
public int byteOffset;
|
||||
|
||||
[JsonSchema(Required = true, EnumValues = new object[] { "SCALAR", "VEC2", "VEC3", "VEC4", "MAT2", "MAT3", "MAT4" }, EnumSerializationType = EnumSerializationType.AsString)]
|
||||
public string type;
|
||||
|
||||
public int TypeCount
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case "SCALAR":
|
||||
return 1;
|
||||
case "VEC2":
|
||||
return 2;
|
||||
case "VEC3":
|
||||
return 3;
|
||||
case "VEC4":
|
||||
case "MAT2":
|
||||
return 4;
|
||||
case "MAT3":
|
||||
return 9;
|
||||
case "MAT4":
|
||||
return 16;
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[JsonSchema(Required = true, EnumSerializationType = EnumSerializationType.AsInt)]
|
||||
public glComponentType componentType;
|
||||
|
||||
[JsonSchema(Required = true, Minimum = 1)]
|
||||
public int count;
|
||||
|
||||
[JsonSchema(MinItems = 1, MaxItems = 16)]
|
||||
public float[] max;
|
||||
|
||||
[JsonSchema(MinItems = 1, MaxItems = 16)]
|
||||
public float[] min;
|
||||
|
||||
public bool normalized;
|
||||
public glTFSparse sparse;
|
||||
|
||||
// empty schemas
|
||||
public string name;
|
||||
|
||||
public object extensions;
|
||||
|
||||
public object extras;
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
f.KeyValue(() => bufferView);
|
||||
f.KeyValue(() => byteOffset);
|
||||
f.KeyValue(() => type);
|
||||
f.Key("componentType"); f.Value((int)componentType);
|
||||
f.KeyValue(() => count);
|
||||
if (max != null && max.Any())
|
||||
{
|
||||
f.KeyValue(() => max);
|
||||
}
|
||||
if (min != null && min.Any())
|
||||
{
|
||||
f.KeyValue(() => min);
|
||||
}
|
||||
|
||||
if (sparse != null && sparse.count > 0)
|
||||
{
|
||||
f.KeyValue(() => sparse);
|
||||
}
|
||||
|
||||
f.KeyValue(() => normalized);
|
||||
f.KeyValue(() => name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,60 +1,60 @@
|
|||
using System;
|
||||
using UniJSON;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public enum ProjectionType
|
||||
{
|
||||
Perspective,
|
||||
Orthographic
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class glTFOrthographic
|
||||
{
|
||||
[JsonSchema(Required = true)]
|
||||
public float xmag;
|
||||
[JsonSchema(Required = true)]
|
||||
public float ymag;
|
||||
[JsonSchema(Required = true, Minimum = 0.0f, ExclusiveMinimum = true)]
|
||||
public float zfar;
|
||||
[JsonSchema(Required = true, Minimum = 0.0f)]
|
||||
public float znear;
|
||||
|
||||
[JsonSchema(MinProperties = 1)]
|
||||
public glTFOrthographic_extensions extensions;
|
||||
[JsonSchema(MinProperties = 1)]
|
||||
public glTFOrthographic_extras extras;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class glTFPerspective
|
||||
{
|
||||
[JsonSchema(Minimum = 0.0f, ExclusiveMinimum = true)]
|
||||
public float aspectRatio;
|
||||
[JsonSchema(Required = true, Minimum = 0.0f, ExclusiveMinimum = true)]
|
||||
public float yfov;
|
||||
[JsonSchema(Minimum = 0.0f, ExclusiveMinimum = true)]
|
||||
public float zfar;
|
||||
[JsonSchema(Required = true, Minimum = 0.0f, ExclusiveMinimum = true)]
|
||||
public float znear;
|
||||
|
||||
public glTFPerspective_extensions extensions;
|
||||
public glTFPerspective_extras extras;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class glTFCamera
|
||||
{
|
||||
public glTFOrthographic orthographic;
|
||||
public glTFPerspective perspective;
|
||||
|
||||
[JsonSchema(Required = true, EnumSerializationType = EnumSerializationType.AsLowerString)]
|
||||
public ProjectionType type;
|
||||
|
||||
public string name;
|
||||
|
||||
public glTFCamera_extensions extensions;
|
||||
public glTFCamera_extras extras;
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using UniJSON;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public enum ProjectionType
|
||||
{
|
||||
Perspective,
|
||||
Orthographic
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class glTFOrthographic
|
||||
{
|
||||
[JsonSchema(Required = true)]
|
||||
public float xmag;
|
||||
[JsonSchema(Required = true)]
|
||||
public float ymag;
|
||||
[JsonSchema(Required = true, Minimum = 0.0f, ExclusiveMinimum = true)]
|
||||
public float zfar;
|
||||
[JsonSchema(Required = true, Minimum = 0.0f)]
|
||||
public float znear;
|
||||
|
||||
[JsonSchema(MinProperties = 1)]
|
||||
public glTFOrthographic_extensions extensions;
|
||||
[JsonSchema(MinProperties = 1)]
|
||||
public glTFOrthographic_extras extras;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class glTFPerspective
|
||||
{
|
||||
[JsonSchema(Minimum = 0.0f, ExclusiveMinimum = true)]
|
||||
public float aspectRatio;
|
||||
[JsonSchema(Required = true, Minimum = 0.0f, ExclusiveMinimum = true)]
|
||||
public float yfov;
|
||||
[JsonSchema(Minimum = 0.0f, ExclusiveMinimum = true)]
|
||||
public float zfar;
|
||||
[JsonSchema(Required = true, Minimum = 0.0f, ExclusiveMinimum = true)]
|
||||
public float znear;
|
||||
|
||||
public glTFPerspective_extensions extensions;
|
||||
public glTFPerspective_extras extras;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class glTFCamera
|
||||
{
|
||||
public glTFOrthographic orthographic;
|
||||
public glTFPerspective perspective;
|
||||
|
||||
[JsonSchema(Required = true, EnumSerializationType = EnumSerializationType.AsLowerString)]
|
||||
public ProjectionType type;
|
||||
|
||||
public string name;
|
||||
|
||||
public glTFCamera_extensions extensions;
|
||||
public glTFCamera_extras extras;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,225 +1,225 @@
|
|||
using System;
|
||||
using UniJSON;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public enum glTFTextureTypes
|
||||
{
|
||||
BaseColor,
|
||||
Metallic,
|
||||
Normal,
|
||||
Occlusion,
|
||||
Emissive,
|
||||
Unknown
|
||||
}
|
||||
|
||||
public interface IglTFTextureinfo
|
||||
{
|
||||
glTFTextureTypes TextreType { get; }
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public abstract class glTFTextureInfo : JsonSerializableBase, IglTFTextureinfo
|
||||
{
|
||||
[JsonSchema(Required = true, Minimum = 0)]
|
||||
public int index = -1;
|
||||
|
||||
[JsonSchema(Minimum = 0)]
|
||||
public int texCoord;
|
||||
|
||||
// empty schemas
|
||||
public object extensions;
|
||||
public object extras;
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
f.KeyValue(() => index);
|
||||
f.KeyValue(() => texCoord);
|
||||
}
|
||||
|
||||
public abstract glTFTextureTypes TextreType { get; }
|
||||
}
|
||||
|
||||
|
||||
[Serializable]
|
||||
public class glTFMaterialBaseColorTextureInfo : glTFTextureInfo
|
||||
{
|
||||
public override glTFTextureTypes TextreType
|
||||
{
|
||||
get { return glTFTextureTypes.BaseColor; }
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class glTFMaterialMetallicRoughnessTextureInfo : glTFTextureInfo
|
||||
{
|
||||
public override glTFTextureTypes TextreType
|
||||
{
|
||||
get { return glTFTextureTypes.Metallic; }
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class glTFMaterialNormalTextureInfo : glTFTextureInfo
|
||||
{
|
||||
public float scale = 1.0f;
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
f.KeyValue(() => scale);
|
||||
base.SerializeMembers(f);
|
||||
}
|
||||
|
||||
public override glTFTextureTypes TextreType
|
||||
{
|
||||
get { return glTFTextureTypes.Normal; }
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class glTFMaterialOcclusionTextureInfo : glTFTextureInfo
|
||||
{
|
||||
[JsonSchema(Minimum = 0.0, Maximum = 1.0)]
|
||||
public float strength = 1.0f;
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
f.KeyValue(() => strength);
|
||||
base.SerializeMembers(f);
|
||||
}
|
||||
|
||||
public override glTFTextureTypes TextreType
|
||||
{
|
||||
get { return glTFTextureTypes.Occlusion; }
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class glTFMaterialEmissiveTextureInfo : glTFTextureInfo
|
||||
{
|
||||
public override glTFTextureTypes TextreType
|
||||
{
|
||||
get { return glTFTextureTypes.Emissive; }
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class glTFPbrMetallicRoughness : JsonSerializableBase
|
||||
{
|
||||
public glTFMaterialBaseColorTextureInfo baseColorTexture = null;
|
||||
|
||||
[JsonSchema(MinItems = 4, MaxItems = 4)]
|
||||
[ItemJsonSchema(Minimum = 0.0, Maximum = 1.0)]
|
||||
public float[] baseColorFactor;
|
||||
|
||||
public glTFMaterialMetallicRoughnessTextureInfo metallicRoughnessTexture = null;
|
||||
|
||||
[JsonSchema(Minimum = 0.0, Maximum = 1.0)]
|
||||
public float metallicFactor = 1.0f;
|
||||
|
||||
[JsonSchema(Minimum = 0.0, Maximum = 1.0)]
|
||||
public float roughnessFactor = 1.0f;
|
||||
|
||||
// empty schemas
|
||||
public object extensions;
|
||||
public object extras;
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
if (baseColorTexture != null)
|
||||
{
|
||||
f.KeyValue(() => baseColorTexture);
|
||||
}
|
||||
if (baseColorFactor != null)
|
||||
{
|
||||
f.KeyValue(() => baseColorFactor);
|
||||
}
|
||||
if (metallicRoughnessTexture != null)
|
||||
{
|
||||
f.KeyValue(() => metallicRoughnessTexture);
|
||||
}
|
||||
f.KeyValue(() => metallicFactor);
|
||||
f.KeyValue(() => roughnessFactor);
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class glTFMaterial : JsonSerializableBase
|
||||
{
|
||||
public string name;
|
||||
public glTFPbrMetallicRoughness pbrMetallicRoughness;
|
||||
public glTFMaterialNormalTextureInfo normalTexture = null;
|
||||
|
||||
public glTFMaterialOcclusionTextureInfo occlusionTexture = null;
|
||||
|
||||
public glTFMaterialEmissiveTextureInfo emissiveTexture = null;
|
||||
|
||||
[JsonSchema(MinItems = 3, MaxItems = 3)]
|
||||
[ItemJsonSchema(Minimum = 0.0, Maximum = 1.0)]
|
||||
public float[] emissiveFactor;
|
||||
|
||||
[JsonSchema(EnumValues = new object[] { "OPAQUE", "MASK", "BLEND" }, EnumSerializationType = EnumSerializationType.AsUpperString)]
|
||||
public string alphaMode;
|
||||
|
||||
[JsonSchema(Dependencies = new string[] { "alphaMode" }, Minimum = 0.0)]
|
||||
public float alphaCutoff = 0.5f;
|
||||
|
||||
public bool doubleSided;
|
||||
|
||||
[JsonSchema(SkipSchemaComparison = true)]
|
||||
public glTFMaterial_extensions extensions;
|
||||
public object extras;
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
if (!String.IsNullOrEmpty(name))
|
||||
{
|
||||
f.Key("name"); f.Value(name);
|
||||
}
|
||||
if (pbrMetallicRoughness != null)
|
||||
{
|
||||
f.Key("pbrMetallicRoughness"); f.GLTFValue(pbrMetallicRoughness);
|
||||
}
|
||||
if (normalTexture != null)
|
||||
{
|
||||
f.Key("normalTexture"); f.GLTFValue(normalTexture);
|
||||
}
|
||||
if (occlusionTexture != null)
|
||||
{
|
||||
f.Key("occlusionTexture"); f.GLTFValue(occlusionTexture);
|
||||
}
|
||||
if (emissiveTexture != null)
|
||||
{
|
||||
f.Key("emissiveTexture"); f.GLTFValue(emissiveTexture);
|
||||
}
|
||||
if (emissiveFactor != null)
|
||||
{
|
||||
f.Key("emissiveFactor"); f.Serialize(emissiveFactor);
|
||||
}
|
||||
|
||||
f.KeyValue(() => doubleSided);
|
||||
|
||||
if (!string.IsNullOrEmpty(alphaMode))
|
||||
{
|
||||
f.KeyValue(() => alphaMode);
|
||||
}
|
||||
|
||||
if (extensions != null)
|
||||
{
|
||||
f.KeyValue(() => extensions);
|
||||
}
|
||||
}
|
||||
|
||||
public glTFTextureInfo[] GetTextures()
|
||||
{
|
||||
return new glTFTextureInfo[]
|
||||
{
|
||||
pbrMetallicRoughness.baseColorTexture,
|
||||
pbrMetallicRoughness.metallicRoughnessTexture,
|
||||
normalTexture,
|
||||
occlusionTexture,
|
||||
emissiveTexture
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using UniJSON;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public enum glTFTextureTypes
|
||||
{
|
||||
BaseColor,
|
||||
Metallic,
|
||||
Normal,
|
||||
Occlusion,
|
||||
Emissive,
|
||||
Unknown
|
||||
}
|
||||
|
||||
public interface IglTFTextureinfo
|
||||
{
|
||||
glTFTextureTypes TextreType { get; }
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public abstract class glTFTextureInfo : JsonSerializableBase, IglTFTextureinfo
|
||||
{
|
||||
[JsonSchema(Required = true, Minimum = 0)]
|
||||
public int index = -1;
|
||||
|
||||
[JsonSchema(Minimum = 0)]
|
||||
public int texCoord;
|
||||
|
||||
// empty schemas
|
||||
public object extensions;
|
||||
public object extras;
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
f.KeyValue(() => index);
|
||||
f.KeyValue(() => texCoord);
|
||||
}
|
||||
|
||||
public abstract glTFTextureTypes TextreType { get; }
|
||||
}
|
||||
|
||||
|
||||
[Serializable]
|
||||
public class glTFMaterialBaseColorTextureInfo : glTFTextureInfo
|
||||
{
|
||||
public override glTFTextureTypes TextreType
|
||||
{
|
||||
get { return glTFTextureTypes.BaseColor; }
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class glTFMaterialMetallicRoughnessTextureInfo : glTFTextureInfo
|
||||
{
|
||||
public override glTFTextureTypes TextreType
|
||||
{
|
||||
get { return glTFTextureTypes.Metallic; }
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class glTFMaterialNormalTextureInfo : glTFTextureInfo
|
||||
{
|
||||
public float scale = 1.0f;
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
f.KeyValue(() => scale);
|
||||
base.SerializeMembers(f);
|
||||
}
|
||||
|
||||
public override glTFTextureTypes TextreType
|
||||
{
|
||||
get { return glTFTextureTypes.Normal; }
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class glTFMaterialOcclusionTextureInfo : glTFTextureInfo
|
||||
{
|
||||
[JsonSchema(Minimum = 0.0, Maximum = 1.0)]
|
||||
public float strength = 1.0f;
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
f.KeyValue(() => strength);
|
||||
base.SerializeMembers(f);
|
||||
}
|
||||
|
||||
public override glTFTextureTypes TextreType
|
||||
{
|
||||
get { return glTFTextureTypes.Occlusion; }
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class glTFMaterialEmissiveTextureInfo : glTFTextureInfo
|
||||
{
|
||||
public override glTFTextureTypes TextreType
|
||||
{
|
||||
get { return glTFTextureTypes.Emissive; }
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class glTFPbrMetallicRoughness : JsonSerializableBase
|
||||
{
|
||||
public glTFMaterialBaseColorTextureInfo baseColorTexture = null;
|
||||
|
||||
[JsonSchema(MinItems = 4, MaxItems = 4)]
|
||||
[ItemJsonSchema(Minimum = 0.0, Maximum = 1.0)]
|
||||
public float[] baseColorFactor;
|
||||
|
||||
public glTFMaterialMetallicRoughnessTextureInfo metallicRoughnessTexture = null;
|
||||
|
||||
[JsonSchema(Minimum = 0.0, Maximum = 1.0)]
|
||||
public float metallicFactor = 1.0f;
|
||||
|
||||
[JsonSchema(Minimum = 0.0, Maximum = 1.0)]
|
||||
public float roughnessFactor = 1.0f;
|
||||
|
||||
// empty schemas
|
||||
public object extensions;
|
||||
public object extras;
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
if (baseColorTexture != null)
|
||||
{
|
||||
f.KeyValue(() => baseColorTexture);
|
||||
}
|
||||
if (baseColorFactor != null)
|
||||
{
|
||||
f.KeyValue(() => baseColorFactor);
|
||||
}
|
||||
if (metallicRoughnessTexture != null)
|
||||
{
|
||||
f.KeyValue(() => metallicRoughnessTexture);
|
||||
}
|
||||
f.KeyValue(() => metallicFactor);
|
||||
f.KeyValue(() => roughnessFactor);
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class glTFMaterial : JsonSerializableBase
|
||||
{
|
||||
public string name;
|
||||
public glTFPbrMetallicRoughness pbrMetallicRoughness;
|
||||
public glTFMaterialNormalTextureInfo normalTexture = null;
|
||||
|
||||
public glTFMaterialOcclusionTextureInfo occlusionTexture = null;
|
||||
|
||||
public glTFMaterialEmissiveTextureInfo emissiveTexture = null;
|
||||
|
||||
[JsonSchema(MinItems = 3, MaxItems = 3)]
|
||||
[ItemJsonSchema(Minimum = 0.0, Maximum = 1.0)]
|
||||
public float[] emissiveFactor;
|
||||
|
||||
[JsonSchema(EnumValues = new object[] { "OPAQUE", "MASK", "BLEND" }, EnumSerializationType = EnumSerializationType.AsUpperString)]
|
||||
public string alphaMode;
|
||||
|
||||
[JsonSchema(Dependencies = new string[] { "alphaMode" }, Minimum = 0.0)]
|
||||
public float alphaCutoff = 0.5f;
|
||||
|
||||
public bool doubleSided;
|
||||
|
||||
[JsonSchema(SkipSchemaComparison = true)]
|
||||
public glTFMaterial_extensions extensions;
|
||||
public object extras;
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
if (!String.IsNullOrEmpty(name))
|
||||
{
|
||||
f.Key("name"); f.Value(name);
|
||||
}
|
||||
if (pbrMetallicRoughness != null)
|
||||
{
|
||||
f.Key("pbrMetallicRoughness"); f.GLTFValue(pbrMetallicRoughness);
|
||||
}
|
||||
if (normalTexture != null)
|
||||
{
|
||||
f.Key("normalTexture"); f.GLTFValue(normalTexture);
|
||||
}
|
||||
if (occlusionTexture != null)
|
||||
{
|
||||
f.Key("occlusionTexture"); f.GLTFValue(occlusionTexture);
|
||||
}
|
||||
if (emissiveTexture != null)
|
||||
{
|
||||
f.Key("emissiveTexture"); f.GLTFValue(emissiveTexture);
|
||||
}
|
||||
if (emissiveFactor != null)
|
||||
{
|
||||
f.Key("emissiveFactor"); f.Serialize(emissiveFactor);
|
||||
}
|
||||
|
||||
f.KeyValue(() => doubleSided);
|
||||
|
||||
if (!string.IsNullOrEmpty(alphaMode))
|
||||
{
|
||||
f.KeyValue(() => alphaMode);
|
||||
}
|
||||
|
||||
if (extensions != null)
|
||||
{
|
||||
f.KeyValue(() => extensions);
|
||||
}
|
||||
}
|
||||
|
||||
public glTFTextureInfo[] GetTextures()
|
||||
{
|
||||
return new glTFTextureInfo[]
|
||||
{
|
||||
pbrMetallicRoughness.baseColorTexture,
|
||||
pbrMetallicRoughness.metallicRoughnessTexture,
|
||||
normalTexture,
|
||||
occlusionTexture,
|
||||
emissiveTexture
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,168 +1,168 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UniJSON;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
[Serializable]
|
||||
public class glTFAttributes : JsonSerializableBase
|
||||
{
|
||||
[JsonSchema(Minimum = 0)]
|
||||
public int POSITION = -1;
|
||||
|
||||
[JsonSchema(Minimum = 0)]
|
||||
public int NORMAL = -1;
|
||||
|
||||
[JsonSchema(Minimum = 0)]
|
||||
public int TANGENT = -1;
|
||||
|
||||
[JsonSchema(Minimum = 0)]
|
||||
public int TEXCOORD_0 = -1;
|
||||
|
||||
[JsonSchema(Minimum = 0)]
|
||||
public int COLOR_0 = -1;
|
||||
|
||||
[JsonSchema(Minimum = 0)]
|
||||
public int JOINTS_0 = -1;
|
||||
|
||||
[JsonSchema(Minimum = 0)]
|
||||
public int WEIGHTS_0 = -1;
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return base.GetHashCode();
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
var rhs = obj as glTFAttributes;
|
||||
if (rhs == null)
|
||||
{
|
||||
return base.Equals(obj);
|
||||
}
|
||||
|
||||
return POSITION == rhs.POSITION
|
||||
&& NORMAL == rhs.NORMAL
|
||||
&& TANGENT == rhs.TANGENT
|
||||
&& TEXCOORD_0 == rhs.TEXCOORD_0
|
||||
&& COLOR_0 == rhs.COLOR_0
|
||||
&& JOINTS_0 == rhs.JOINTS_0
|
||||
&& WEIGHTS_0 == rhs.WEIGHTS_0
|
||||
;
|
||||
}
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
f.KeyValue(() => POSITION);
|
||||
if (NORMAL != -1) f.KeyValue(() => NORMAL);
|
||||
if (TANGENT != -1) f.KeyValue(() => TANGENT);
|
||||
if (TEXCOORD_0 != -1) f.KeyValue(() => TEXCOORD_0);
|
||||
if (COLOR_0 != -1) f.KeyValue(() => COLOR_0);
|
||||
if (JOINTS_0 != -1) f.KeyValue(() => JOINTS_0);
|
||||
if (WEIGHTS_0 != -1) f.KeyValue(() => WEIGHTS_0);
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class gltfMorphTarget : JsonSerializableBase
|
||||
{
|
||||
public int POSITION = -1;
|
||||
public int NORMAL = -1;
|
||||
public int TANGENT = -1;
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
f.KeyValue(() => POSITION);
|
||||
if (NORMAL >= 0) f.KeyValue(() => NORMAL);
|
||||
if (TANGENT >= 0) f.KeyValue(() => TANGENT);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/schema/mesh.primitive.schema.json
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class glTFPrimitives : JsonSerializableBase
|
||||
{
|
||||
[JsonSchema(EnumValues = new object[] { 0, 1, 2, 3, 4, 5, 6 })]
|
||||
public int mode;
|
||||
|
||||
[JsonSchema(Minimum = 0)]
|
||||
public int indices = -1;
|
||||
|
||||
[JsonSchema(Required = true, SkipSchemaComparison = true)]
|
||||
public glTFAttributes attributes;
|
||||
|
||||
public bool HasVertexColor
|
||||
{
|
||||
get
|
||||
{
|
||||
return attributes.COLOR_0 != -1;
|
||||
}
|
||||
}
|
||||
|
||||
[JsonSchema(Minimum = 0)]
|
||||
public int material;
|
||||
|
||||
[JsonSchema(MinItems = 1)]
|
||||
[ItemJsonSchema(SkipSchemaComparison = true)]
|
||||
public List<gltfMorphTarget> targets = new List<gltfMorphTarget>();
|
||||
|
||||
public glTFPrimitives_extras extras = new glTFPrimitives_extras();
|
||||
|
||||
[JsonSchema(SkipSchemaComparison = true)]
|
||||
public glTFPrimitives_extensions extensions = new glTFPrimitives_extensions();
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
f.KeyValue(() => mode);
|
||||
f.KeyValue(() => indices);
|
||||
f.Key("attributes"); f.GLTFValue(attributes);
|
||||
f.KeyValue(() => material);
|
||||
if (targets != null && targets.Count > 0)
|
||||
{
|
||||
f.Key("targets"); f.GLTFValue(targets);
|
||||
}
|
||||
if (extensions.KHR_draco_mesh_compression != null)
|
||||
{
|
||||
f.KeyValue(() => extensions);
|
||||
}
|
||||
if (extras.targetNames.Count > 0)
|
||||
{
|
||||
f.KeyValue(() => extras);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class glTFMesh : JsonSerializableBase
|
||||
{
|
||||
public string name;
|
||||
|
||||
[JsonSchema(Required = true, MinItems = 1)]
|
||||
public List<glTFPrimitives> primitives;
|
||||
|
||||
[JsonSchema(MinItems = 1)]
|
||||
public float[] weights;
|
||||
|
||||
// empty schemas
|
||||
public object extensions;
|
||||
public object extras;
|
||||
|
||||
public glTFMesh(string _name)
|
||||
{
|
||||
name = _name;
|
||||
primitives = new List<glTFPrimitives>();
|
||||
}
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
f.KeyValue(() => name);
|
||||
f.Key("primitives"); f.GLTFValue(primitives);
|
||||
if (weights != null && weights.Length > 0)
|
||||
{
|
||||
f.KeyValue(() => weights);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UniJSON;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
[Serializable]
|
||||
public class glTFAttributes : JsonSerializableBase
|
||||
{
|
||||
[JsonSchema(Minimum = 0)]
|
||||
public int POSITION = -1;
|
||||
|
||||
[JsonSchema(Minimum = 0)]
|
||||
public int NORMAL = -1;
|
||||
|
||||
[JsonSchema(Minimum = 0)]
|
||||
public int TANGENT = -1;
|
||||
|
||||
[JsonSchema(Minimum = 0)]
|
||||
public int TEXCOORD_0 = -1;
|
||||
|
||||
[JsonSchema(Minimum = 0)]
|
||||
public int COLOR_0 = -1;
|
||||
|
||||
[JsonSchema(Minimum = 0)]
|
||||
public int JOINTS_0 = -1;
|
||||
|
||||
[JsonSchema(Minimum = 0)]
|
||||
public int WEIGHTS_0 = -1;
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return base.GetHashCode();
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
var rhs = obj as glTFAttributes;
|
||||
if (rhs == null)
|
||||
{
|
||||
return base.Equals(obj);
|
||||
}
|
||||
|
||||
return POSITION == rhs.POSITION
|
||||
&& NORMAL == rhs.NORMAL
|
||||
&& TANGENT == rhs.TANGENT
|
||||
&& TEXCOORD_0 == rhs.TEXCOORD_0
|
||||
&& COLOR_0 == rhs.COLOR_0
|
||||
&& JOINTS_0 == rhs.JOINTS_0
|
||||
&& WEIGHTS_0 == rhs.WEIGHTS_0
|
||||
;
|
||||
}
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
f.KeyValue(() => POSITION);
|
||||
if (NORMAL != -1) f.KeyValue(() => NORMAL);
|
||||
if (TANGENT != -1) f.KeyValue(() => TANGENT);
|
||||
if (TEXCOORD_0 != -1) f.KeyValue(() => TEXCOORD_0);
|
||||
if (COLOR_0 != -1) f.KeyValue(() => COLOR_0);
|
||||
if (JOINTS_0 != -1) f.KeyValue(() => JOINTS_0);
|
||||
if (WEIGHTS_0 != -1) f.KeyValue(() => WEIGHTS_0);
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class gltfMorphTarget : JsonSerializableBase
|
||||
{
|
||||
public int POSITION = -1;
|
||||
public int NORMAL = -1;
|
||||
public int TANGENT = -1;
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
f.KeyValue(() => POSITION);
|
||||
if (NORMAL >= 0) f.KeyValue(() => NORMAL);
|
||||
if (TANGENT >= 0) f.KeyValue(() => TANGENT);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/schema/mesh.primitive.schema.json
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class glTFPrimitives : JsonSerializableBase
|
||||
{
|
||||
[JsonSchema(EnumValues = new object[] { 0, 1, 2, 3, 4, 5, 6 })]
|
||||
public int mode;
|
||||
|
||||
[JsonSchema(Minimum = 0)]
|
||||
public int indices = -1;
|
||||
|
||||
[JsonSchema(Required = true, SkipSchemaComparison = true)]
|
||||
public glTFAttributes attributes;
|
||||
|
||||
public bool HasVertexColor
|
||||
{
|
||||
get
|
||||
{
|
||||
return attributes.COLOR_0 != -1;
|
||||
}
|
||||
}
|
||||
|
||||
[JsonSchema(Minimum = 0)]
|
||||
public int material;
|
||||
|
||||
[JsonSchema(MinItems = 1)]
|
||||
[ItemJsonSchema(SkipSchemaComparison = true)]
|
||||
public List<gltfMorphTarget> targets = new List<gltfMorphTarget>();
|
||||
|
||||
public glTFPrimitives_extras extras = new glTFPrimitives_extras();
|
||||
|
||||
[JsonSchema(SkipSchemaComparison = true)]
|
||||
public glTFPrimitives_extensions extensions = new glTFPrimitives_extensions();
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
f.KeyValue(() => mode);
|
||||
f.KeyValue(() => indices);
|
||||
f.Key("attributes"); f.GLTFValue(attributes);
|
||||
f.KeyValue(() => material);
|
||||
if (targets != null && targets.Count > 0)
|
||||
{
|
||||
f.Key("targets"); f.GLTFValue(targets);
|
||||
}
|
||||
if (extensions.KHR_draco_mesh_compression != null)
|
||||
{
|
||||
f.KeyValue(() => extensions);
|
||||
}
|
||||
if (extras.targetNames.Count > 0)
|
||||
{
|
||||
f.KeyValue(() => extras);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class glTFMesh : JsonSerializableBase
|
||||
{
|
||||
public string name;
|
||||
|
||||
[JsonSchema(Required = true, MinItems = 1)]
|
||||
public List<glTFPrimitives> primitives;
|
||||
|
||||
[JsonSchema(MinItems = 1)]
|
||||
public float[] weights;
|
||||
|
||||
// empty schemas
|
||||
public object extensions;
|
||||
public object extras;
|
||||
|
||||
public glTFMesh(string _name)
|
||||
{
|
||||
name = _name;
|
||||
primitives = new List<glTFPrimitives>();
|
||||
}
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
f.KeyValue(() => name);
|
||||
f.Key("primitives"); f.GLTFValue(primitives);
|
||||
if (weights != null && weights.Length > 0)
|
||||
{
|
||||
f.KeyValue(() => weights);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,76 +1,76 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using UniJSON;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
[Serializable]
|
||||
public class glTFNode : JsonSerializableBase
|
||||
{
|
||||
public string name = "";
|
||||
|
||||
[JsonSchema(MinItems = 1)]
|
||||
[ItemJsonSchema(Minimum = 0)]
|
||||
public int[] children;
|
||||
|
||||
[JsonSchema(MinItems = 16, MaxItems = 16)]
|
||||
public float[] matrix;
|
||||
|
||||
[JsonSchema(MinItems = 3, MaxItems = 3)]
|
||||
public float[] translation;
|
||||
|
||||
[JsonSchema(MinItems = 4, MaxItems = 4)]
|
||||
[ItemJsonSchema(Minimum = -1.0, Maximum = 1.0)]
|
||||
public float[] rotation;
|
||||
|
||||
[JsonSchema(MinItems = 3, MaxItems = 3)]
|
||||
public float[] scale;
|
||||
|
||||
[JsonSchema(Minimum = 0)]
|
||||
public int mesh = -1;
|
||||
|
||||
[JsonSchema(Dependencies = new string[] { "mesh" }, Minimum = 0)]
|
||||
public int skin = -1;
|
||||
|
||||
[JsonSchema(Dependencies = new string[] { "mesh" }, MinItems = 1)]
|
||||
public float[] weights;
|
||||
|
||||
[JsonSchema(Minimum = 0)]
|
||||
public int camera = -1;
|
||||
|
||||
// empty schemas
|
||||
public glTFNode_extensions extensions;
|
||||
public glTFNode_extra extras = new glTFNode_extra();
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
if (children != null && children.Any())
|
||||
{
|
||||
f.Key("children"); f.BeginList();
|
||||
foreach (var child in children)
|
||||
{
|
||||
f.Value(child);
|
||||
}
|
||||
f.EndList();
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(name)) f.KeyValue(() => name);
|
||||
if (matrix != null) f.KeyValue(() => matrix);
|
||||
if (translation != null) f.KeyValue(() => translation);
|
||||
if (rotation != null) f.KeyValue(() => rotation);
|
||||
if (scale != null) f.KeyValue(() => scale);
|
||||
|
||||
if (mesh >= 0) f.KeyValue(() => mesh);
|
||||
if (camera >= 0) f.KeyValue(() => camera);
|
||||
if (skin >= 0)
|
||||
{
|
||||
f.KeyValue(() => skin);
|
||||
|
||||
if (extras.__count > 0)
|
||||
{
|
||||
f.KeyValue(() => extras);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Linq;
|
||||
using UniJSON;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
[Serializable]
|
||||
public class glTFNode : JsonSerializableBase
|
||||
{
|
||||
public string name = "";
|
||||
|
||||
[JsonSchema(MinItems = 1)]
|
||||
[ItemJsonSchema(Minimum = 0)]
|
||||
public int[] children;
|
||||
|
||||
[JsonSchema(MinItems = 16, MaxItems = 16)]
|
||||
public float[] matrix;
|
||||
|
||||
[JsonSchema(MinItems = 3, MaxItems = 3)]
|
||||
public float[] translation;
|
||||
|
||||
[JsonSchema(MinItems = 4, MaxItems = 4)]
|
||||
[ItemJsonSchema(Minimum = -1.0, Maximum = 1.0)]
|
||||
public float[] rotation;
|
||||
|
||||
[JsonSchema(MinItems = 3, MaxItems = 3)]
|
||||
public float[] scale;
|
||||
|
||||
[JsonSchema(Minimum = 0)]
|
||||
public int mesh = -1;
|
||||
|
||||
[JsonSchema(Dependencies = new string[] { "mesh" }, Minimum = 0)]
|
||||
public int skin = -1;
|
||||
|
||||
[JsonSchema(Dependencies = new string[] { "mesh" }, MinItems = 1)]
|
||||
public float[] weights;
|
||||
|
||||
[JsonSchema(Minimum = 0)]
|
||||
public int camera = -1;
|
||||
|
||||
// empty schemas
|
||||
public glTFNode_extensions extensions;
|
||||
public glTFNode_extra extras = new glTFNode_extra();
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
if (children != null && children.Any())
|
||||
{
|
||||
f.Key("children"); f.BeginList();
|
||||
foreach (var child in children)
|
||||
{
|
||||
f.Value(child);
|
||||
}
|
||||
f.EndList();
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(name)) f.KeyValue(() => name);
|
||||
if (matrix != null) f.KeyValue(() => matrix);
|
||||
if (translation != null) f.KeyValue(() => translation);
|
||||
if (rotation != null) f.KeyValue(() => rotation);
|
||||
if (scale != null) f.KeyValue(() => scale);
|
||||
|
||||
if (mesh >= 0) f.KeyValue(() => mesh);
|
||||
if (camera >= 0) f.KeyValue(() => camera);
|
||||
if (skin >= 0)
|
||||
{
|
||||
f.KeyValue(() => skin);
|
||||
|
||||
if (extras.__count > 0)
|
||||
{
|
||||
f.KeyValue(() => extras);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,34 +1,34 @@
|
|||
using System;
|
||||
using UniJSON;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
[Serializable]
|
||||
public class glTFSkin : JsonSerializableBase
|
||||
{
|
||||
[JsonSchema(Minimum = 0)]
|
||||
public int inverseBindMatrices = -1;
|
||||
|
||||
[JsonSchema(Required = true, MinItems = 1)]
|
||||
[ItemJsonSchema(Minimum = 0)]
|
||||
public int[] joints;
|
||||
|
||||
[JsonSchema(Minimum = 0)]
|
||||
public int skeleton = -1;
|
||||
|
||||
// empty schemas
|
||||
public object extensions;
|
||||
public object extras;
|
||||
public string name;
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
f.KeyValue(() => inverseBindMatrices);
|
||||
f.KeyValue(() => joints);
|
||||
if (skeleton >= 0)
|
||||
{
|
||||
f.KeyValue(() => skeleton);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using UniJSON;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
[Serializable]
|
||||
public class glTFSkin : JsonSerializableBase
|
||||
{
|
||||
[JsonSchema(Minimum = 0)]
|
||||
public int inverseBindMatrices = -1;
|
||||
|
||||
[JsonSchema(Required = true, MinItems = 1)]
|
||||
[ItemJsonSchema(Minimum = 0)]
|
||||
public int[] joints;
|
||||
|
||||
[JsonSchema(Minimum = 0)]
|
||||
public int skeleton = -1;
|
||||
|
||||
// empty schemas
|
||||
public object extensions;
|
||||
public object extras;
|
||||
public string name;
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
f.KeyValue(() => inverseBindMatrices);
|
||||
f.KeyValue(() => joints);
|
||||
if (skeleton >= 0)
|
||||
{
|
||||
f.KeyValue(() => skeleton);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,123 +1,123 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using UniJSON;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
[Serializable]
|
||||
public class glTFTextureSampler : JsonSerializableBase
|
||||
{
|
||||
[JsonSchema(EnumSerializationType = EnumSerializationType.AsInt,
|
||||
EnumExcludes = new object[] {
|
||||
glFilter.NONE,
|
||||
glFilter.NEAREST_MIPMAP_NEAREST,
|
||||
glFilter.LINEAR_MIPMAP_NEAREST,
|
||||
glFilter.NEAREST_MIPMAP_LINEAR,
|
||||
glFilter.LINEAR_MIPMAP_LINEAR,
|
||||
})]
|
||||
public glFilter magFilter = glFilter.NEAREST;
|
||||
|
||||
[JsonSchema(EnumSerializationType = EnumSerializationType.AsInt,
|
||||
EnumExcludes = new object[] { glFilter.NONE })]
|
||||
public glFilter minFilter = glFilter.NEAREST;
|
||||
|
||||
[JsonSchema(EnumSerializationType = EnumSerializationType.AsInt,
|
||||
EnumExcludes = new object[] { glWrap.NONE })]
|
||||
public glWrap wrapS = glWrap.REPEAT;
|
||||
|
||||
[JsonSchema(EnumSerializationType = EnumSerializationType.AsInt,
|
||||
EnumExcludes = new object[] { glWrap.NONE })]
|
||||
public glWrap wrapT = glWrap.REPEAT;
|
||||
|
||||
// empty schemas
|
||||
public object extensions;
|
||||
public object extras;
|
||||
public string name;
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
f.Key("magFilter"); f.Value((int)magFilter);
|
||||
f.Key("minFilter"); f.Value((int)minFilter);
|
||||
f.Key("wrapS"); f.Value((int)wrapS);
|
||||
f.Key("wrapT"); f.Value((int)wrapT);
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class glTFImage : JsonSerializableBase
|
||||
{
|
||||
public string name;
|
||||
public string uri;
|
||||
|
||||
[JsonSchema(Dependencies = new string[] { "mimeType" }, Minimum = 0)]
|
||||
public int bufferView;
|
||||
|
||||
[JsonSchema(EnumValues = new object[] { "image/jpeg", "image/png" }, EnumSerializationType =EnumSerializationType.AsString)]
|
||||
public string mimeType;
|
||||
|
||||
public string GetExt()
|
||||
{
|
||||
switch (mimeType)
|
||||
{
|
||||
case "image/png":
|
||||
return ".png";
|
||||
|
||||
case "image/jpeg":
|
||||
return ".jpg";
|
||||
|
||||
default:
|
||||
if (uri.StartsWith("data:image/jpeg;"))
|
||||
{
|
||||
return ".jpg";
|
||||
}
|
||||
else if (uri.StartsWith("data:image/png;"))
|
||||
{
|
||||
return ".png";
|
||||
}
|
||||
else
|
||||
{
|
||||
return Path.GetExtension(uri).ToLower();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// empty schemas
|
||||
public object extensions;
|
||||
public object extras;
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
f.KeyValue(() => name);
|
||||
if (!string.IsNullOrEmpty(uri))
|
||||
{
|
||||
f.KeyValue(() => uri);
|
||||
}
|
||||
else
|
||||
{
|
||||
f.KeyValue(() => bufferView);
|
||||
f.KeyValue(() => mimeType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class glTFTexture : JsonSerializableBase
|
||||
{
|
||||
[JsonSchema(Minimum = 0)]
|
||||
public int sampler;
|
||||
|
||||
[JsonSchema(Minimum = 0)]
|
||||
public int source;
|
||||
|
||||
// empty schemas
|
||||
public object extensions;
|
||||
public object extras;
|
||||
public string name;
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
f.KeyValue(() => sampler);
|
||||
f.KeyValue(() => source);
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.IO;
|
||||
using UniJSON;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
[Serializable]
|
||||
public class glTFTextureSampler : JsonSerializableBase
|
||||
{
|
||||
[JsonSchema(EnumSerializationType = EnumSerializationType.AsInt,
|
||||
EnumExcludes = new object[] {
|
||||
glFilter.NONE,
|
||||
glFilter.NEAREST_MIPMAP_NEAREST,
|
||||
glFilter.LINEAR_MIPMAP_NEAREST,
|
||||
glFilter.NEAREST_MIPMAP_LINEAR,
|
||||
glFilter.LINEAR_MIPMAP_LINEAR,
|
||||
})]
|
||||
public glFilter magFilter = glFilter.NEAREST;
|
||||
|
||||
[JsonSchema(EnumSerializationType = EnumSerializationType.AsInt,
|
||||
EnumExcludes = new object[] { glFilter.NONE })]
|
||||
public glFilter minFilter = glFilter.NEAREST;
|
||||
|
||||
[JsonSchema(EnumSerializationType = EnumSerializationType.AsInt,
|
||||
EnumExcludes = new object[] { glWrap.NONE })]
|
||||
public glWrap wrapS = glWrap.REPEAT;
|
||||
|
||||
[JsonSchema(EnumSerializationType = EnumSerializationType.AsInt,
|
||||
EnumExcludes = new object[] { glWrap.NONE })]
|
||||
public glWrap wrapT = glWrap.REPEAT;
|
||||
|
||||
// empty schemas
|
||||
public object extensions;
|
||||
public object extras;
|
||||
public string name;
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
f.Key("magFilter"); f.Value((int)magFilter);
|
||||
f.Key("minFilter"); f.Value((int)minFilter);
|
||||
f.Key("wrapS"); f.Value((int)wrapS);
|
||||
f.Key("wrapT"); f.Value((int)wrapT);
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class glTFImage : JsonSerializableBase
|
||||
{
|
||||
public string name;
|
||||
public string uri;
|
||||
|
||||
[JsonSchema(Dependencies = new string[] { "mimeType" }, Minimum = 0)]
|
||||
public int bufferView;
|
||||
|
||||
[JsonSchema(EnumValues = new object[] { "image/jpeg", "image/png" }, EnumSerializationType =EnumSerializationType.AsString)]
|
||||
public string mimeType;
|
||||
|
||||
public string GetExt()
|
||||
{
|
||||
switch (mimeType)
|
||||
{
|
||||
case "image/png":
|
||||
return ".png";
|
||||
|
||||
case "image/jpeg":
|
||||
return ".jpg";
|
||||
|
||||
default:
|
||||
if (uri.StartsWith("data:image/jpeg;"))
|
||||
{
|
||||
return ".jpg";
|
||||
}
|
||||
else if (uri.StartsWith("data:image/png;"))
|
||||
{
|
||||
return ".png";
|
||||
}
|
||||
else
|
||||
{
|
||||
return Path.GetExtension(uri).ToLower();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// empty schemas
|
||||
public object extensions;
|
||||
public object extras;
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
f.KeyValue(() => name);
|
||||
if (!string.IsNullOrEmpty(uri))
|
||||
{
|
||||
f.KeyValue(() => uri);
|
||||
}
|
||||
else
|
||||
{
|
||||
f.KeyValue(() => bufferView);
|
||||
f.KeyValue(() => mimeType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class glTFTexture : JsonSerializableBase
|
||||
{
|
||||
[JsonSchema(Minimum = 0)]
|
||||
public int sampler;
|
||||
|
||||
[JsonSchema(Minimum = 0)]
|
||||
public int source;
|
||||
|
||||
// empty schemas
|
||||
public object extensions;
|
||||
public object extras;
|
||||
public string name;
|
||||
|
||||
protected override void SerializeMembers(GLTFJsonFormatter f)
|
||||
{
|
||||
f.KeyValue(() => sampler);
|
||||
f.KeyValue(() => source);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,142 +1,142 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public enum GlbChunkType : UInt32
|
||||
{
|
||||
JSON = 0x4E4F534A,
|
||||
BIN = 0x004E4942,
|
||||
}
|
||||
|
||||
public struct GlbHeader
|
||||
{
|
||||
public static void WriteTo(Stream s)
|
||||
{
|
||||
s.WriteByte((Byte)'g');
|
||||
s.WriteByte((Byte)'l');
|
||||
s.WriteByte((Byte)'T');
|
||||
s.WriteByte((Byte)'F');
|
||||
var bytes = BitConverter.GetBytes((UInt32)2);
|
||||
s.Write(bytes, 0, bytes.Length);
|
||||
}
|
||||
}
|
||||
|
||||
public struct GlbChunk
|
||||
{
|
||||
public GlbChunkType ChunkType;
|
||||
public ArraySegment<Byte> Bytes;
|
||||
|
||||
public GlbChunk(string json) : this(
|
||||
GlbChunkType.JSON,
|
||||
new ArraySegment<byte>(Encoding.UTF8.GetBytes(json))
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
public GlbChunk(ArraySegment<Byte> bytes) : this(
|
||||
GlbChunkType.BIN,
|
||||
bytes
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
public GlbChunk(GlbChunkType type, ArraySegment<Byte> bytes)
|
||||
{
|
||||
ChunkType = type;
|
||||
Bytes = bytes;
|
||||
}
|
||||
|
||||
byte GetPaddingByte()
|
||||
{
|
||||
// chunk type
|
||||
switch (ChunkType)
|
||||
{
|
||||
case GlbChunkType.JSON:
|
||||
return 0x20;
|
||||
|
||||
case GlbChunkType.BIN:
|
||||
return 0x00;
|
||||
|
||||
default:
|
||||
throw new Exception("unknown chunk type: " + ChunkType);
|
||||
}
|
||||
}
|
||||
|
||||
public int WriteTo(Stream s)
|
||||
{
|
||||
// padding
|
||||
var paddingValue = Bytes.Count % 4;
|
||||
var padding = (paddingValue > 0) ? 4 - paddingValue : 0;
|
||||
|
||||
// size
|
||||
var bytes = BitConverter.GetBytes((int)(Bytes.Count + padding));
|
||||
s.Write(bytes, 0, bytes.Length);
|
||||
|
||||
// chunk type
|
||||
switch (ChunkType)
|
||||
{
|
||||
case GlbChunkType.JSON:
|
||||
s.WriteByte((byte)'J');
|
||||
s.WriteByte((byte)'S');
|
||||
s.WriteByte((byte)'O');
|
||||
s.WriteByte((byte)'N');
|
||||
break;
|
||||
|
||||
case GlbChunkType.BIN:
|
||||
s.WriteByte((byte)'B');
|
||||
s.WriteByte((byte)'I');
|
||||
s.WriteByte((byte)'N');
|
||||
s.WriteByte((byte)0);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Exception("unknown chunk type: " + ChunkType);
|
||||
}
|
||||
|
||||
// body
|
||||
s.Write(Bytes.Array, Bytes.Offset, Bytes.Count);
|
||||
|
||||
// 4byte align
|
||||
var pad = GetPaddingByte();
|
||||
for(int i=0; i<padding; ++i)
|
||||
{
|
||||
s.WriteByte(pad);
|
||||
}
|
||||
|
||||
return 4 + 4 + Bytes.Count + padding;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Glb
|
||||
{
|
||||
public static byte[] ToBytes(string json, ArraySegment<byte> body)
|
||||
{
|
||||
using (var s = new MemoryStream())
|
||||
{
|
||||
GlbHeader.WriteTo(s);
|
||||
|
||||
var pos = s.Position;
|
||||
s.Position += 4; // skip total size
|
||||
|
||||
int size = 12;
|
||||
|
||||
{
|
||||
var chunk = new GlbChunk(json);
|
||||
size += chunk.WriteTo(s);
|
||||
}
|
||||
{
|
||||
var chunk = new GlbChunk(body);
|
||||
size += chunk.WriteTo(s);
|
||||
}
|
||||
|
||||
s.Position = pos;
|
||||
var bytes = BitConverter.GetBytes(size);
|
||||
s.Write(bytes, 0, bytes.Length);
|
||||
|
||||
return s.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public enum GlbChunkType : UInt32
|
||||
{
|
||||
JSON = 0x4E4F534A,
|
||||
BIN = 0x004E4942,
|
||||
}
|
||||
|
||||
public struct GlbHeader
|
||||
{
|
||||
public static void WriteTo(Stream s)
|
||||
{
|
||||
s.WriteByte((Byte)'g');
|
||||
s.WriteByte((Byte)'l');
|
||||
s.WriteByte((Byte)'T');
|
||||
s.WriteByte((Byte)'F');
|
||||
var bytes = BitConverter.GetBytes((UInt32)2);
|
||||
s.Write(bytes, 0, bytes.Length);
|
||||
}
|
||||
}
|
||||
|
||||
public struct GlbChunk
|
||||
{
|
||||
public GlbChunkType ChunkType;
|
||||
public ArraySegment<Byte> Bytes;
|
||||
|
||||
public GlbChunk(string json) : this(
|
||||
GlbChunkType.JSON,
|
||||
new ArraySegment<byte>(Encoding.UTF8.GetBytes(json))
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
public GlbChunk(ArraySegment<Byte> bytes) : this(
|
||||
GlbChunkType.BIN,
|
||||
bytes
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
public GlbChunk(GlbChunkType type, ArraySegment<Byte> bytes)
|
||||
{
|
||||
ChunkType = type;
|
||||
Bytes = bytes;
|
||||
}
|
||||
|
||||
byte GetPaddingByte()
|
||||
{
|
||||
// chunk type
|
||||
switch (ChunkType)
|
||||
{
|
||||
case GlbChunkType.JSON:
|
||||
return 0x20;
|
||||
|
||||
case GlbChunkType.BIN:
|
||||
return 0x00;
|
||||
|
||||
default:
|
||||
throw new Exception("unknown chunk type: " + ChunkType);
|
||||
}
|
||||
}
|
||||
|
||||
public int WriteTo(Stream s)
|
||||
{
|
||||
// padding
|
||||
var paddingValue = Bytes.Count % 4;
|
||||
var padding = (paddingValue > 0) ? 4 - paddingValue : 0;
|
||||
|
||||
// size
|
||||
var bytes = BitConverter.GetBytes((int)(Bytes.Count + padding));
|
||||
s.Write(bytes, 0, bytes.Length);
|
||||
|
||||
// chunk type
|
||||
switch (ChunkType)
|
||||
{
|
||||
case GlbChunkType.JSON:
|
||||
s.WriteByte((byte)'J');
|
||||
s.WriteByte((byte)'S');
|
||||
s.WriteByte((byte)'O');
|
||||
s.WriteByte((byte)'N');
|
||||
break;
|
||||
|
||||
case GlbChunkType.BIN:
|
||||
s.WriteByte((byte)'B');
|
||||
s.WriteByte((byte)'I');
|
||||
s.WriteByte((byte)'N');
|
||||
s.WriteByte((byte)0);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Exception("unknown chunk type: " + ChunkType);
|
||||
}
|
||||
|
||||
// body
|
||||
s.Write(Bytes.Array, Bytes.Offset, Bytes.Count);
|
||||
|
||||
// 4byte align
|
||||
var pad = GetPaddingByte();
|
||||
for(int i=0; i<padding; ++i)
|
||||
{
|
||||
s.WriteByte(pad);
|
||||
}
|
||||
|
||||
return 4 + 4 + Bytes.Count + padding;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Glb
|
||||
{
|
||||
public static byte[] ToBytes(string json, ArraySegment<byte> body)
|
||||
{
|
||||
using (var s = new MemoryStream())
|
||||
{
|
||||
GlbHeader.WriteTo(s);
|
||||
|
||||
var pos = s.Position;
|
||||
s.Position += 4; // skip total size
|
||||
|
||||
int size = 12;
|
||||
|
||||
{
|
||||
var chunk = new GlbChunk(json);
|
||||
size += chunk.WriteTo(s);
|
||||
}
|
||||
{
|
||||
var chunk = new GlbChunk(body);
|
||||
size += chunk.WriteTo(s);
|
||||
}
|
||||
|
||||
s.Position = pos;
|
||||
var bytes = BitConverter.GetBytes(size);
|
||||
s.Write(bytes, 0, bytes.Length);
|
||||
|
||||
return s.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,121 +1,121 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
class AnimationCurveData
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
public AnimationUtility.TangentMode TangentMode { get; private set; }
|
||||
public glTFAnimationTarget.AnimationPropertys AnimationProperty { get; private set; }
|
||||
public int SamplerIndex { get; private set; }
|
||||
public int ElementCount { get; private set; }
|
||||
public readonly List<AnimationKeyframeData> Keyframes = new List<AnimationKeyframeData>();
|
||||
|
||||
public AnimationCurveData(AnimationUtility.TangentMode tangentMode, glTFAnimationTarget.AnimationPropertys property, int samplerIndex, int elementCount)
|
||||
{
|
||||
TangentMode = tangentMode;
|
||||
AnimationProperty = property;
|
||||
SamplerIndex = samplerIndex;
|
||||
ElementCount = elementCount;
|
||||
}
|
||||
|
||||
public string GetInterpolation()
|
||||
{
|
||||
switch (TangentMode)
|
||||
{
|
||||
case AnimationUtility.TangentMode.Linear:
|
||||
return glTFAnimationTarget.Interpolations.LINEAR.ToString();
|
||||
case AnimationUtility.TangentMode.Constant:
|
||||
return glTFAnimationTarget.Interpolations.STEP.ToString();
|
||||
default:
|
||||
return glTFAnimationTarget.Interpolations.LINEAR.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// キーフレームのデータを入力する
|
||||
/// </summary>
|
||||
/// <param name="time"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="valueOffset"></param>
|
||||
public void SetKeyframeData(float time, float value, int valueOffset)
|
||||
{
|
||||
var existKeyframe = Keyframes.FirstOrDefault(x => x.Time == time);
|
||||
if (existKeyframe != null)
|
||||
{
|
||||
existKeyframe.SetValue(value, valueOffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
var newKeyframe = GetKeyframeData(AnimationProperty, ElementCount);
|
||||
newKeyframe.Time = time;
|
||||
newKeyframe.SetValue(value, valueOffset);
|
||||
Keyframes.Add(newKeyframe);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// キー情報がなかった要素に対して直前のキーの値を入力する
|
||||
/// </summary>
|
||||
public void RecountEmptyKeyframe()
|
||||
{
|
||||
if (Keyframes.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Keyframes.Sort((x, y) => (x.Time < y.Time) ? -1 : 1);
|
||||
|
||||
for (int i = 1; i < Keyframes.Count; i++)
|
||||
{
|
||||
var current = Keyframes[i];
|
||||
var last = Keyframes[i - 1];
|
||||
for (int j = 0; j < current.EnterValues.Length; j++)
|
||||
{
|
||||
if (!current.EnterValues[j])
|
||||
{
|
||||
Keyframes[i].SetValue(last.Values[j], j);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// アニメーションプロパティに対応したキーフレームを挿入する
|
||||
/// </summary>
|
||||
/// <param name="property"></param>
|
||||
/// <returns></returns>
|
||||
private static AnimationKeyframeData GetKeyframeData(glTFAnimationTarget.AnimationPropertys property, int elementCount)
|
||||
{
|
||||
switch (property)
|
||||
{
|
||||
case glTFAnimationTarget.AnimationPropertys.Translation:
|
||||
return new AnimationKeyframeData(elementCount, (values) =>
|
||||
{
|
||||
var temp = new Vector3(values[0], values[1], values[2]);
|
||||
return temp.ReverseZ().ToArray();
|
||||
});
|
||||
case glTFAnimationTarget.AnimationPropertys.Rotation:
|
||||
return new AnimationKeyframeData(elementCount, (values) =>
|
||||
{
|
||||
var temp = new Quaternion(values[0], values[1], values[2], values[3]);
|
||||
return temp.ReverseZ().ToArray();
|
||||
});
|
||||
case glTFAnimationTarget.AnimationPropertys.Scale:
|
||||
return new AnimationKeyframeData(elementCount, null);
|
||||
case glTFAnimationTarget.AnimationPropertys.BlendShape:
|
||||
return new AnimationKeyframeData(elementCount, null);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
class AnimationCurveData
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
public AnimationUtility.TangentMode TangentMode { get; private set; }
|
||||
public glTFAnimationTarget.AnimationPropertys AnimationProperty { get; private set; }
|
||||
public int SamplerIndex { get; private set; }
|
||||
public int ElementCount { get; private set; }
|
||||
public readonly List<AnimationKeyframeData> Keyframes = new List<AnimationKeyframeData>();
|
||||
|
||||
public AnimationCurveData(AnimationUtility.TangentMode tangentMode, glTFAnimationTarget.AnimationPropertys property, int samplerIndex, int elementCount)
|
||||
{
|
||||
TangentMode = tangentMode;
|
||||
AnimationProperty = property;
|
||||
SamplerIndex = samplerIndex;
|
||||
ElementCount = elementCount;
|
||||
}
|
||||
|
||||
public string GetInterpolation()
|
||||
{
|
||||
switch (TangentMode)
|
||||
{
|
||||
case AnimationUtility.TangentMode.Linear:
|
||||
return glTFAnimationTarget.Interpolations.LINEAR.ToString();
|
||||
case AnimationUtility.TangentMode.Constant:
|
||||
return glTFAnimationTarget.Interpolations.STEP.ToString();
|
||||
default:
|
||||
return glTFAnimationTarget.Interpolations.LINEAR.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// キーフレームのデータを入力する
|
||||
/// </summary>
|
||||
/// <param name="time"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="valueOffset"></param>
|
||||
public void SetKeyframeData(float time, float value, int valueOffset)
|
||||
{
|
||||
var existKeyframe = Keyframes.FirstOrDefault(x => x.Time == time);
|
||||
if (existKeyframe != null)
|
||||
{
|
||||
existKeyframe.SetValue(value, valueOffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
var newKeyframe = GetKeyframeData(AnimationProperty, ElementCount);
|
||||
newKeyframe.Time = time;
|
||||
newKeyframe.SetValue(value, valueOffset);
|
||||
Keyframes.Add(newKeyframe);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// キー情報がなかった要素に対して直前のキーの値を入力する
|
||||
/// </summary>
|
||||
public void RecountEmptyKeyframe()
|
||||
{
|
||||
if (Keyframes.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Keyframes.Sort((x, y) => (x.Time < y.Time) ? -1 : 1);
|
||||
|
||||
for (int i = 1; i < Keyframes.Count; i++)
|
||||
{
|
||||
var current = Keyframes[i];
|
||||
var last = Keyframes[i - 1];
|
||||
for (int j = 0; j < current.EnterValues.Length; j++)
|
||||
{
|
||||
if (!current.EnterValues[j])
|
||||
{
|
||||
Keyframes[i].SetValue(last.Values[j], j);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// アニメーションプロパティに対応したキーフレームを挿入する
|
||||
/// </summary>
|
||||
/// <param name="property"></param>
|
||||
/// <returns></returns>
|
||||
private static AnimationKeyframeData GetKeyframeData(glTFAnimationTarget.AnimationPropertys property, int elementCount)
|
||||
{
|
||||
switch (property)
|
||||
{
|
||||
case glTFAnimationTarget.AnimationPropertys.Translation:
|
||||
return new AnimationKeyframeData(elementCount, (values) =>
|
||||
{
|
||||
var temp = new Vector3(values[0], values[1], values[2]);
|
||||
return temp.ReverseZ().ToArray();
|
||||
});
|
||||
case glTFAnimationTarget.AnimationPropertys.Rotation:
|
||||
return new AnimationKeyframeData(elementCount, (values) =>
|
||||
{
|
||||
var temp = new Quaternion(values[0], values[1], values[2], values[3]);
|
||||
return temp.ReverseZ().ToArray();
|
||||
});
|
||||
case glTFAnimationTarget.AnimationPropertys.Scale:
|
||||
return new AnimationKeyframeData(elementCount, null);
|
||||
case glTFAnimationTarget.AnimationPropertys.BlendShape:
|
||||
return new AnimationKeyframeData(elementCount, null);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1af21722605d44f58deebfcfca642b32
|
||||
fileFormatVersion: 2
|
||||
guid: 1af21722605d44f58deebfcfca642b32
|
||||
timeCreated: 1537442711
|
||||
|
|
@ -1,222 +1,222 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
|
||||
public static class AnimationExporter
|
||||
{
|
||||
public class InputOutputValues
|
||||
{
|
||||
public float[] Input;
|
||||
public float[] Output;
|
||||
}
|
||||
|
||||
public class AnimationWithSampleCurves
|
||||
{
|
||||
public glTFAnimation Animation;
|
||||
public Dictionary<int, InputOutputValues> SamplerMap = new Dictionary<int, InputOutputValues>();
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public static List<AnimationClip> GetAnimationClips(Animation animation)
|
||||
{
|
||||
var clips = new List<AnimationClip>();
|
||||
foreach (AnimationState state in animation)
|
||||
{
|
||||
clips.Add(state.clip);
|
||||
}
|
||||
return clips;
|
||||
}
|
||||
|
||||
public static List<AnimationClip> GetAnimationClips(Animator animator)
|
||||
{
|
||||
var clips = new List<AnimationClip>();
|
||||
|
||||
RuntimeAnimatorController runtimeAnimatorController = animator.runtimeAnimatorController;
|
||||
UnityEditor.Animations.AnimatorController animationController = runtimeAnimatorController as UnityEditor.Animations.AnimatorController;
|
||||
|
||||
if (animationController == null)
|
||||
{
|
||||
return clips;
|
||||
}
|
||||
|
||||
foreach (var layer in animationController.layers)
|
||||
{
|
||||
foreach (var state in layer.stateMachine.states)
|
||||
{
|
||||
clips.Add(state.state.motion as AnimationClip);
|
||||
}
|
||||
}
|
||||
return clips;
|
||||
}
|
||||
|
||||
static int GetNodeIndex(Transform root, List<Transform> nodes, string path)
|
||||
{
|
||||
var descendant = root.GetFromPath(path);
|
||||
return nodes.IndexOf(descendant);
|
||||
}
|
||||
|
||||
public static glTFAnimationTarget.AnimationPropertys PropertyToTarget(string property)
|
||||
{
|
||||
if (property.StartsWith("m_LocalPosition."))
|
||||
{
|
||||
return glTFAnimationTarget.AnimationPropertys.Translation;
|
||||
}
|
||||
else if (property.StartsWith("localEulerAnglesRaw."))
|
||||
{
|
||||
return glTFAnimationTarget.AnimationPropertys.EulerRotation;
|
||||
}
|
||||
else if (property.StartsWith("m_LocalRotation."))
|
||||
{
|
||||
return glTFAnimationTarget.AnimationPropertys.Rotation;
|
||||
}
|
||||
else if (property.StartsWith("m_LocalScale."))
|
||||
{
|
||||
return glTFAnimationTarget.AnimationPropertys.Scale;
|
||||
}
|
||||
else if (property.StartsWith("blendShape."))
|
||||
{
|
||||
return glTFAnimationTarget.AnimationPropertys.BlendShape;
|
||||
}
|
||||
else
|
||||
{
|
||||
return glTFAnimationTarget.AnimationPropertys.NotImplemented;
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetElementOffset(string property)
|
||||
{
|
||||
if (property.EndsWith(".x"))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (property.EndsWith(".y") || property.StartsWith("blendShape."))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if (property.EndsWith(".z"))
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
if (property.EndsWith(".w"))
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public static AnimationWithSampleCurves Export(AnimationClip clip, Transform root, List<Transform> nodes)
|
||||
{
|
||||
var animation = new AnimationWithSampleCurves
|
||||
{
|
||||
Animation = new glTFAnimation(),
|
||||
};
|
||||
|
||||
#if UNITY_5_6_OR_NEWER
|
||||
List<AnimationCurveData> curveDatas = new List<AnimationCurveData>();
|
||||
|
||||
foreach (var binding in AnimationUtility.GetCurveBindings(clip))
|
||||
{
|
||||
var curve = AnimationUtility.GetEditorCurve(clip, binding);
|
||||
|
||||
var property = AnimationExporter.PropertyToTarget(binding.propertyName);
|
||||
if (property == glTFAnimationTarget.AnimationPropertys.NotImplemented)
|
||||
{
|
||||
Debug.LogWarning("Not Implemented keyframe property : " + binding.propertyName);
|
||||
continue;
|
||||
}
|
||||
if (property == glTFAnimationTarget.AnimationPropertys.EulerRotation)
|
||||
{
|
||||
Debug.LogWarning("Interpolation setting of AnimationClip should be Quaternion");
|
||||
continue;
|
||||
}
|
||||
|
||||
var nodeIndex = GetNodeIndex(root, nodes, binding.path);
|
||||
var samplerIndex = animation.Animation.AddChannelAndGetSampler(nodeIndex, property);
|
||||
var elementCount = 0;
|
||||
if (property == glTFAnimationTarget.AnimationPropertys.BlendShape)
|
||||
{
|
||||
var mesh = nodes[nodeIndex].GetComponent<SkinnedMeshRenderer>().sharedMesh;
|
||||
elementCount = mesh.blendShapeCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
elementCount = glTFAnimationTarget.GetElementCount(property);
|
||||
}
|
||||
|
||||
// 同一のsamplerIndexが割り当てられているcurveDataがある場合はそれを使用し、無ければ作る
|
||||
var curveData = curveDatas.FirstOrDefault(x => x.SamplerIndex == samplerIndex);
|
||||
if (curveData == null)
|
||||
{
|
||||
curveData = new AnimationCurveData(AnimationUtility.GetKeyRightTangentMode(curve, 0), property, samplerIndex, elementCount);
|
||||
curveDatas.Add(curveData);
|
||||
}
|
||||
|
||||
// 全てのキーフレームを回収
|
||||
int elementOffset = 0;
|
||||
float valueFactor = 1.0f;
|
||||
if (property == glTFAnimationTarget.AnimationPropertys.BlendShape)
|
||||
{
|
||||
var mesh = nodes[nodeIndex].GetComponent<SkinnedMeshRenderer>().sharedMesh;
|
||||
var blendShapeName = binding.propertyName.Replace("blendShape.", "");
|
||||
elementOffset = mesh.GetBlendShapeIndex(blendShapeName);
|
||||
valueFactor = 0.01f;
|
||||
}
|
||||
else
|
||||
{
|
||||
elementOffset = AnimationExporter.GetElementOffset(binding.propertyName);
|
||||
}
|
||||
|
||||
if (elementOffset >= 0 && elementOffset < elementCount)
|
||||
{
|
||||
for (int i = 0; i < curve.keys.Length; i++)
|
||||
{
|
||||
curveData.SetKeyframeData(curve.keys[i].time, curve.keys[i].value * valueFactor, elementOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//キー挿入
|
||||
foreach (var curve in curveDatas)
|
||||
{
|
||||
if (curve.Keyframes.Count == 0)
|
||||
continue;
|
||||
|
||||
curve.RecountEmptyKeyframe();
|
||||
|
||||
var elementNum = curve.Keyframes.First().Values.Length;
|
||||
var values = default(InputOutputValues);
|
||||
if (!animation.SamplerMap.TryGetValue(curve.SamplerIndex, out values))
|
||||
{
|
||||
values = new InputOutputValues();
|
||||
values.Input = new float[curve.Keyframes.Count];
|
||||
values.Output = new float[curve.Keyframes.Count * elementNum];
|
||||
animation.SamplerMap[curve.SamplerIndex] = values;
|
||||
animation.Animation.samplers[curve.SamplerIndex].interpolation = curve.GetInterpolation();
|
||||
}
|
||||
|
||||
int keyframeIndex = 0;
|
||||
foreach (var keyframe in curve.Keyframes)
|
||||
{
|
||||
values.Input[keyframeIndex] = keyframe.Time;
|
||||
Buffer.BlockCopy(keyframe.GetRightHandCoordinate(), 0, values.Output, keyframeIndex * elementNum * sizeof(float), elementNum * sizeof(float));
|
||||
keyframeIndex++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return animation;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
|
||||
public static class AnimationExporter
|
||||
{
|
||||
public class InputOutputValues
|
||||
{
|
||||
public float[] Input;
|
||||
public float[] Output;
|
||||
}
|
||||
|
||||
public class AnimationWithSampleCurves
|
||||
{
|
||||
public glTFAnimation Animation;
|
||||
public Dictionary<int, InputOutputValues> SamplerMap = new Dictionary<int, InputOutputValues>();
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public static List<AnimationClip> GetAnimationClips(Animation animation)
|
||||
{
|
||||
var clips = new List<AnimationClip>();
|
||||
foreach (AnimationState state in animation)
|
||||
{
|
||||
clips.Add(state.clip);
|
||||
}
|
||||
return clips;
|
||||
}
|
||||
|
||||
public static List<AnimationClip> GetAnimationClips(Animator animator)
|
||||
{
|
||||
var clips = new List<AnimationClip>();
|
||||
|
||||
RuntimeAnimatorController runtimeAnimatorController = animator.runtimeAnimatorController;
|
||||
UnityEditor.Animations.AnimatorController animationController = runtimeAnimatorController as UnityEditor.Animations.AnimatorController;
|
||||
|
||||
if (animationController == null)
|
||||
{
|
||||
return clips;
|
||||
}
|
||||
|
||||
foreach (var layer in animationController.layers)
|
||||
{
|
||||
foreach (var state in layer.stateMachine.states)
|
||||
{
|
||||
clips.Add(state.state.motion as AnimationClip);
|
||||
}
|
||||
}
|
||||
return clips;
|
||||
}
|
||||
|
||||
static int GetNodeIndex(Transform root, List<Transform> nodes, string path)
|
||||
{
|
||||
var descendant = root.GetFromPath(path);
|
||||
return nodes.IndexOf(descendant);
|
||||
}
|
||||
|
||||
public static glTFAnimationTarget.AnimationPropertys PropertyToTarget(string property)
|
||||
{
|
||||
if (property.StartsWith("m_LocalPosition."))
|
||||
{
|
||||
return glTFAnimationTarget.AnimationPropertys.Translation;
|
||||
}
|
||||
else if (property.StartsWith("localEulerAnglesRaw."))
|
||||
{
|
||||
return glTFAnimationTarget.AnimationPropertys.EulerRotation;
|
||||
}
|
||||
else if (property.StartsWith("m_LocalRotation."))
|
||||
{
|
||||
return glTFAnimationTarget.AnimationPropertys.Rotation;
|
||||
}
|
||||
else if (property.StartsWith("m_LocalScale."))
|
||||
{
|
||||
return glTFAnimationTarget.AnimationPropertys.Scale;
|
||||
}
|
||||
else if (property.StartsWith("blendShape."))
|
||||
{
|
||||
return glTFAnimationTarget.AnimationPropertys.BlendShape;
|
||||
}
|
||||
else
|
||||
{
|
||||
return glTFAnimationTarget.AnimationPropertys.NotImplemented;
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetElementOffset(string property)
|
||||
{
|
||||
if (property.EndsWith(".x"))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (property.EndsWith(".y") || property.StartsWith("blendShape."))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if (property.EndsWith(".z"))
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
if (property.EndsWith(".w"))
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public static AnimationWithSampleCurves Export(AnimationClip clip, Transform root, List<Transform> nodes)
|
||||
{
|
||||
var animation = new AnimationWithSampleCurves
|
||||
{
|
||||
Animation = new glTFAnimation(),
|
||||
};
|
||||
|
||||
#if UNITY_5_6_OR_NEWER
|
||||
List<AnimationCurveData> curveDatas = new List<AnimationCurveData>();
|
||||
|
||||
foreach (var binding in AnimationUtility.GetCurveBindings(clip))
|
||||
{
|
||||
var curve = AnimationUtility.GetEditorCurve(clip, binding);
|
||||
|
||||
var property = AnimationExporter.PropertyToTarget(binding.propertyName);
|
||||
if (property == glTFAnimationTarget.AnimationPropertys.NotImplemented)
|
||||
{
|
||||
Debug.LogWarning("Not Implemented keyframe property : " + binding.propertyName);
|
||||
continue;
|
||||
}
|
||||
if (property == glTFAnimationTarget.AnimationPropertys.EulerRotation)
|
||||
{
|
||||
Debug.LogWarning("Interpolation setting of AnimationClip should be Quaternion");
|
||||
continue;
|
||||
}
|
||||
|
||||
var nodeIndex = GetNodeIndex(root, nodes, binding.path);
|
||||
var samplerIndex = animation.Animation.AddChannelAndGetSampler(nodeIndex, property);
|
||||
var elementCount = 0;
|
||||
if (property == glTFAnimationTarget.AnimationPropertys.BlendShape)
|
||||
{
|
||||
var mesh = nodes[nodeIndex].GetComponent<SkinnedMeshRenderer>().sharedMesh;
|
||||
elementCount = mesh.blendShapeCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
elementCount = glTFAnimationTarget.GetElementCount(property);
|
||||
}
|
||||
|
||||
// 同一のsamplerIndexが割り当てられているcurveDataがある場合はそれを使用し、無ければ作る
|
||||
var curveData = curveDatas.FirstOrDefault(x => x.SamplerIndex == samplerIndex);
|
||||
if (curveData == null)
|
||||
{
|
||||
curveData = new AnimationCurveData(AnimationUtility.GetKeyRightTangentMode(curve, 0), property, samplerIndex, elementCount);
|
||||
curveDatas.Add(curveData);
|
||||
}
|
||||
|
||||
// 全てのキーフレームを回収
|
||||
int elementOffset = 0;
|
||||
float valueFactor = 1.0f;
|
||||
if (property == glTFAnimationTarget.AnimationPropertys.BlendShape)
|
||||
{
|
||||
var mesh = nodes[nodeIndex].GetComponent<SkinnedMeshRenderer>().sharedMesh;
|
||||
var blendShapeName = binding.propertyName.Replace("blendShape.", "");
|
||||
elementOffset = mesh.GetBlendShapeIndex(blendShapeName);
|
||||
valueFactor = 0.01f;
|
||||
}
|
||||
else
|
||||
{
|
||||
elementOffset = AnimationExporter.GetElementOffset(binding.propertyName);
|
||||
}
|
||||
|
||||
if (elementOffset >= 0 && elementOffset < elementCount)
|
||||
{
|
||||
for (int i = 0; i < curve.keys.Length; i++)
|
||||
{
|
||||
curveData.SetKeyframeData(curve.keys[i].time, curve.keys[i].value * valueFactor, elementOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//キー挿入
|
||||
foreach (var curve in curveDatas)
|
||||
{
|
||||
if (curve.Keyframes.Count == 0)
|
||||
continue;
|
||||
|
||||
curve.RecountEmptyKeyframe();
|
||||
|
||||
var elementNum = curve.Keyframes.First().Values.Length;
|
||||
var values = default(InputOutputValues);
|
||||
if (!animation.SamplerMap.TryGetValue(curve.SamplerIndex, out values))
|
||||
{
|
||||
values = new InputOutputValues();
|
||||
values.Input = new float[curve.Keyframes.Count];
|
||||
values.Output = new float[curve.Keyframes.Count * elementNum];
|
||||
animation.SamplerMap[curve.SamplerIndex] = values;
|
||||
animation.Animation.samplers[curve.SamplerIndex].interpolation = curve.GetInterpolation();
|
||||
}
|
||||
|
||||
int keyframeIndex = 0;
|
||||
foreach (var keyframe in curve.Keyframes)
|
||||
{
|
||||
values.Input[keyframeIndex] = keyframe.Time;
|
||||
Buffer.BlockCopy(keyframe.GetRightHandCoordinate(), 0, values.Output, keyframeIndex * elementNum * sizeof(float), elementNum * sizeof(float));
|
||||
keyframeIndex++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return animation;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 015ae41bf6cb4428b8257ead79772908
|
||||
fileFormatVersion: 2
|
||||
guid: 015ae41bf6cb4428b8257ead79772908
|
||||
timeCreated: 1537443293
|
||||
|
|
@ -1,330 +1,330 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public static class AnimationImporter
|
||||
{
|
||||
private enum TangentMode
|
||||
{
|
||||
Linear,
|
||||
Constant,
|
||||
Cubicspline
|
||||
}
|
||||
|
||||
private static TangentMode GetTangentMode(string interpolation)
|
||||
{
|
||||
if (interpolation == glTFAnimationTarget.Interpolations.LINEAR.ToString())
|
||||
{
|
||||
return TangentMode.Linear;
|
||||
}
|
||||
else if (interpolation == glTFAnimationTarget.Interpolations.STEP.ToString())
|
||||
{
|
||||
return TangentMode.Constant;
|
||||
}
|
||||
else if (interpolation == glTFAnimationTarget.Interpolations.CUBICSPLINE.ToString())
|
||||
{
|
||||
return TangentMode.Cubicspline;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
private static void CalculateTanget(List<Keyframe> keyframes, int current)
|
||||
{
|
||||
int back = current - 1;
|
||||
if (back < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (current < keyframes.Count)
|
||||
{
|
||||
var rightTangent = (keyframes[current].value - keyframes[back].value) / (keyframes[current].time - keyframes[back].time);
|
||||
keyframes[back] = new Keyframe(keyframes[back].time, keyframes[back].value, keyframes[back].inTangent, rightTangent);
|
||||
|
||||
var leftTangent = (keyframes[back].value - keyframes[current].value) / (keyframes[back].time - keyframes[current].time);
|
||||
keyframes[current] = new Keyframe(keyframes[current].time, keyframes[current].value, leftTangent, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public static Quaternion GetShortest(Quaternion last, Quaternion rot)
|
||||
{
|
||||
if (Quaternion.Dot(last, rot) > 0.0)
|
||||
{
|
||||
return rot;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Quaternion(-rot.x, -rot.y, -rot.z, -rot.w);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public delegate float[] ReverseZ(float[] current, float[] last);
|
||||
public static void SetAnimationCurve(
|
||||
AnimationClip targetClip,
|
||||
string relativePath,
|
||||
string[] propertyNames,
|
||||
float[] input,
|
||||
float[] output,
|
||||
string interpolation,
|
||||
Type curveType,
|
||||
ReverseZ reverse)
|
||||
{
|
||||
var tangentMode = GetTangentMode(interpolation);
|
||||
|
||||
var curveCount = propertyNames.Length;
|
||||
AnimationCurve[] curves = new AnimationCurve[curveCount];
|
||||
List<Keyframe>[] keyframes = new List<Keyframe>[curveCount];
|
||||
|
||||
int elementNum = curveCount;
|
||||
int inputIndex = 0;
|
||||
//Quaternion用
|
||||
float[] last = new float[curveCount];
|
||||
if (last.Length == 4)
|
||||
{
|
||||
last[3] = 1.0f;
|
||||
}
|
||||
for (inputIndex = 0; inputIndex < input.Length; ++inputIndex)
|
||||
{
|
||||
var time = input[inputIndex];
|
||||
var outputIndex = 0;
|
||||
if (tangentMode == TangentMode.Cubicspline)
|
||||
{
|
||||
outputIndex = inputIndex * elementNum * 3;
|
||||
var value = new float[curveCount];
|
||||
for (int i = 0; i < value.Length; i++)
|
||||
{
|
||||
value[i] = output[outputIndex + elementNum + i];
|
||||
}
|
||||
var reversed = reverse(value, last);
|
||||
last = reversed;
|
||||
for (int i = 0; i < keyframes.Length; i++)
|
||||
{
|
||||
if (keyframes[i] == null)
|
||||
keyframes[i] = new List<Keyframe>();
|
||||
keyframes[i].Add(new Keyframe(
|
||||
time,
|
||||
reversed[i],
|
||||
output[outputIndex + i],
|
||||
output[outputIndex + i + elementNum * 2]));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
outputIndex = inputIndex * elementNum;
|
||||
var value = new float[curveCount];
|
||||
for (int i = 0; i < value.Length; i++)
|
||||
{
|
||||
value[i] = output[outputIndex + i];
|
||||
}
|
||||
var reversed = reverse(value, last);
|
||||
last = reversed;
|
||||
|
||||
for (int i = 0; i < keyframes.Length; i++)
|
||||
{
|
||||
if (keyframes[i] == null)
|
||||
keyframes[i] = new List<Keyframe>();
|
||||
if (tangentMode == TangentMode.Linear)
|
||||
{
|
||||
keyframes[i].Add(new Keyframe(time, reversed[i], 0, 0));
|
||||
if (keyframes[i].Count > 0)
|
||||
{
|
||||
CalculateTanget(keyframes[i], keyframes[i].Count - 1);
|
||||
}
|
||||
}
|
||||
else if (tangentMode == TangentMode.Constant)
|
||||
keyframes[i].Add(new Keyframe(time, reversed[i], 0, float.PositiveInfinity));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < curves.Length; i++)
|
||||
{
|
||||
curves[i] = new AnimationCurve();
|
||||
for (int j = 0; j < keyframes[i].Count; j++)
|
||||
{
|
||||
curves[i].AddKey(keyframes[i][j]);
|
||||
}
|
||||
|
||||
targetClip.SetCurve(relativePath, curveType, propertyNames[i], curves[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public static List<AnimationClip> ImportAnimationClip(ImporterContext ctx)
|
||||
{
|
||||
List<AnimationClip> animasionClips = new List<AnimationClip>();
|
||||
for (int i = 0; i < ctx.GLTF.animations.Count; ++i)
|
||||
{
|
||||
var clip = new AnimationClip();
|
||||
clip.ClearCurves();
|
||||
clip.legacy = true;
|
||||
clip.name = ctx.GLTF.animations[i].name;
|
||||
if (string.IsNullOrEmpty(clip.name))
|
||||
{
|
||||
clip.name = "legacy_" + i;
|
||||
}
|
||||
clip.wrapMode = WrapMode.Loop;
|
||||
|
||||
var animation = ctx.GLTF.animations[i];
|
||||
if (string.IsNullOrEmpty(animation.name))
|
||||
{
|
||||
animation.name = string.Format("animation:{0}", i);
|
||||
}
|
||||
|
||||
foreach (var channel in animation.channels)
|
||||
{
|
||||
var targetTransform = ctx.Nodes[channel.target.node];
|
||||
var relativePath = targetTransform.RelativePathFrom(ctx.Root.transform);
|
||||
switch (channel.target.path)
|
||||
{
|
||||
case glTFAnimationTarget.PATH_TRANSLATION:
|
||||
{
|
||||
var sampler = animation.samplers[channel.sampler];
|
||||
var input = ctx.GLTF.GetArrayFromAccessor<float>(sampler.input);
|
||||
var output = ctx.GLTF.GetArrayFromAccessorAsFloat(sampler.output);
|
||||
|
||||
AnimationImporter.SetAnimationCurve(
|
||||
clip,
|
||||
relativePath,
|
||||
new string[] { "localPosition.x", "localPosition.y", "localPosition.z" },
|
||||
input,
|
||||
output,
|
||||
sampler.interpolation,
|
||||
typeof(Transform),
|
||||
(values, last) =>
|
||||
{
|
||||
Vector3 temp = new Vector3(values[0], values[1], values[2]);
|
||||
return temp.ReverseZ().ToArray();
|
||||
}
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case glTFAnimationTarget.PATH_ROTATION:
|
||||
{
|
||||
var sampler = animation.samplers[channel.sampler];
|
||||
var input = ctx.GLTF.GetArrayFromAccessor<float>(sampler.input);
|
||||
var output = ctx.GLTF.GetArrayFromAccessorAsFloat(sampler.output);
|
||||
|
||||
AnimationImporter.SetAnimationCurve(
|
||||
clip,
|
||||
relativePath,
|
||||
new string[] { "localRotation.x", "localRotation.y", "localRotation.z", "localRotation.w" },
|
||||
input,
|
||||
output,
|
||||
sampler.interpolation,
|
||||
typeof(Transform),
|
||||
(values, last) =>
|
||||
{
|
||||
Quaternion currentQuaternion = new Quaternion(values[0], values[1], values[2], values[3]);
|
||||
Quaternion lastQuaternion = new Quaternion(last[0], last[1], last[2], last[3]);
|
||||
return AnimationImporter.GetShortest(lastQuaternion, currentQuaternion.ReverseZ()).ToArray();
|
||||
}
|
||||
);
|
||||
|
||||
clip.EnsureQuaternionContinuity();
|
||||
}
|
||||
break;
|
||||
|
||||
case glTFAnimationTarget.PATH_SCALE:
|
||||
{
|
||||
var sampler = animation.samplers[channel.sampler];
|
||||
var input = ctx.GLTF.GetArrayFromAccessor<float>(sampler.input);
|
||||
var output = ctx.GLTF.GetArrayFromAccessorAsFloat(sampler.output);
|
||||
|
||||
AnimationImporter.SetAnimationCurve(
|
||||
clip,
|
||||
relativePath,
|
||||
new string[] { "localScale.x", "localScale.y", "localScale.z" },
|
||||
input,
|
||||
output,
|
||||
sampler.interpolation,
|
||||
typeof(Transform),
|
||||
(values, last) => values);
|
||||
}
|
||||
break;
|
||||
|
||||
case glTFAnimationTarget.PATH_WEIGHT:
|
||||
{
|
||||
var node = ctx.GLTF.nodes[channel.target.node];
|
||||
var mesh = ctx.GLTF.meshes[node.mesh];
|
||||
//var primitive = mesh.primitives.FirstOrDefault();
|
||||
//var targets = primitive.targets;
|
||||
|
||||
List<string> blendShapeNames = new List<string>();
|
||||
var transform = ctx.Nodes[channel.target.node];
|
||||
var skinnedMeshRenderer = transform.GetComponent<SkinnedMeshRenderer>();
|
||||
if (skinnedMeshRenderer == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int j = 0; j < skinnedMeshRenderer.sharedMesh.blendShapeCount; j++)
|
||||
{
|
||||
blendShapeNames.Add(skinnedMeshRenderer.sharedMesh.GetBlendShapeName(j));
|
||||
}
|
||||
|
||||
var keyNames = blendShapeNames
|
||||
.Where(x => !string.IsNullOrEmpty(x))
|
||||
.Select(x => "blendShape." + x)
|
||||
.ToArray();
|
||||
|
||||
var sampler = animation.samplers[channel.sampler];
|
||||
var input = ctx.GLTF.GetArrayFromAccessor<float>(sampler.input);
|
||||
var output = ctx.GLTF.GetArrayFromAccessor<float>(sampler.output);
|
||||
AnimationImporter.SetAnimationCurve(
|
||||
clip,
|
||||
relativePath,
|
||||
keyNames,
|
||||
input,
|
||||
output,
|
||||
sampler.interpolation,
|
||||
typeof(SkinnedMeshRenderer),
|
||||
(values, last) =>
|
||||
{
|
||||
for (int j = 0; j < values.Length; j++)
|
||||
{
|
||||
values[j] *= 100.0f;
|
||||
}
|
||||
return values;
|
||||
});
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
Debug.LogWarningFormat("unknown path: {0}", channel.target.path);
|
||||
break;
|
||||
}
|
||||
}
|
||||
animasionClips.Add(clip);
|
||||
}
|
||||
|
||||
return animasionClips;
|
||||
}
|
||||
|
||||
public static void ImportAnimation(ImporterContext ctx)
|
||||
{
|
||||
// animation
|
||||
if (ctx.GLTF.animations != null && ctx.GLTF.animations.Any())
|
||||
{
|
||||
var animation = ctx.Root.AddComponent<Animation>();
|
||||
ctx.AnimationClips = ImportAnimationClip(ctx);
|
||||
foreach (var clip in ctx.AnimationClips)
|
||||
{
|
||||
animation.AddClip(clip, clip.name);
|
||||
}
|
||||
if (ctx.AnimationClips.Count > 0)
|
||||
{
|
||||
animation.clip = ctx.AnimationClips.First();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public static class AnimationImporter
|
||||
{
|
||||
private enum TangentMode
|
||||
{
|
||||
Linear,
|
||||
Constant,
|
||||
Cubicspline
|
||||
}
|
||||
|
||||
private static TangentMode GetTangentMode(string interpolation)
|
||||
{
|
||||
if (interpolation == glTFAnimationTarget.Interpolations.LINEAR.ToString())
|
||||
{
|
||||
return TangentMode.Linear;
|
||||
}
|
||||
else if (interpolation == glTFAnimationTarget.Interpolations.STEP.ToString())
|
||||
{
|
||||
return TangentMode.Constant;
|
||||
}
|
||||
else if (interpolation == glTFAnimationTarget.Interpolations.CUBICSPLINE.ToString())
|
||||
{
|
||||
return TangentMode.Cubicspline;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
private static void CalculateTanget(List<Keyframe> keyframes, int current)
|
||||
{
|
||||
int back = current - 1;
|
||||
if (back < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (current < keyframes.Count)
|
||||
{
|
||||
var rightTangent = (keyframes[current].value - keyframes[back].value) / (keyframes[current].time - keyframes[back].time);
|
||||
keyframes[back] = new Keyframe(keyframes[back].time, keyframes[back].value, keyframes[back].inTangent, rightTangent);
|
||||
|
||||
var leftTangent = (keyframes[back].value - keyframes[current].value) / (keyframes[back].time - keyframes[current].time);
|
||||
keyframes[current] = new Keyframe(keyframes[current].time, keyframes[current].value, leftTangent, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public static Quaternion GetShortest(Quaternion last, Quaternion rot)
|
||||
{
|
||||
if (Quaternion.Dot(last, rot) > 0.0)
|
||||
{
|
||||
return rot;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Quaternion(-rot.x, -rot.y, -rot.z, -rot.w);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public delegate float[] ReverseZ(float[] current, float[] last);
|
||||
public static void SetAnimationCurve(
|
||||
AnimationClip targetClip,
|
||||
string relativePath,
|
||||
string[] propertyNames,
|
||||
float[] input,
|
||||
float[] output,
|
||||
string interpolation,
|
||||
Type curveType,
|
||||
ReverseZ reverse)
|
||||
{
|
||||
var tangentMode = GetTangentMode(interpolation);
|
||||
|
||||
var curveCount = propertyNames.Length;
|
||||
AnimationCurve[] curves = new AnimationCurve[curveCount];
|
||||
List<Keyframe>[] keyframes = new List<Keyframe>[curveCount];
|
||||
|
||||
int elementNum = curveCount;
|
||||
int inputIndex = 0;
|
||||
//Quaternion用
|
||||
float[] last = new float[curveCount];
|
||||
if (last.Length == 4)
|
||||
{
|
||||
last[3] = 1.0f;
|
||||
}
|
||||
for (inputIndex = 0; inputIndex < input.Length; ++inputIndex)
|
||||
{
|
||||
var time = input[inputIndex];
|
||||
var outputIndex = 0;
|
||||
if (tangentMode == TangentMode.Cubicspline)
|
||||
{
|
||||
outputIndex = inputIndex * elementNum * 3;
|
||||
var value = new float[curveCount];
|
||||
for (int i = 0; i < value.Length; i++)
|
||||
{
|
||||
value[i] = output[outputIndex + elementNum + i];
|
||||
}
|
||||
var reversed = reverse(value, last);
|
||||
last = reversed;
|
||||
for (int i = 0; i < keyframes.Length; i++)
|
||||
{
|
||||
if (keyframes[i] == null)
|
||||
keyframes[i] = new List<Keyframe>();
|
||||
keyframes[i].Add(new Keyframe(
|
||||
time,
|
||||
reversed[i],
|
||||
output[outputIndex + i],
|
||||
output[outputIndex + i + elementNum * 2]));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
outputIndex = inputIndex * elementNum;
|
||||
var value = new float[curveCount];
|
||||
for (int i = 0; i < value.Length; i++)
|
||||
{
|
||||
value[i] = output[outputIndex + i];
|
||||
}
|
||||
var reversed = reverse(value, last);
|
||||
last = reversed;
|
||||
|
||||
for (int i = 0; i < keyframes.Length; i++)
|
||||
{
|
||||
if (keyframes[i] == null)
|
||||
keyframes[i] = new List<Keyframe>();
|
||||
if (tangentMode == TangentMode.Linear)
|
||||
{
|
||||
keyframes[i].Add(new Keyframe(time, reversed[i], 0, 0));
|
||||
if (keyframes[i].Count > 0)
|
||||
{
|
||||
CalculateTanget(keyframes[i], keyframes[i].Count - 1);
|
||||
}
|
||||
}
|
||||
else if (tangentMode == TangentMode.Constant)
|
||||
keyframes[i].Add(new Keyframe(time, reversed[i], 0, float.PositiveInfinity));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < curves.Length; i++)
|
||||
{
|
||||
curves[i] = new AnimationCurve();
|
||||
for (int j = 0; j < keyframes[i].Count; j++)
|
||||
{
|
||||
curves[i].AddKey(keyframes[i][j]);
|
||||
}
|
||||
|
||||
targetClip.SetCurve(relativePath, curveType, propertyNames[i], curves[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public static List<AnimationClip> ImportAnimationClip(ImporterContext ctx)
|
||||
{
|
||||
List<AnimationClip> animasionClips = new List<AnimationClip>();
|
||||
for (int i = 0; i < ctx.GLTF.animations.Count; ++i)
|
||||
{
|
||||
var clip = new AnimationClip();
|
||||
clip.ClearCurves();
|
||||
clip.legacy = true;
|
||||
clip.name = ctx.GLTF.animations[i].name;
|
||||
if (string.IsNullOrEmpty(clip.name))
|
||||
{
|
||||
clip.name = "legacy_" + i;
|
||||
}
|
||||
clip.wrapMode = WrapMode.Loop;
|
||||
|
||||
var animation = ctx.GLTF.animations[i];
|
||||
if (string.IsNullOrEmpty(animation.name))
|
||||
{
|
||||
animation.name = string.Format("animation:{0}", i);
|
||||
}
|
||||
|
||||
foreach (var channel in animation.channels)
|
||||
{
|
||||
var targetTransform = ctx.Nodes[channel.target.node];
|
||||
var relativePath = targetTransform.RelativePathFrom(ctx.Root.transform);
|
||||
switch (channel.target.path)
|
||||
{
|
||||
case glTFAnimationTarget.PATH_TRANSLATION:
|
||||
{
|
||||
var sampler = animation.samplers[channel.sampler];
|
||||
var input = ctx.GLTF.GetArrayFromAccessor<float>(sampler.input);
|
||||
var output = ctx.GLTF.GetArrayFromAccessorAsFloat(sampler.output);
|
||||
|
||||
AnimationImporter.SetAnimationCurve(
|
||||
clip,
|
||||
relativePath,
|
||||
new string[] { "localPosition.x", "localPosition.y", "localPosition.z" },
|
||||
input,
|
||||
output,
|
||||
sampler.interpolation,
|
||||
typeof(Transform),
|
||||
(values, last) =>
|
||||
{
|
||||
Vector3 temp = new Vector3(values[0], values[1], values[2]);
|
||||
return temp.ReverseZ().ToArray();
|
||||
}
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case glTFAnimationTarget.PATH_ROTATION:
|
||||
{
|
||||
var sampler = animation.samplers[channel.sampler];
|
||||
var input = ctx.GLTF.GetArrayFromAccessor<float>(sampler.input);
|
||||
var output = ctx.GLTF.GetArrayFromAccessorAsFloat(sampler.output);
|
||||
|
||||
AnimationImporter.SetAnimationCurve(
|
||||
clip,
|
||||
relativePath,
|
||||
new string[] { "localRotation.x", "localRotation.y", "localRotation.z", "localRotation.w" },
|
||||
input,
|
||||
output,
|
||||
sampler.interpolation,
|
||||
typeof(Transform),
|
||||
(values, last) =>
|
||||
{
|
||||
Quaternion currentQuaternion = new Quaternion(values[0], values[1], values[2], values[3]);
|
||||
Quaternion lastQuaternion = new Quaternion(last[0], last[1], last[2], last[3]);
|
||||
return AnimationImporter.GetShortest(lastQuaternion, currentQuaternion.ReverseZ()).ToArray();
|
||||
}
|
||||
);
|
||||
|
||||
clip.EnsureQuaternionContinuity();
|
||||
}
|
||||
break;
|
||||
|
||||
case glTFAnimationTarget.PATH_SCALE:
|
||||
{
|
||||
var sampler = animation.samplers[channel.sampler];
|
||||
var input = ctx.GLTF.GetArrayFromAccessor<float>(sampler.input);
|
||||
var output = ctx.GLTF.GetArrayFromAccessorAsFloat(sampler.output);
|
||||
|
||||
AnimationImporter.SetAnimationCurve(
|
||||
clip,
|
||||
relativePath,
|
||||
new string[] { "localScale.x", "localScale.y", "localScale.z" },
|
||||
input,
|
||||
output,
|
||||
sampler.interpolation,
|
||||
typeof(Transform),
|
||||
(values, last) => values);
|
||||
}
|
||||
break;
|
||||
|
||||
case glTFAnimationTarget.PATH_WEIGHT:
|
||||
{
|
||||
var node = ctx.GLTF.nodes[channel.target.node];
|
||||
var mesh = ctx.GLTF.meshes[node.mesh];
|
||||
//var primitive = mesh.primitives.FirstOrDefault();
|
||||
//var targets = primitive.targets;
|
||||
|
||||
List<string> blendShapeNames = new List<string>();
|
||||
var transform = ctx.Nodes[channel.target.node];
|
||||
var skinnedMeshRenderer = transform.GetComponent<SkinnedMeshRenderer>();
|
||||
if (skinnedMeshRenderer == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int j = 0; j < skinnedMeshRenderer.sharedMesh.blendShapeCount; j++)
|
||||
{
|
||||
blendShapeNames.Add(skinnedMeshRenderer.sharedMesh.GetBlendShapeName(j));
|
||||
}
|
||||
|
||||
var keyNames = blendShapeNames
|
||||
.Where(x => !string.IsNullOrEmpty(x))
|
||||
.Select(x => "blendShape." + x)
|
||||
.ToArray();
|
||||
|
||||
var sampler = animation.samplers[channel.sampler];
|
||||
var input = ctx.GLTF.GetArrayFromAccessor<float>(sampler.input);
|
||||
var output = ctx.GLTF.GetArrayFromAccessor<float>(sampler.output);
|
||||
AnimationImporter.SetAnimationCurve(
|
||||
clip,
|
||||
relativePath,
|
||||
keyNames,
|
||||
input,
|
||||
output,
|
||||
sampler.interpolation,
|
||||
typeof(SkinnedMeshRenderer),
|
||||
(values, last) =>
|
||||
{
|
||||
for (int j = 0; j < values.Length; j++)
|
||||
{
|
||||
values[j] *= 100.0f;
|
||||
}
|
||||
return values;
|
||||
});
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
Debug.LogWarningFormat("unknown path: {0}", channel.target.path);
|
||||
break;
|
||||
}
|
||||
}
|
||||
animasionClips.Add(clip);
|
||||
}
|
||||
|
||||
return animasionClips;
|
||||
}
|
||||
|
||||
public static void ImportAnimation(ImporterContext ctx)
|
||||
{
|
||||
// animation
|
||||
if (ctx.GLTF.animations != null && ctx.GLTF.animations.Any())
|
||||
{
|
||||
var animation = ctx.Root.AddComponent<Animation>();
|
||||
ctx.AnimationClips = ImportAnimationClip(ctx);
|
||||
foreach (var clip in ctx.AnimationClips)
|
||||
{
|
||||
animation.AddClip(clip, clip.name);
|
||||
}
|
||||
if (ctx.AnimationClips.Count > 0)
|
||||
{
|
||||
animation.clip = ctx.AnimationClips.First();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d602384685dd4f179350052013659720
|
||||
fileFormatVersion: 2
|
||||
guid: d602384685dd4f179350052013659720
|
||||
timeCreated: 1537445972
|
||||
|
|
@ -1,54 +1,54 @@
|
|||
namespace UniGLTF
|
||||
{
|
||||
class AnimationKeyframeData
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
public float Time { get; set; }
|
||||
public delegate float[] ConverterFunc(float[] values);
|
||||
private ConverterFunc _converter;
|
||||
private float[] _values;
|
||||
public float[] Values
|
||||
{
|
||||
get { return _values; }
|
||||
}
|
||||
|
||||
private bool[] _enterValues;
|
||||
public bool[] EnterValues
|
||||
{
|
||||
get { return _enterValues; }
|
||||
}
|
||||
|
||||
public AnimationKeyframeData(int elementCount, ConverterFunc converter)
|
||||
{
|
||||
_values = new float[elementCount];
|
||||
_enterValues = new bool[elementCount];
|
||||
for (int i = 0; i < _enterValues.Length; i++)
|
||||
{
|
||||
_enterValues[i] = false;
|
||||
}
|
||||
_converter = converter;
|
||||
}
|
||||
|
||||
public void SetValue(float src, int offset)
|
||||
{
|
||||
if (_values.Length > offset)
|
||||
{
|
||||
_values[offset] = src;
|
||||
_enterValues[offset] = true;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual float[] GetRightHandCoordinate()
|
||||
{
|
||||
if (_converter != null)
|
||||
{
|
||||
return _converter(_values);
|
||||
}
|
||||
else
|
||||
{
|
||||
return _values;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
namespace UniGLTF
|
||||
{
|
||||
class AnimationKeyframeData
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
public float Time { get; set; }
|
||||
public delegate float[] ConverterFunc(float[] values);
|
||||
private ConverterFunc _converter;
|
||||
private float[] _values;
|
||||
public float[] Values
|
||||
{
|
||||
get { return _values; }
|
||||
}
|
||||
|
||||
private bool[] _enterValues;
|
||||
public bool[] EnterValues
|
||||
{
|
||||
get { return _enterValues; }
|
||||
}
|
||||
|
||||
public AnimationKeyframeData(int elementCount, ConverterFunc converter)
|
||||
{
|
||||
_values = new float[elementCount];
|
||||
_enterValues = new bool[elementCount];
|
||||
for (int i = 0; i < _enterValues.Length; i++)
|
||||
{
|
||||
_enterValues[i] = false;
|
||||
}
|
||||
_converter = converter;
|
||||
}
|
||||
|
||||
public void SetValue(float src, int offset)
|
||||
{
|
||||
if (_values.Length > offset)
|
||||
{
|
||||
_values[offset] = src;
|
||||
_enterValues[offset] = true;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual float[] GetRightHandCoordinate()
|
||||
{
|
||||
if (_converter != null)
|
||||
{
|
||||
return _converter(_values);
|
||||
}
|
||||
else
|
||||
{
|
||||
return _values;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e27ef4fb768e49f591c2bb5eadd3b19b
|
||||
fileFormatVersion: 2
|
||||
guid: e27ef4fb768e49f591c2bb5eadd3b19b
|
||||
timeCreated: 1537442737
|
||||
|
|
@ -1,81 +1,81 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public class BytesReader
|
||||
{
|
||||
Byte[] m_bytes;
|
||||
int m_pos;
|
||||
|
||||
public BytesReader(Byte[] bytes, int pos=0)
|
||||
{
|
||||
m_bytes = bytes;
|
||||
m_pos = pos;
|
||||
}
|
||||
|
||||
public string ReadString(int count, Encoding encoding)
|
||||
{
|
||||
var s = encoding.GetString(m_bytes, m_pos, count);
|
||||
m_pos += count;
|
||||
return s;
|
||||
}
|
||||
|
||||
public float ReadSingle()
|
||||
{
|
||||
var n = BitConverter.ToSingle(m_bytes, m_pos);
|
||||
m_pos += 4;
|
||||
return n;
|
||||
}
|
||||
|
||||
public byte ReadUInt8()
|
||||
{
|
||||
return m_bytes[m_pos++];
|
||||
}
|
||||
|
||||
public UInt16 ReadUInt16()
|
||||
{
|
||||
var n = BitConverter.ToUInt16(m_bytes, m_pos);
|
||||
m_pos += 2;
|
||||
return n;
|
||||
}
|
||||
|
||||
public sbyte ReadInt8()
|
||||
{
|
||||
return (sbyte)m_bytes[m_pos++];
|
||||
}
|
||||
|
||||
public Int16 ReadInt16()
|
||||
{
|
||||
var n = BitConverter.ToInt16(m_bytes, m_pos);
|
||||
m_pos += 2;
|
||||
return n;
|
||||
}
|
||||
|
||||
public int ReadInt32()
|
||||
{
|
||||
var n = BitConverter.ToInt32(m_bytes, m_pos);
|
||||
m_pos += 4;
|
||||
return n;
|
||||
}
|
||||
|
||||
public void ReadToArray<T>(T[] dst) where T : struct
|
||||
{
|
||||
var size = new ArraySegment<Byte>(m_bytes, m_pos, m_bytes.Length - m_pos).MarshalCoyTo(dst);
|
||||
m_pos += size;
|
||||
}
|
||||
|
||||
public T ReadStruct<T>() where T : struct
|
||||
{
|
||||
var size = Marshal.SizeOf(typeof(T));
|
||||
using (var pin = Pin.Create(new ArraySegment<Byte>(m_bytes, m_pos, m_bytes.Length - m_pos)))
|
||||
{
|
||||
var s = (T)Marshal.PtrToStructure(pin.Ptr, typeof(T));
|
||||
m_pos += size;
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public class BytesReader
|
||||
{
|
||||
Byte[] m_bytes;
|
||||
int m_pos;
|
||||
|
||||
public BytesReader(Byte[] bytes, int pos=0)
|
||||
{
|
||||
m_bytes = bytes;
|
||||
m_pos = pos;
|
||||
}
|
||||
|
||||
public string ReadString(int count, Encoding encoding)
|
||||
{
|
||||
var s = encoding.GetString(m_bytes, m_pos, count);
|
||||
m_pos += count;
|
||||
return s;
|
||||
}
|
||||
|
||||
public float ReadSingle()
|
||||
{
|
||||
var n = BitConverter.ToSingle(m_bytes, m_pos);
|
||||
m_pos += 4;
|
||||
return n;
|
||||
}
|
||||
|
||||
public byte ReadUInt8()
|
||||
{
|
||||
return m_bytes[m_pos++];
|
||||
}
|
||||
|
||||
public UInt16 ReadUInt16()
|
||||
{
|
||||
var n = BitConverter.ToUInt16(m_bytes, m_pos);
|
||||
m_pos += 2;
|
||||
return n;
|
||||
}
|
||||
|
||||
public sbyte ReadInt8()
|
||||
{
|
||||
return (sbyte)m_bytes[m_pos++];
|
||||
}
|
||||
|
||||
public Int16 ReadInt16()
|
||||
{
|
||||
var n = BitConverter.ToInt16(m_bytes, m_pos);
|
||||
m_pos += 2;
|
||||
return n;
|
||||
}
|
||||
|
||||
public int ReadInt32()
|
||||
{
|
||||
var n = BitConverter.ToInt32(m_bytes, m_pos);
|
||||
m_pos += 4;
|
||||
return n;
|
||||
}
|
||||
|
||||
public void ReadToArray<T>(T[] dst) where T : struct
|
||||
{
|
||||
var size = new ArraySegment<Byte>(m_bytes, m_pos, m_bytes.Length - m_pos).MarshalCoyTo(dst);
|
||||
m_pos += size;
|
||||
}
|
||||
|
||||
public T ReadStruct<T>() where T : struct
|
||||
{
|
||||
var size = Marshal.SizeOf(typeof(T));
|
||||
using (var pin = Pin.Create(new ArraySegment<Byte>(m_bytes, m_pos, m_bytes.Length - m_pos)))
|
||||
{
|
||||
var s = (T)Marshal.PtrToStructure(pin.Ptr, typeof(T));
|
||||
m_pos += size;
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,74 +1,74 @@
|
|||
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(ArraySegment<Byte> bytes)
|
||||
{
|
||||
m_bytes = bytes;
|
||||
}
|
||||
|
||||
public ArraySegment<byte> Get(string url)
|
||||
{
|
||||
return m_bytes;
|
||||
}
|
||||
|
||||
public string GetPath(string url)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public class FileSystemStorage : IStorage
|
||||
{
|
||||
string m_root;
|
||||
|
||||
public FileSystemStorage(string root)
|
||||
{
|
||||
m_root = Path.GetFullPath(root);
|
||||
}
|
||||
|
||||
public ArraySegment<byte> Get(string url)
|
||||
{
|
||||
var bytes =
|
||||
(url.StartsWith("data:"))
|
||||
? UriByteBuffer.ReadEmbeded(url)
|
||||
: File.ReadAllBytes(Path.Combine(m_root, url))
|
||||
;
|
||||
return new ArraySegment<byte>(bytes);
|
||||
}
|
||||
|
||||
public string GetPath(string url)
|
||||
{
|
||||
if (url.StartsWith("data:"))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Path.Combine(m_root, url).Replace("\\", "/");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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(ArraySegment<Byte> bytes)
|
||||
{
|
||||
m_bytes = bytes;
|
||||
}
|
||||
|
||||
public ArraySegment<byte> Get(string url)
|
||||
{
|
||||
return m_bytes;
|
||||
}
|
||||
|
||||
public string GetPath(string url)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public class FileSystemStorage : IStorage
|
||||
{
|
||||
string m_root;
|
||||
|
||||
public FileSystemStorage(string root)
|
||||
{
|
||||
m_root = Path.GetFullPath(root);
|
||||
}
|
||||
|
||||
public ArraySegment<byte> Get(string url)
|
||||
{
|
||||
var bytes =
|
||||
(url.StartsWith("data:"))
|
||||
? UriByteBuffer.ReadEmbeded(url)
|
||||
: File.ReadAllBytes(Path.Combine(m_root, url))
|
||||
;
|
||||
return new ArraySegment<byte>(bytes);
|
||||
}
|
||||
|
||||
public string GetPath(string url)
|
||||
{
|
||||
if (url.StartsWith("data:"))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Path.Combine(m_root, url).Replace("\\", "/");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,268 +1,268 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UniGLTF.UniUnlit;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public enum glTFBlendMode
|
||||
{
|
||||
OPAQUE,
|
||||
MASK,
|
||||
BLEND
|
||||
}
|
||||
|
||||
public interface IMaterialExporter
|
||||
{
|
||||
glTFMaterial ExportMaterial(Material m, TextureExportManager textureManager);
|
||||
}
|
||||
|
||||
public class MaterialExporter : IMaterialExporter
|
||||
{
|
||||
public virtual glTFMaterial ExportMaterial(Material m, TextureExportManager textureManager)
|
||||
{
|
||||
var material = CreateMaterial(m);
|
||||
|
||||
// common params
|
||||
material.name = m.name;
|
||||
Export_Color(m, textureManager, material);
|
||||
Export_Metallic(m, textureManager, material);
|
||||
Export_Normal(m, textureManager, material);
|
||||
Export_Occlusion(m, textureManager, material);
|
||||
Export_Emission(m, textureManager, material);
|
||||
|
||||
return material;
|
||||
}
|
||||
|
||||
static void Export_Color(Material m, TextureExportManager textureManager, glTFMaterial material)
|
||||
{
|
||||
if (m.HasProperty("_Color"))
|
||||
{
|
||||
material.pbrMetallicRoughness.baseColorFactor = m.color.ToArray();
|
||||
}
|
||||
|
||||
if (m.HasProperty("_MainTex"))
|
||||
{
|
||||
var index = textureManager.CopyAndGetIndex(m.GetTexture("_MainTex"), RenderTextureReadWrite.sRGB);
|
||||
if (index != -1)
|
||||
{
|
||||
material.pbrMetallicRoughness.baseColorTexture = new glTFMaterialBaseColorTextureInfo()
|
||||
{
|
||||
index = index,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void Export_Metallic(Material m, TextureExportManager textureManager, glTFMaterial material)
|
||||
{
|
||||
int index = -1;
|
||||
if (m.HasProperty("_MetallicGlossMap"))
|
||||
{
|
||||
index = textureManager.ConvertAndGetIndex(m.GetTexture("_MetallicGlossMap"), new MetallicRoughnessConverter());
|
||||
if (index != -1)
|
||||
{
|
||||
material.pbrMetallicRoughness.metallicRoughnessTexture = new glTFMaterialMetallicRoughnessTextureInfo()
|
||||
{
|
||||
index = index,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (index != -1 && m.HasProperty("_GlossMapScale"))
|
||||
{
|
||||
material.pbrMetallicRoughness.metallicFactor = 1.0f;
|
||||
material.pbrMetallicRoughness.roughnessFactor = 1.0f - m.GetFloat("_GlossMapScale");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m.HasProperty("_Metallic"))
|
||||
{
|
||||
material.pbrMetallicRoughness.metallicFactor = m.GetFloat("_Metallic");
|
||||
}
|
||||
if (m.HasProperty("_Glossiness"))
|
||||
{
|
||||
material.pbrMetallicRoughness.roughnessFactor = 1.0f - m.GetFloat("_Glossiness");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void Export_Normal(Material m, TextureExportManager textureManager, glTFMaterial material)
|
||||
{
|
||||
if (m.HasProperty("_BumpMap"))
|
||||
{
|
||||
var index = textureManager.ConvertAndGetIndex(m.GetTexture("_BumpMap"), new NormalConverter());
|
||||
if (index != -1)
|
||||
{
|
||||
material.normalTexture = new glTFMaterialNormalTextureInfo()
|
||||
{
|
||||
index = index,
|
||||
};
|
||||
}
|
||||
|
||||
if (index != -1 && m.HasProperty("_BumpScale"))
|
||||
{
|
||||
material.normalTexture.scale = m.GetFloat("_BumpScale");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void Export_Occlusion(Material m, TextureExportManager textureManager, glTFMaterial material)
|
||||
{
|
||||
if (m.HasProperty("_OcclusionMap"))
|
||||
{
|
||||
var index = textureManager.ConvertAndGetIndex(m.GetTexture("_OcclusionMap"), new OcclusionConverter());
|
||||
if (index != -1)
|
||||
{
|
||||
material.occlusionTexture = new glTFMaterialOcclusionTextureInfo()
|
||||
{
|
||||
index = index,
|
||||
};
|
||||
}
|
||||
|
||||
if (index != -1 && m.HasProperty("_OcclusionStrength"))
|
||||
{
|
||||
material.occlusionTexture.strength = m.GetFloat("_OcclusionStrength");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void Export_Emission(Material m, TextureExportManager textureManager, glTFMaterial material)
|
||||
{
|
||||
if (m.HasProperty("_EmissionColor"))
|
||||
{
|
||||
var color = m.GetColor("_EmissionColor");
|
||||
material.emissiveFactor = new float[] { color.r, color.g, color.b };
|
||||
}
|
||||
|
||||
if (m.HasProperty("_EmissionMap"))
|
||||
{
|
||||
var index = textureManager.CopyAndGetIndex(m.GetTexture("_EmissionMap"), RenderTextureReadWrite.sRGB);
|
||||
if (index != -1)
|
||||
{
|
||||
material.emissiveTexture = new glTFMaterialEmissiveTextureInfo()
|
||||
{
|
||||
index = index,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual glTFMaterial CreateMaterial(Material m)
|
||||
{
|
||||
switch (m.shader.name)
|
||||
{
|
||||
case "Unlit/Color":
|
||||
return Export_UnlitColor(m);
|
||||
|
||||
case "Unlit/Texture":
|
||||
return Export_UnlitTexture(m);
|
||||
|
||||
case "Unlit/Transparent":
|
||||
return Export_UnlitTransparent(m);
|
||||
|
||||
case "Unlit/Transparent Cutout":
|
||||
return Export_UnlitCutout(m);
|
||||
|
||||
case "UniGLTF/UniUnlit":
|
||||
return Export_UniUnlit(m);
|
||||
|
||||
default:
|
||||
return Export_Standard(m);
|
||||
}
|
||||
}
|
||||
|
||||
static glTFMaterial Export_UnlitColor(Material m)
|
||||
{
|
||||
var material = glTF_KHR_materials_unlit.CreateDefault();
|
||||
material.alphaMode = glTFBlendMode.OPAQUE.ToString();
|
||||
return material;
|
||||
}
|
||||
|
||||
static glTFMaterial Export_UnlitTexture(Material m)
|
||||
{
|
||||
var material = glTF_KHR_materials_unlit.CreateDefault();
|
||||
material.alphaMode = glTFBlendMode.OPAQUE.ToString();
|
||||
return material;
|
||||
}
|
||||
|
||||
static glTFMaterial Export_UnlitTransparent(Material m)
|
||||
{
|
||||
var material = glTF_KHR_materials_unlit.CreateDefault();
|
||||
material.alphaMode = glTFBlendMode.BLEND.ToString();
|
||||
return material;
|
||||
}
|
||||
|
||||
static glTFMaterial Export_UnlitCutout(Material m)
|
||||
{
|
||||
var material = glTF_KHR_materials_unlit.CreateDefault();
|
||||
material.alphaMode = glTFBlendMode.MASK.ToString();
|
||||
material.alphaCutoff = m.GetFloat("_Cutoff");
|
||||
return material;
|
||||
}
|
||||
|
||||
private glTFMaterial Export_UniUnlit(Material m)
|
||||
{
|
||||
var material = glTF_KHR_materials_unlit.CreateDefault();
|
||||
|
||||
var renderMode = UniUnlit.Utils.GetRenderMode(m);
|
||||
if (renderMode == UniUnlitRenderMode.Opaque)
|
||||
{
|
||||
material.alphaMode = glTFBlendMode.OPAQUE.ToString();
|
||||
}
|
||||
else if (renderMode == UniUnlitRenderMode.Transparent)
|
||||
{
|
||||
material.alphaMode = glTFBlendMode.BLEND.ToString();
|
||||
}
|
||||
else if (renderMode == UniUnlitRenderMode.Cutout)
|
||||
{
|
||||
material.alphaMode = glTFBlendMode.MASK.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
material.alphaMode = glTFBlendMode.OPAQUE.ToString();
|
||||
}
|
||||
|
||||
var cullMode = UniUnlit.Utils.GetCullMode(m);
|
||||
if (cullMode == UniUnlitCullMode.Off)
|
||||
{
|
||||
material.doubleSided = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
material.doubleSided = false;
|
||||
}
|
||||
|
||||
return material;
|
||||
}
|
||||
|
||||
static glTFMaterial Export_Standard(Material m)
|
||||
{
|
||||
var material = new glTFMaterial
|
||||
{
|
||||
pbrMetallicRoughness = new glTFPbrMetallicRoughness(),
|
||||
};
|
||||
|
||||
switch (m.GetTag("RenderType", true))
|
||||
{
|
||||
case "Transparent":
|
||||
material.alphaMode = glTFBlendMode.BLEND.ToString();
|
||||
break;
|
||||
|
||||
case "TransparentCutout":
|
||||
material.alphaMode = glTFBlendMode.MASK.ToString();
|
||||
material.alphaCutoff = m.GetFloat("_Cutoff");
|
||||
break;
|
||||
|
||||
default:
|
||||
material.alphaMode = glTFBlendMode.OPAQUE.ToString();
|
||||
break;
|
||||
}
|
||||
|
||||
return material;
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UniGLTF.UniUnlit;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public enum glTFBlendMode
|
||||
{
|
||||
OPAQUE,
|
||||
MASK,
|
||||
BLEND
|
||||
}
|
||||
|
||||
public interface IMaterialExporter
|
||||
{
|
||||
glTFMaterial ExportMaterial(Material m, TextureExportManager textureManager);
|
||||
}
|
||||
|
||||
public class MaterialExporter : IMaterialExporter
|
||||
{
|
||||
public virtual glTFMaterial ExportMaterial(Material m, TextureExportManager textureManager)
|
||||
{
|
||||
var material = CreateMaterial(m);
|
||||
|
||||
// common params
|
||||
material.name = m.name;
|
||||
Export_Color(m, textureManager, material);
|
||||
Export_Metallic(m, textureManager, material);
|
||||
Export_Normal(m, textureManager, material);
|
||||
Export_Occlusion(m, textureManager, material);
|
||||
Export_Emission(m, textureManager, material);
|
||||
|
||||
return material;
|
||||
}
|
||||
|
||||
static void Export_Color(Material m, TextureExportManager textureManager, glTFMaterial material)
|
||||
{
|
||||
if (m.HasProperty("_Color"))
|
||||
{
|
||||
material.pbrMetallicRoughness.baseColorFactor = m.color.ToArray();
|
||||
}
|
||||
|
||||
if (m.HasProperty("_MainTex"))
|
||||
{
|
||||
var index = textureManager.CopyAndGetIndex(m.GetTexture("_MainTex"), RenderTextureReadWrite.sRGB);
|
||||
if (index != -1)
|
||||
{
|
||||
material.pbrMetallicRoughness.baseColorTexture = new glTFMaterialBaseColorTextureInfo()
|
||||
{
|
||||
index = index,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void Export_Metallic(Material m, TextureExportManager textureManager, glTFMaterial material)
|
||||
{
|
||||
int index = -1;
|
||||
if (m.HasProperty("_MetallicGlossMap"))
|
||||
{
|
||||
index = textureManager.ConvertAndGetIndex(m.GetTexture("_MetallicGlossMap"), new MetallicRoughnessConverter());
|
||||
if (index != -1)
|
||||
{
|
||||
material.pbrMetallicRoughness.metallicRoughnessTexture = new glTFMaterialMetallicRoughnessTextureInfo()
|
||||
{
|
||||
index = index,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (index != -1 && m.HasProperty("_GlossMapScale"))
|
||||
{
|
||||
material.pbrMetallicRoughness.metallicFactor = 1.0f;
|
||||
material.pbrMetallicRoughness.roughnessFactor = 1.0f - m.GetFloat("_GlossMapScale");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m.HasProperty("_Metallic"))
|
||||
{
|
||||
material.pbrMetallicRoughness.metallicFactor = m.GetFloat("_Metallic");
|
||||
}
|
||||
if (m.HasProperty("_Glossiness"))
|
||||
{
|
||||
material.pbrMetallicRoughness.roughnessFactor = 1.0f - m.GetFloat("_Glossiness");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void Export_Normal(Material m, TextureExportManager textureManager, glTFMaterial material)
|
||||
{
|
||||
if (m.HasProperty("_BumpMap"))
|
||||
{
|
||||
var index = textureManager.ConvertAndGetIndex(m.GetTexture("_BumpMap"), new NormalConverter());
|
||||
if (index != -1)
|
||||
{
|
||||
material.normalTexture = new glTFMaterialNormalTextureInfo()
|
||||
{
|
||||
index = index,
|
||||
};
|
||||
}
|
||||
|
||||
if (index != -1 && m.HasProperty("_BumpScale"))
|
||||
{
|
||||
material.normalTexture.scale = m.GetFloat("_BumpScale");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void Export_Occlusion(Material m, TextureExportManager textureManager, glTFMaterial material)
|
||||
{
|
||||
if (m.HasProperty("_OcclusionMap"))
|
||||
{
|
||||
var index = textureManager.ConvertAndGetIndex(m.GetTexture("_OcclusionMap"), new OcclusionConverter());
|
||||
if (index != -1)
|
||||
{
|
||||
material.occlusionTexture = new glTFMaterialOcclusionTextureInfo()
|
||||
{
|
||||
index = index,
|
||||
};
|
||||
}
|
||||
|
||||
if (index != -1 && m.HasProperty("_OcclusionStrength"))
|
||||
{
|
||||
material.occlusionTexture.strength = m.GetFloat("_OcclusionStrength");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void Export_Emission(Material m, TextureExportManager textureManager, glTFMaterial material)
|
||||
{
|
||||
if (m.HasProperty("_EmissionColor"))
|
||||
{
|
||||
var color = m.GetColor("_EmissionColor");
|
||||
material.emissiveFactor = new float[] { color.r, color.g, color.b };
|
||||
}
|
||||
|
||||
if (m.HasProperty("_EmissionMap"))
|
||||
{
|
||||
var index = textureManager.CopyAndGetIndex(m.GetTexture("_EmissionMap"), RenderTextureReadWrite.sRGB);
|
||||
if (index != -1)
|
||||
{
|
||||
material.emissiveTexture = new glTFMaterialEmissiveTextureInfo()
|
||||
{
|
||||
index = index,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual glTFMaterial CreateMaterial(Material m)
|
||||
{
|
||||
switch (m.shader.name)
|
||||
{
|
||||
case "Unlit/Color":
|
||||
return Export_UnlitColor(m);
|
||||
|
||||
case "Unlit/Texture":
|
||||
return Export_UnlitTexture(m);
|
||||
|
||||
case "Unlit/Transparent":
|
||||
return Export_UnlitTransparent(m);
|
||||
|
||||
case "Unlit/Transparent Cutout":
|
||||
return Export_UnlitCutout(m);
|
||||
|
||||
case "UniGLTF/UniUnlit":
|
||||
return Export_UniUnlit(m);
|
||||
|
||||
default:
|
||||
return Export_Standard(m);
|
||||
}
|
||||
}
|
||||
|
||||
static glTFMaterial Export_UnlitColor(Material m)
|
||||
{
|
||||
var material = glTF_KHR_materials_unlit.CreateDefault();
|
||||
material.alphaMode = glTFBlendMode.OPAQUE.ToString();
|
||||
return material;
|
||||
}
|
||||
|
||||
static glTFMaterial Export_UnlitTexture(Material m)
|
||||
{
|
||||
var material = glTF_KHR_materials_unlit.CreateDefault();
|
||||
material.alphaMode = glTFBlendMode.OPAQUE.ToString();
|
||||
return material;
|
||||
}
|
||||
|
||||
static glTFMaterial Export_UnlitTransparent(Material m)
|
||||
{
|
||||
var material = glTF_KHR_materials_unlit.CreateDefault();
|
||||
material.alphaMode = glTFBlendMode.BLEND.ToString();
|
||||
return material;
|
||||
}
|
||||
|
||||
static glTFMaterial Export_UnlitCutout(Material m)
|
||||
{
|
||||
var material = glTF_KHR_materials_unlit.CreateDefault();
|
||||
material.alphaMode = glTFBlendMode.MASK.ToString();
|
||||
material.alphaCutoff = m.GetFloat("_Cutoff");
|
||||
return material;
|
||||
}
|
||||
|
||||
private glTFMaterial Export_UniUnlit(Material m)
|
||||
{
|
||||
var material = glTF_KHR_materials_unlit.CreateDefault();
|
||||
|
||||
var renderMode = UniUnlit.Utils.GetRenderMode(m);
|
||||
if (renderMode == UniUnlitRenderMode.Opaque)
|
||||
{
|
||||
material.alphaMode = glTFBlendMode.OPAQUE.ToString();
|
||||
}
|
||||
else if (renderMode == UniUnlitRenderMode.Transparent)
|
||||
{
|
||||
material.alphaMode = glTFBlendMode.BLEND.ToString();
|
||||
}
|
||||
else if (renderMode == UniUnlitRenderMode.Cutout)
|
||||
{
|
||||
material.alphaMode = glTFBlendMode.MASK.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
material.alphaMode = glTFBlendMode.OPAQUE.ToString();
|
||||
}
|
||||
|
||||
var cullMode = UniUnlit.Utils.GetCullMode(m);
|
||||
if (cullMode == UniUnlitCullMode.Off)
|
||||
{
|
||||
material.doubleSided = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
material.doubleSided = false;
|
||||
}
|
||||
|
||||
return material;
|
||||
}
|
||||
|
||||
static glTFMaterial Export_Standard(Material m)
|
||||
{
|
||||
var material = new glTFMaterial
|
||||
{
|
||||
pbrMetallicRoughness = new glTFPbrMetallicRoughness(),
|
||||
};
|
||||
|
||||
switch (m.GetTag("RenderType", true))
|
||||
{
|
||||
case "Transparent":
|
||||
material.alphaMode = glTFBlendMode.BLEND.ToString();
|
||||
break;
|
||||
|
||||
case "TransparentCutout":
|
||||
material.alphaMode = glTFBlendMode.MASK.ToString();
|
||||
material.alphaCutoff = m.GetFloat("_Cutoff");
|
||||
break;
|
||||
|
||||
default:
|
||||
material.alphaMode = glTFBlendMode.OPAQUE.ToString();
|
||||
break;
|
||||
}
|
||||
|
||||
return material;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,262 +1,262 @@
|
|||
using UnityEngine;
|
||||
using System;
|
||||
using UnityEngine.Rendering;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public interface IMaterialImporter
|
||||
{
|
||||
Material CreateMaterial(int i, glTFMaterial src);
|
||||
}
|
||||
|
||||
public class MaterialImporter : IMaterialImporter
|
||||
{
|
||||
IShaderStore m_shaderStore;
|
||||
|
||||
ImporterContext m_context;
|
||||
protected ImporterContext Context
|
||||
{
|
||||
get { return m_context; }
|
||||
}
|
||||
|
||||
public MaterialImporter(IShaderStore shaderStore, ImporterContext context)
|
||||
{
|
||||
m_shaderStore = shaderStore;
|
||||
m_context = context;
|
||||
}
|
||||
|
||||
private enum BlendMode
|
||||
{
|
||||
Opaque,
|
||||
Cutout,
|
||||
Fade,
|
||||
Transparent
|
||||
}
|
||||
|
||||
/// StandardShader vaiables
|
||||
///
|
||||
/// _Color
|
||||
/// _MainTex
|
||||
/// _Cutoff
|
||||
/// _Glossiness
|
||||
/// _Metallic
|
||||
/// _MetallicGlossMap
|
||||
/// _BumpScale
|
||||
/// _BumpMap
|
||||
/// _Parallax
|
||||
/// _ParallaxMap
|
||||
/// _OcclusionStrength
|
||||
/// _OcclusionMap
|
||||
/// _EmissionColor
|
||||
/// _EmissionMap
|
||||
/// _DetailMask
|
||||
/// _DetailAlbedoMap
|
||||
/// _DetailNormalMapScale
|
||||
/// _DetailNormalMap
|
||||
/// _UVSec
|
||||
/// _EmissionScaleUI
|
||||
/// _EmissionColorUI
|
||||
/// _Mode
|
||||
/// _SrcBlend
|
||||
/// _DstBlend
|
||||
/// _ZWrite
|
||||
public virtual Material CreateMaterial(int i, glTFMaterial x)
|
||||
{
|
||||
var shader = m_shaderStore.GetShader(x);
|
||||
//Debug.LogFormat("[{0}]{1}", i, shader.name);
|
||||
var material = new Material(shader);
|
||||
#if UNITY_EDITOR
|
||||
// textureImporter.SaveAndReimport(); may destory this material
|
||||
material.hideFlags = HideFlags.DontUnloadUnusedAsset;
|
||||
#endif
|
||||
|
||||
material.name = (x == null || string.IsNullOrEmpty(x.name))
|
||||
? string.Format("material_{0:00}", i)
|
||||
: x.name
|
||||
;
|
||||
|
||||
if (x == null)
|
||||
{
|
||||
Debug.LogWarning("glTFMaterial is empty");
|
||||
return material;
|
||||
}
|
||||
|
||||
// unlit material
|
||||
if (x.extensions != null && x.extensions.KHR_materials_unlit != null)
|
||||
{
|
||||
// texture
|
||||
var texture = m_context.GetTexture(x.pbrMetallicRoughness.baseColorTexture.index);
|
||||
if (texture != null)
|
||||
{
|
||||
material.mainTexture = texture.Texture;
|
||||
}
|
||||
|
||||
// color
|
||||
if (x.pbrMetallicRoughness.baseColorFactor != null && x.pbrMetallicRoughness.baseColorFactor.Length == 4)
|
||||
{
|
||||
var color = x.pbrMetallicRoughness.baseColorFactor;
|
||||
material.color = new Color(color[0], color[1], color[2], color[3]);
|
||||
}
|
||||
|
||||
//renderMode
|
||||
if (x.alphaMode == "OPAQUE")
|
||||
{
|
||||
UniUnlit.Utils.SetRenderMode(material, UniUnlit.UniUnlitRenderMode.Opaque);
|
||||
}
|
||||
else if (x.alphaMode == "BLEND")
|
||||
{
|
||||
UniUnlit.Utils.SetRenderMode(material, UniUnlit.UniUnlitRenderMode.Transparent);
|
||||
}
|
||||
else if(x.alphaMode == "MASK")
|
||||
{
|
||||
UniUnlit.Utils.SetRenderMode(material, UniUnlit.UniUnlitRenderMode.Cutout);
|
||||
}
|
||||
else
|
||||
{
|
||||
// default OPAQUE
|
||||
UniUnlit.Utils.SetRenderMode(material, UniUnlit.UniUnlitRenderMode.Opaque);
|
||||
}
|
||||
|
||||
// culling
|
||||
if (x.doubleSided)
|
||||
{
|
||||
UniUnlit.Utils.SetCullMode(material, UniUnlit.UniUnlitCullMode.Off);
|
||||
}
|
||||
else
|
||||
{
|
||||
UniUnlit.Utils.SetCullMode(material, UniUnlit.UniUnlitCullMode.Back);
|
||||
}
|
||||
|
||||
UniUnlit.Utils.ValidateProperties(material, true);
|
||||
|
||||
return material;
|
||||
}
|
||||
|
||||
// PBR material
|
||||
if (x.pbrMetallicRoughness != null)
|
||||
{
|
||||
if (x.pbrMetallicRoughness.baseColorFactor != null && x.pbrMetallicRoughness.baseColorFactor.Length == 4)
|
||||
{
|
||||
var color = x.pbrMetallicRoughness.baseColorFactor;
|
||||
material.color = new Color(color[0], color[1], color[2], color[3]);
|
||||
}
|
||||
|
||||
if (x.pbrMetallicRoughness.baseColorTexture != null && x.pbrMetallicRoughness.baseColorTexture.index != -1)
|
||||
{
|
||||
var texture = m_context.GetTexture(x.pbrMetallicRoughness.baseColorTexture.index);
|
||||
if (texture != null)
|
||||
{
|
||||
material.mainTexture = texture.Texture;
|
||||
}
|
||||
}
|
||||
|
||||
if (x.pbrMetallicRoughness.metallicRoughnessTexture != null && x.pbrMetallicRoughness.metallicRoughnessTexture.index != -1)
|
||||
{
|
||||
material.EnableKeyword("_METALLICGLOSSMAP");
|
||||
var texture = Context.GetTexture(x.pbrMetallicRoughness.metallicRoughnessTexture.index);
|
||||
if (texture != null)
|
||||
{
|
||||
var prop = "_MetallicGlossMap";
|
||||
material.SetTexture(prop, texture.ConvertTexture(prop));
|
||||
}
|
||||
}
|
||||
|
||||
material.SetFloat("_Metallic", x.pbrMetallicRoughness.metallicFactor);
|
||||
material.SetFloat("_Glossiness", 1.0f - x.pbrMetallicRoughness.roughnessFactor);
|
||||
}
|
||||
|
||||
if (x.normalTexture != null && x.normalTexture.index != -1)
|
||||
{
|
||||
material.EnableKeyword("_NORMALMAP");
|
||||
var texture = Context.GetTexture(x.normalTexture.index);
|
||||
if (texture != null)
|
||||
{
|
||||
var prop = "_BumpMap";
|
||||
material.SetTexture(prop, texture.ConvertTexture(prop));
|
||||
material.SetFloat("_BumpScale", x.normalTexture.scale);
|
||||
}
|
||||
}
|
||||
|
||||
if (x.occlusionTexture != null && x.occlusionTexture.index != -1)
|
||||
{
|
||||
var texture = Context.GetTexture(x.occlusionTexture.index);
|
||||
if (texture != null)
|
||||
{
|
||||
var prop = "_OcclusionMap";
|
||||
material.SetTexture(prop, texture.ConvertTexture(prop));
|
||||
material.SetFloat("_OcclusionStrength", x.occlusionTexture.strength);
|
||||
}
|
||||
}
|
||||
|
||||
if (x.emissiveFactor != null
|
||||
|| (x.emissiveTexture != null && x.emissiveTexture.index != -1))
|
||||
{
|
||||
material.EnableKeyword("_EMISSION");
|
||||
material.globalIlluminationFlags &= ~MaterialGlobalIlluminationFlags.EmissiveIsBlack;
|
||||
|
||||
if (x.emissiveFactor != null && x.emissiveFactor.Length == 3)
|
||||
{
|
||||
material.SetColor("_EmissionColor", new Color(x.emissiveFactor[0], x.emissiveFactor[1], x.emissiveFactor[2]));
|
||||
}
|
||||
|
||||
if (x.emissiveTexture.index != -1)
|
||||
{
|
||||
var texture = Context.GetTexture(x.emissiveTexture.index);
|
||||
if (texture != null)
|
||||
{
|
||||
material.SetTexture("_EmissionMap", texture.Texture);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BlendMode blendMode = BlendMode.Opaque;
|
||||
// https://forum.unity.com/threads/standard-material-shader-ignoring-setfloat-property-_mode.344557/#post-2229980
|
||||
switch (x.alphaMode)
|
||||
{
|
||||
case "BLEND":
|
||||
blendMode = BlendMode.Fade;
|
||||
material.SetOverrideTag("RenderType", "Transparent");
|
||||
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
|
||||
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
|
||||
material.SetInt("_ZWrite", 0);
|
||||
material.DisableKeyword("_ALPHATEST_ON");
|
||||
material.EnableKeyword("_ALPHABLEND_ON");
|
||||
material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
|
||||
material.renderQueue = 3000;
|
||||
break;
|
||||
|
||||
case "MASK":
|
||||
blendMode = BlendMode.Cutout;
|
||||
material.SetOverrideTag("RenderType", "TransparentCutout");
|
||||
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
|
||||
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
|
||||
material.SetInt("_ZWrite", 1);
|
||||
material.EnableKeyword("_ALPHATEST_ON");
|
||||
material.DisableKeyword("_ALPHABLEND_ON");
|
||||
material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
|
||||
material.renderQueue = 2450;
|
||||
|
||||
break;
|
||||
|
||||
default: // OPAQUE
|
||||
blendMode = BlendMode.Opaque;
|
||||
material.SetOverrideTag("RenderType", "");
|
||||
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
|
||||
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
|
||||
material.SetInt("_ZWrite", 1);
|
||||
material.DisableKeyword("_ALPHATEST_ON");
|
||||
material.DisableKeyword("_ALPHABLEND_ON");
|
||||
material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
|
||||
material.renderQueue = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
material.SetFloat("_Mode", (float)blendMode);
|
||||
return material;
|
||||
}
|
||||
}
|
||||
}
|
||||
using UnityEngine;
|
||||
using System;
|
||||
using UnityEngine.Rendering;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public interface IMaterialImporter
|
||||
{
|
||||
Material CreateMaterial(int i, glTFMaterial src);
|
||||
}
|
||||
|
||||
public class MaterialImporter : IMaterialImporter
|
||||
{
|
||||
IShaderStore m_shaderStore;
|
||||
|
||||
ImporterContext m_context;
|
||||
protected ImporterContext Context
|
||||
{
|
||||
get { return m_context; }
|
||||
}
|
||||
|
||||
public MaterialImporter(IShaderStore shaderStore, ImporterContext context)
|
||||
{
|
||||
m_shaderStore = shaderStore;
|
||||
m_context = context;
|
||||
}
|
||||
|
||||
private enum BlendMode
|
||||
{
|
||||
Opaque,
|
||||
Cutout,
|
||||
Fade,
|
||||
Transparent
|
||||
}
|
||||
|
||||
/// StandardShader vaiables
|
||||
///
|
||||
/// _Color
|
||||
/// _MainTex
|
||||
/// _Cutoff
|
||||
/// _Glossiness
|
||||
/// _Metallic
|
||||
/// _MetallicGlossMap
|
||||
/// _BumpScale
|
||||
/// _BumpMap
|
||||
/// _Parallax
|
||||
/// _ParallaxMap
|
||||
/// _OcclusionStrength
|
||||
/// _OcclusionMap
|
||||
/// _EmissionColor
|
||||
/// _EmissionMap
|
||||
/// _DetailMask
|
||||
/// _DetailAlbedoMap
|
||||
/// _DetailNormalMapScale
|
||||
/// _DetailNormalMap
|
||||
/// _UVSec
|
||||
/// _EmissionScaleUI
|
||||
/// _EmissionColorUI
|
||||
/// _Mode
|
||||
/// _SrcBlend
|
||||
/// _DstBlend
|
||||
/// _ZWrite
|
||||
public virtual Material CreateMaterial(int i, glTFMaterial x)
|
||||
{
|
||||
var shader = m_shaderStore.GetShader(x);
|
||||
//Debug.LogFormat("[{0}]{1}", i, shader.name);
|
||||
var material = new Material(shader);
|
||||
#if UNITY_EDITOR
|
||||
// textureImporter.SaveAndReimport(); may destory this material
|
||||
material.hideFlags = HideFlags.DontUnloadUnusedAsset;
|
||||
#endif
|
||||
|
||||
material.name = (x == null || string.IsNullOrEmpty(x.name))
|
||||
? string.Format("material_{0:00}", i)
|
||||
: x.name
|
||||
;
|
||||
|
||||
if (x == null)
|
||||
{
|
||||
Debug.LogWarning("glTFMaterial is empty");
|
||||
return material;
|
||||
}
|
||||
|
||||
// unlit material
|
||||
if (x.extensions != null && x.extensions.KHR_materials_unlit != null)
|
||||
{
|
||||
// texture
|
||||
var texture = m_context.GetTexture(x.pbrMetallicRoughness.baseColorTexture.index);
|
||||
if (texture != null)
|
||||
{
|
||||
material.mainTexture = texture.Texture;
|
||||
}
|
||||
|
||||
// color
|
||||
if (x.pbrMetallicRoughness.baseColorFactor != null && x.pbrMetallicRoughness.baseColorFactor.Length == 4)
|
||||
{
|
||||
var color = x.pbrMetallicRoughness.baseColorFactor;
|
||||
material.color = new Color(color[0], color[1], color[2], color[3]);
|
||||
}
|
||||
|
||||
//renderMode
|
||||
if (x.alphaMode == "OPAQUE")
|
||||
{
|
||||
UniUnlit.Utils.SetRenderMode(material, UniUnlit.UniUnlitRenderMode.Opaque);
|
||||
}
|
||||
else if (x.alphaMode == "BLEND")
|
||||
{
|
||||
UniUnlit.Utils.SetRenderMode(material, UniUnlit.UniUnlitRenderMode.Transparent);
|
||||
}
|
||||
else if(x.alphaMode == "MASK")
|
||||
{
|
||||
UniUnlit.Utils.SetRenderMode(material, UniUnlit.UniUnlitRenderMode.Cutout);
|
||||
}
|
||||
else
|
||||
{
|
||||
// default OPAQUE
|
||||
UniUnlit.Utils.SetRenderMode(material, UniUnlit.UniUnlitRenderMode.Opaque);
|
||||
}
|
||||
|
||||
// culling
|
||||
if (x.doubleSided)
|
||||
{
|
||||
UniUnlit.Utils.SetCullMode(material, UniUnlit.UniUnlitCullMode.Off);
|
||||
}
|
||||
else
|
||||
{
|
||||
UniUnlit.Utils.SetCullMode(material, UniUnlit.UniUnlitCullMode.Back);
|
||||
}
|
||||
|
||||
UniUnlit.Utils.ValidateProperties(material, true);
|
||||
|
||||
return material;
|
||||
}
|
||||
|
||||
// PBR material
|
||||
if (x.pbrMetallicRoughness != null)
|
||||
{
|
||||
if (x.pbrMetallicRoughness.baseColorFactor != null && x.pbrMetallicRoughness.baseColorFactor.Length == 4)
|
||||
{
|
||||
var color = x.pbrMetallicRoughness.baseColorFactor;
|
||||
material.color = new Color(color[0], color[1], color[2], color[3]);
|
||||
}
|
||||
|
||||
if (x.pbrMetallicRoughness.baseColorTexture != null && x.pbrMetallicRoughness.baseColorTexture.index != -1)
|
||||
{
|
||||
var texture = m_context.GetTexture(x.pbrMetallicRoughness.baseColorTexture.index);
|
||||
if (texture != null)
|
||||
{
|
||||
material.mainTexture = texture.Texture;
|
||||
}
|
||||
}
|
||||
|
||||
if (x.pbrMetallicRoughness.metallicRoughnessTexture != null && x.pbrMetallicRoughness.metallicRoughnessTexture.index != -1)
|
||||
{
|
||||
material.EnableKeyword("_METALLICGLOSSMAP");
|
||||
var texture = Context.GetTexture(x.pbrMetallicRoughness.metallicRoughnessTexture.index);
|
||||
if (texture != null)
|
||||
{
|
||||
var prop = "_MetallicGlossMap";
|
||||
material.SetTexture(prop, texture.ConvertTexture(prop));
|
||||
}
|
||||
}
|
||||
|
||||
material.SetFloat("_Metallic", x.pbrMetallicRoughness.metallicFactor);
|
||||
material.SetFloat("_Glossiness", 1.0f - x.pbrMetallicRoughness.roughnessFactor);
|
||||
}
|
||||
|
||||
if (x.normalTexture != null && x.normalTexture.index != -1)
|
||||
{
|
||||
material.EnableKeyword("_NORMALMAP");
|
||||
var texture = Context.GetTexture(x.normalTexture.index);
|
||||
if (texture != null)
|
||||
{
|
||||
var prop = "_BumpMap";
|
||||
material.SetTexture(prop, texture.ConvertTexture(prop));
|
||||
material.SetFloat("_BumpScale", x.normalTexture.scale);
|
||||
}
|
||||
}
|
||||
|
||||
if (x.occlusionTexture != null && x.occlusionTexture.index != -1)
|
||||
{
|
||||
var texture = Context.GetTexture(x.occlusionTexture.index);
|
||||
if (texture != null)
|
||||
{
|
||||
var prop = "_OcclusionMap";
|
||||
material.SetTexture(prop, texture.ConvertTexture(prop));
|
||||
material.SetFloat("_OcclusionStrength", x.occlusionTexture.strength);
|
||||
}
|
||||
}
|
||||
|
||||
if (x.emissiveFactor != null
|
||||
|| (x.emissiveTexture != null && x.emissiveTexture.index != -1))
|
||||
{
|
||||
material.EnableKeyword("_EMISSION");
|
||||
material.globalIlluminationFlags &= ~MaterialGlobalIlluminationFlags.EmissiveIsBlack;
|
||||
|
||||
if (x.emissiveFactor != null && x.emissiveFactor.Length == 3)
|
||||
{
|
||||
material.SetColor("_EmissionColor", new Color(x.emissiveFactor[0], x.emissiveFactor[1], x.emissiveFactor[2]));
|
||||
}
|
||||
|
||||
if (x.emissiveTexture.index != -1)
|
||||
{
|
||||
var texture = Context.GetTexture(x.emissiveTexture.index);
|
||||
if (texture != null)
|
||||
{
|
||||
material.SetTexture("_EmissionMap", texture.Texture);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BlendMode blendMode = BlendMode.Opaque;
|
||||
// https://forum.unity.com/threads/standard-material-shader-ignoring-setfloat-property-_mode.344557/#post-2229980
|
||||
switch (x.alphaMode)
|
||||
{
|
||||
case "BLEND":
|
||||
blendMode = BlendMode.Fade;
|
||||
material.SetOverrideTag("RenderType", "Transparent");
|
||||
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
|
||||
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
|
||||
material.SetInt("_ZWrite", 0);
|
||||
material.DisableKeyword("_ALPHATEST_ON");
|
||||
material.EnableKeyword("_ALPHABLEND_ON");
|
||||
material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
|
||||
material.renderQueue = 3000;
|
||||
break;
|
||||
|
||||
case "MASK":
|
||||
blendMode = BlendMode.Cutout;
|
||||
material.SetOverrideTag("RenderType", "TransparentCutout");
|
||||
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
|
||||
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
|
||||
material.SetInt("_ZWrite", 1);
|
||||
material.EnableKeyword("_ALPHATEST_ON");
|
||||
material.DisableKeyword("_ALPHABLEND_ON");
|
||||
material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
|
||||
material.renderQueue = 2450;
|
||||
|
||||
break;
|
||||
|
||||
default: // OPAQUE
|
||||
blendMode = BlendMode.Opaque;
|
||||
material.SetOverrideTag("RenderType", "");
|
||||
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
|
||||
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
|
||||
material.SetInt("_ZWrite", 1);
|
||||
material.DisableKeyword("_ALPHATEST_ON");
|
||||
material.DisableKeyword("_ALPHABLEND_ON");
|
||||
material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
|
||||
material.renderQueue = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
material.SetFloat("_Mode", (float)blendMode);
|
||||
return material;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,261 +1,261 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public struct MeshWithRenderer
|
||||
{
|
||||
public Mesh Mesh;
|
||||
public Renderer Rendererer;
|
||||
}
|
||||
|
||||
public static class MeshExporter
|
||||
{
|
||||
static glTFMesh ExportPrimitives(glTF gltf, int bufferIndex,
|
||||
string rendererName,
|
||||
Mesh mesh, Material[] materials,
|
||||
List<Material> unityMaterials)
|
||||
{
|
||||
var positions = mesh.vertices.Select(y => y.ReverseZ()).ToArray();
|
||||
var positionAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, positions, glBufferTarget.ARRAY_BUFFER);
|
||||
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();
|
||||
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();
|
||||
|
||||
var normalAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.normals.Select(y => y.ReverseZ()).ToArray(), glBufferTarget.ARRAY_BUFFER);
|
||||
#if GLTF_EXPORT_TANGENTS
|
||||
var tangentAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.tangents.Select(y => y.ReverseZ()).ToArray(), glBufferTarget.ARRAY_BUFFER);
|
||||
#endif
|
||||
var uvAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.uv.Select(y => y.ReverseUV()).ToArray(), glBufferTarget.ARRAY_BUFFER);
|
||||
var colorAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.colors, glBufferTarget.ARRAY_BUFFER);
|
||||
|
||||
var boneweights = mesh.boneWeights;
|
||||
var weightAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, boneweights.Select(y => new Vector4(y.weight0, y.weight1, y.weight2, y.weight3)).ToArray(), glBufferTarget.ARRAY_BUFFER);
|
||||
var jointsAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, boneweights.Select(y => new UShort4((ushort)y.boneIndex0, (ushort)y.boneIndex1, (ushort)y.boneIndex2, (ushort)y.boneIndex3)).ToArray(), glBufferTarget.ARRAY_BUFFER);
|
||||
|
||||
var attributes = new glTFAttributes
|
||||
{
|
||||
POSITION = positionAccessorIndex,
|
||||
};
|
||||
if (normalAccessorIndex != -1)
|
||||
{
|
||||
attributes.NORMAL = normalAccessorIndex;
|
||||
}
|
||||
#if GLTF_EXPORT_TANGENTS
|
||||
if (tangentAccessorIndex != -1)
|
||||
{
|
||||
attributes.TANGENT = tangentAccessorIndex;
|
||||
}
|
||||
#endif
|
||||
if (uvAccessorIndex != -1)
|
||||
{
|
||||
attributes.TEXCOORD_0 = uvAccessorIndex;
|
||||
}
|
||||
if (colorAccessorIndex != -1)
|
||||
{
|
||||
attributes.COLOR_0 = colorAccessorIndex;
|
||||
}
|
||||
if (weightAccessorIndex != -1)
|
||||
{
|
||||
attributes.WEIGHTS_0 = weightAccessorIndex;
|
||||
}
|
||||
if (jointsAccessorIndex != -1)
|
||||
{
|
||||
attributes.JOINTS_0 = jointsAccessorIndex;
|
||||
}
|
||||
|
||||
var gltfMesh = new glTFMesh(mesh.name);
|
||||
for (int j = 0; j < mesh.subMeshCount; ++j)
|
||||
{
|
||||
var indices = TriangleUtil.FlipTriangle(mesh.GetIndices(j)).Select(y => (uint)y).ToArray();
|
||||
var indicesAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, indices, glBufferTarget.ELEMENT_ARRAY_BUFFER);
|
||||
|
||||
if (j >= materials.Length)
|
||||
{
|
||||
Debug.LogWarningFormat("{0}.materials is not enough", rendererName);
|
||||
break;
|
||||
}
|
||||
|
||||
gltfMesh.primitives.Add(new glTFPrimitives
|
||||
{
|
||||
attributes = attributes,
|
||||
indices = indicesAccessorIndex,
|
||||
mode = 4, // triangels ?
|
||||
material = unityMaterials.IndexOf(materials[j])
|
||||
});
|
||||
}
|
||||
return gltfMesh;
|
||||
}
|
||||
|
||||
static bool UseSparse(
|
||||
bool usePosition, Vector3 position,
|
||||
bool useNormal, Vector3 normal,
|
||||
bool useTangent, Vector3 tangent
|
||||
)
|
||||
{
|
||||
var useSparse =
|
||||
(usePosition && position != Vector3.zero)
|
||||
|| (useNormal && normal != Vector3.zero)
|
||||
|| (useTangent && tangent != Vector3.zero)
|
||||
;
|
||||
return useSparse;
|
||||
}
|
||||
|
||||
static gltfMorphTarget ExportMorphTarget(glTF gltf, int bufferIndex,
|
||||
Mesh mesh, int j,
|
||||
bool useSparseAccessorForMorphTarget)
|
||||
{
|
||||
var blendShapeVertices = mesh.vertices;
|
||||
var usePosition = blendShapeVertices != null && blendShapeVertices.Length > 0;
|
||||
|
||||
var blendShapeNormals = mesh.normals;
|
||||
var useNormal = usePosition && blendShapeNormals != null && blendShapeNormals.Length == blendShapeVertices.Length;
|
||||
|
||||
var blendShapeTangents = mesh.tangents.Select(y => (Vector3)y).ToArray();
|
||||
//var useTangent = usePosition && blendShapeTangents != null && blendShapeTangents.Length == blendShapeVertices.Length;
|
||||
var useTangent = false;
|
||||
|
||||
var frameCount = mesh.GetBlendShapeFrameCount(j);
|
||||
mesh.GetBlendShapeFrameVertices(j, frameCount - 1, blendShapeVertices, blendShapeNormals, null);
|
||||
|
||||
var blendShapePositionAccessorIndex = -1;
|
||||
var blendShapeNormalAccessorIndex = -1;
|
||||
var blendShapeTangentAccessorIndex = -1;
|
||||
if (useSparseAccessorForMorphTarget)
|
||||
{
|
||||
var accessorCount = blendShapeVertices.Length;
|
||||
var sparseIndices = Enumerable.Range(0, blendShapeVertices.Length)
|
||||
.Where(x => UseSparse(
|
||||
usePosition, blendShapeVertices[x],
|
||||
useNormal, blendShapeNormals[x],
|
||||
useTangent, blendShapeTangents[x]))
|
||||
.ToArray()
|
||||
;
|
||||
|
||||
if (sparseIndices.Length == 0)
|
||||
{
|
||||
usePosition = false;
|
||||
useNormal = false;
|
||||
useTangent = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogFormat("Sparse {0}/{1}", sparseIndices.Length, mesh.vertexCount);
|
||||
}
|
||||
/*
|
||||
var vertexSize = 12;
|
||||
if (useNormal) vertexSize += 12;
|
||||
if (useTangent) vertexSize += 24;
|
||||
var sparseBytes = (4 + vertexSize) * sparseIndices.Length;
|
||||
var fullBytes = (vertexSize) * blendShapeVertices.Length;
|
||||
Debug.LogFormat("Export sparse: {0}/{1}bytes({2}%)",
|
||||
sparseBytes, fullBytes, (int)((float)sparseBytes / fullBytes)
|
||||
);
|
||||
*/
|
||||
|
||||
var sparseIndicesViewIndex = -1;
|
||||
if (usePosition)
|
||||
{
|
||||
sparseIndicesViewIndex = gltf.ExtendBufferAndGetViewIndex(bufferIndex, sparseIndices);
|
||||
|
||||
blendShapeVertices = sparseIndices.Select(x => blendShapeVertices[x].ReverseZ()).ToArray();
|
||||
blendShapePositionAccessorIndex = gltf.ExtendSparseBufferAndGetAccessorIndex(bufferIndex, accessorCount,
|
||||
blendShapeVertices,
|
||||
sparseIndices, sparseIndicesViewIndex,
|
||||
glBufferTarget.ARRAY_BUFFER);
|
||||
}
|
||||
|
||||
if (useNormal)
|
||||
{
|
||||
blendShapeNormals = sparseIndices.Select(x => blendShapeNormals[x].ReverseZ()).ToArray();
|
||||
blendShapeNormalAccessorIndex = gltf.ExtendSparseBufferAndGetAccessorIndex(bufferIndex, accessorCount,
|
||||
blendShapeNormals,
|
||||
sparseIndices, sparseIndicesViewIndex,
|
||||
glBufferTarget.ARRAY_BUFFER);
|
||||
}
|
||||
|
||||
if (useTangent)
|
||||
{
|
||||
blendShapeTangents = sparseIndices.Select(x => blendShapeTangents[x].ReverseZ()).ToArray();
|
||||
blendShapeTangentAccessorIndex = gltf.ExtendSparseBufferAndGetAccessorIndex(bufferIndex, accessorCount,
|
||||
blendShapeTangents, sparseIndices, sparseIndicesViewIndex,
|
||||
glBufferTarget.ARRAY_BUFFER);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < blendShapeVertices.Length; ++i) blendShapeVertices[i] = blendShapeVertices[i].ReverseZ();
|
||||
if (usePosition)
|
||||
{
|
||||
blendShapePositionAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex,
|
||||
blendShapeVertices,
|
||||
glBufferTarget.ARRAY_BUFFER);
|
||||
}
|
||||
|
||||
if (useNormal)
|
||||
{
|
||||
for (int i = 0; i < blendShapeNormals.Length; ++i) blendShapeNormals[i] = blendShapeNormals[i].ReverseZ();
|
||||
blendShapeNormalAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex,
|
||||
blendShapeNormals,
|
||||
glBufferTarget.ARRAY_BUFFER);
|
||||
}
|
||||
|
||||
if (useTangent)
|
||||
{
|
||||
for (int i = 0; i < blendShapeTangents.Length; ++i) blendShapeTangents[i] = blendShapeTangents[i].ReverseZ();
|
||||
blendShapeTangentAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex,
|
||||
blendShapeTangents,
|
||||
glBufferTarget.ARRAY_BUFFER);
|
||||
}
|
||||
}
|
||||
|
||||
if (blendShapePositionAccessorIndex != -1)
|
||||
{
|
||||
gltf.accessors[blendShapePositionAccessorIndex].min = blendShapeVertices.Aggregate(blendShapeVertices[0], (a, b) => new Vector3(Mathf.Min(a.x, b.x), Math.Min(a.y, b.y), Mathf.Min(a.z, b.z))).ToArray();
|
||||
gltf.accessors[blendShapePositionAccessorIndex].max = blendShapeVertices.Aggregate(blendShapeVertices[0], (a, b) => new Vector3(Mathf.Max(a.x, b.x), Math.Max(a.y, b.y), Mathf.Max(a.z, b.z))).ToArray();
|
||||
}
|
||||
|
||||
return new gltfMorphTarget
|
||||
{
|
||||
POSITION = blendShapePositionAccessorIndex,
|
||||
NORMAL = blendShapeNormalAccessorIndex,
|
||||
TANGENT = blendShapeTangentAccessorIndex,
|
||||
};
|
||||
}
|
||||
|
||||
public static void ExportMeshes(glTF gltf, int bufferIndex,
|
||||
List<MeshWithRenderer> unityMeshes, List<Material> unityMaterials,
|
||||
bool useSparseAccessorForMorphTarget)
|
||||
{
|
||||
for (int i = 0; i < unityMeshes.Count; ++i)
|
||||
{
|
||||
var x = unityMeshes[i];
|
||||
var mesh = x.Mesh;
|
||||
var materials = x.Rendererer.sharedMaterials;
|
||||
|
||||
var gltfMesh = ExportPrimitives(gltf, bufferIndex,
|
||||
x.Rendererer.name,
|
||||
mesh, materials, unityMaterials);
|
||||
|
||||
for (int j = 0; j < mesh.blendShapeCount; ++j)
|
||||
{
|
||||
var morphTarget = ExportMorphTarget(gltf, bufferIndex,
|
||||
mesh, j,
|
||||
useSparseAccessorForMorphTarget);
|
||||
|
||||
//
|
||||
// all primitive has same blendShape
|
||||
//
|
||||
for (int k = 0; k < gltfMesh.primitives.Count; ++k)
|
||||
{
|
||||
gltfMesh.primitives[k].targets.Add(morphTarget);
|
||||
gltfMesh.primitives[k].extras.targetNames.Add(mesh.GetBlendShapeName(j));
|
||||
}
|
||||
}
|
||||
|
||||
gltf.meshes.Add(gltfMesh);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public struct MeshWithRenderer
|
||||
{
|
||||
public Mesh Mesh;
|
||||
public Renderer Rendererer;
|
||||
}
|
||||
|
||||
public static class MeshExporter
|
||||
{
|
||||
static glTFMesh ExportPrimitives(glTF gltf, int bufferIndex,
|
||||
string rendererName,
|
||||
Mesh mesh, Material[] materials,
|
||||
List<Material> unityMaterials)
|
||||
{
|
||||
var positions = mesh.vertices.Select(y => y.ReverseZ()).ToArray();
|
||||
var positionAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, positions, glBufferTarget.ARRAY_BUFFER);
|
||||
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();
|
||||
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();
|
||||
|
||||
var normalAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.normals.Select(y => y.ReverseZ()).ToArray(), glBufferTarget.ARRAY_BUFFER);
|
||||
#if GLTF_EXPORT_TANGENTS
|
||||
var tangentAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.tangents.Select(y => y.ReverseZ()).ToArray(), glBufferTarget.ARRAY_BUFFER);
|
||||
#endif
|
||||
var uvAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.uv.Select(y => y.ReverseUV()).ToArray(), glBufferTarget.ARRAY_BUFFER);
|
||||
var colorAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.colors, glBufferTarget.ARRAY_BUFFER);
|
||||
|
||||
var boneweights = mesh.boneWeights;
|
||||
var weightAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, boneweights.Select(y => new Vector4(y.weight0, y.weight1, y.weight2, y.weight3)).ToArray(), glBufferTarget.ARRAY_BUFFER);
|
||||
var jointsAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, boneweights.Select(y => new UShort4((ushort)y.boneIndex0, (ushort)y.boneIndex1, (ushort)y.boneIndex2, (ushort)y.boneIndex3)).ToArray(), glBufferTarget.ARRAY_BUFFER);
|
||||
|
||||
var attributes = new glTFAttributes
|
||||
{
|
||||
POSITION = positionAccessorIndex,
|
||||
};
|
||||
if (normalAccessorIndex != -1)
|
||||
{
|
||||
attributes.NORMAL = normalAccessorIndex;
|
||||
}
|
||||
#if GLTF_EXPORT_TANGENTS
|
||||
if (tangentAccessorIndex != -1)
|
||||
{
|
||||
attributes.TANGENT = tangentAccessorIndex;
|
||||
}
|
||||
#endif
|
||||
if (uvAccessorIndex != -1)
|
||||
{
|
||||
attributes.TEXCOORD_0 = uvAccessorIndex;
|
||||
}
|
||||
if (colorAccessorIndex != -1)
|
||||
{
|
||||
attributes.COLOR_0 = colorAccessorIndex;
|
||||
}
|
||||
if (weightAccessorIndex != -1)
|
||||
{
|
||||
attributes.WEIGHTS_0 = weightAccessorIndex;
|
||||
}
|
||||
if (jointsAccessorIndex != -1)
|
||||
{
|
||||
attributes.JOINTS_0 = jointsAccessorIndex;
|
||||
}
|
||||
|
||||
var gltfMesh = new glTFMesh(mesh.name);
|
||||
for (int j = 0; j < mesh.subMeshCount; ++j)
|
||||
{
|
||||
var indices = TriangleUtil.FlipTriangle(mesh.GetIndices(j)).Select(y => (uint)y).ToArray();
|
||||
var indicesAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, indices, glBufferTarget.ELEMENT_ARRAY_BUFFER);
|
||||
|
||||
if (j >= materials.Length)
|
||||
{
|
||||
Debug.LogWarningFormat("{0}.materials is not enough", rendererName);
|
||||
break;
|
||||
}
|
||||
|
||||
gltfMesh.primitives.Add(new glTFPrimitives
|
||||
{
|
||||
attributes = attributes,
|
||||
indices = indicesAccessorIndex,
|
||||
mode = 4, // triangels ?
|
||||
material = unityMaterials.IndexOf(materials[j])
|
||||
});
|
||||
}
|
||||
return gltfMesh;
|
||||
}
|
||||
|
||||
static bool UseSparse(
|
||||
bool usePosition, Vector3 position,
|
||||
bool useNormal, Vector3 normal,
|
||||
bool useTangent, Vector3 tangent
|
||||
)
|
||||
{
|
||||
var useSparse =
|
||||
(usePosition && position != Vector3.zero)
|
||||
|| (useNormal && normal != Vector3.zero)
|
||||
|| (useTangent && tangent != Vector3.zero)
|
||||
;
|
||||
return useSparse;
|
||||
}
|
||||
|
||||
static gltfMorphTarget ExportMorphTarget(glTF gltf, int bufferIndex,
|
||||
Mesh mesh, int j,
|
||||
bool useSparseAccessorForMorphTarget)
|
||||
{
|
||||
var blendShapeVertices = mesh.vertices;
|
||||
var usePosition = blendShapeVertices != null && blendShapeVertices.Length > 0;
|
||||
|
||||
var blendShapeNormals = mesh.normals;
|
||||
var useNormal = usePosition && blendShapeNormals != null && blendShapeNormals.Length == blendShapeVertices.Length;
|
||||
|
||||
var blendShapeTangents = mesh.tangents.Select(y => (Vector3)y).ToArray();
|
||||
//var useTangent = usePosition && blendShapeTangents != null && blendShapeTangents.Length == blendShapeVertices.Length;
|
||||
var useTangent = false;
|
||||
|
||||
var frameCount = mesh.GetBlendShapeFrameCount(j);
|
||||
mesh.GetBlendShapeFrameVertices(j, frameCount - 1, blendShapeVertices, blendShapeNormals, null);
|
||||
|
||||
var blendShapePositionAccessorIndex = -1;
|
||||
var blendShapeNormalAccessorIndex = -1;
|
||||
var blendShapeTangentAccessorIndex = -1;
|
||||
if (useSparseAccessorForMorphTarget)
|
||||
{
|
||||
var accessorCount = blendShapeVertices.Length;
|
||||
var sparseIndices = Enumerable.Range(0, blendShapeVertices.Length)
|
||||
.Where(x => UseSparse(
|
||||
usePosition, blendShapeVertices[x],
|
||||
useNormal, blendShapeNormals[x],
|
||||
useTangent, blendShapeTangents[x]))
|
||||
.ToArray()
|
||||
;
|
||||
|
||||
if (sparseIndices.Length == 0)
|
||||
{
|
||||
usePosition = false;
|
||||
useNormal = false;
|
||||
useTangent = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogFormat("Sparse {0}/{1}", sparseIndices.Length, mesh.vertexCount);
|
||||
}
|
||||
/*
|
||||
var vertexSize = 12;
|
||||
if (useNormal) vertexSize += 12;
|
||||
if (useTangent) vertexSize += 24;
|
||||
var sparseBytes = (4 + vertexSize) * sparseIndices.Length;
|
||||
var fullBytes = (vertexSize) * blendShapeVertices.Length;
|
||||
Debug.LogFormat("Export sparse: {0}/{1}bytes({2}%)",
|
||||
sparseBytes, fullBytes, (int)((float)sparseBytes / fullBytes)
|
||||
);
|
||||
*/
|
||||
|
||||
var sparseIndicesViewIndex = -1;
|
||||
if (usePosition)
|
||||
{
|
||||
sparseIndicesViewIndex = gltf.ExtendBufferAndGetViewIndex(bufferIndex, sparseIndices);
|
||||
|
||||
blendShapeVertices = sparseIndices.Select(x => blendShapeVertices[x].ReverseZ()).ToArray();
|
||||
blendShapePositionAccessorIndex = gltf.ExtendSparseBufferAndGetAccessorIndex(bufferIndex, accessorCount,
|
||||
blendShapeVertices,
|
||||
sparseIndices, sparseIndicesViewIndex,
|
||||
glBufferTarget.ARRAY_BUFFER);
|
||||
}
|
||||
|
||||
if (useNormal)
|
||||
{
|
||||
blendShapeNormals = sparseIndices.Select(x => blendShapeNormals[x].ReverseZ()).ToArray();
|
||||
blendShapeNormalAccessorIndex = gltf.ExtendSparseBufferAndGetAccessorIndex(bufferIndex, accessorCount,
|
||||
blendShapeNormals,
|
||||
sparseIndices, sparseIndicesViewIndex,
|
||||
glBufferTarget.ARRAY_BUFFER);
|
||||
}
|
||||
|
||||
if (useTangent)
|
||||
{
|
||||
blendShapeTangents = sparseIndices.Select(x => blendShapeTangents[x].ReverseZ()).ToArray();
|
||||
blendShapeTangentAccessorIndex = gltf.ExtendSparseBufferAndGetAccessorIndex(bufferIndex, accessorCount,
|
||||
blendShapeTangents, sparseIndices, sparseIndicesViewIndex,
|
||||
glBufferTarget.ARRAY_BUFFER);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < blendShapeVertices.Length; ++i) blendShapeVertices[i] = blendShapeVertices[i].ReverseZ();
|
||||
if (usePosition)
|
||||
{
|
||||
blendShapePositionAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex,
|
||||
blendShapeVertices,
|
||||
glBufferTarget.ARRAY_BUFFER);
|
||||
}
|
||||
|
||||
if (useNormal)
|
||||
{
|
||||
for (int i = 0; i < blendShapeNormals.Length; ++i) blendShapeNormals[i] = blendShapeNormals[i].ReverseZ();
|
||||
blendShapeNormalAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex,
|
||||
blendShapeNormals,
|
||||
glBufferTarget.ARRAY_BUFFER);
|
||||
}
|
||||
|
||||
if (useTangent)
|
||||
{
|
||||
for (int i = 0; i < blendShapeTangents.Length; ++i) blendShapeTangents[i] = blendShapeTangents[i].ReverseZ();
|
||||
blendShapeTangentAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex,
|
||||
blendShapeTangents,
|
||||
glBufferTarget.ARRAY_BUFFER);
|
||||
}
|
||||
}
|
||||
|
||||
if (blendShapePositionAccessorIndex != -1)
|
||||
{
|
||||
gltf.accessors[blendShapePositionAccessorIndex].min = blendShapeVertices.Aggregate(blendShapeVertices[0], (a, b) => new Vector3(Mathf.Min(a.x, b.x), Math.Min(a.y, b.y), Mathf.Min(a.z, b.z))).ToArray();
|
||||
gltf.accessors[blendShapePositionAccessorIndex].max = blendShapeVertices.Aggregate(blendShapeVertices[0], (a, b) => new Vector3(Mathf.Max(a.x, b.x), Math.Max(a.y, b.y), Mathf.Max(a.z, b.z))).ToArray();
|
||||
}
|
||||
|
||||
return new gltfMorphTarget
|
||||
{
|
||||
POSITION = blendShapePositionAccessorIndex,
|
||||
NORMAL = blendShapeNormalAccessorIndex,
|
||||
TANGENT = blendShapeTangentAccessorIndex,
|
||||
};
|
||||
}
|
||||
|
||||
public static void ExportMeshes(glTF gltf, int bufferIndex,
|
||||
List<MeshWithRenderer> unityMeshes, List<Material> unityMaterials,
|
||||
bool useSparseAccessorForMorphTarget)
|
||||
{
|
||||
for (int i = 0; i < unityMeshes.Count; ++i)
|
||||
{
|
||||
var x = unityMeshes[i];
|
||||
var mesh = x.Mesh;
|
||||
var materials = x.Rendererer.sharedMaterials;
|
||||
|
||||
var gltfMesh = ExportPrimitives(gltf, bufferIndex,
|
||||
x.Rendererer.name,
|
||||
mesh, materials, unityMaterials);
|
||||
|
||||
for (int j = 0; j < mesh.blendShapeCount; ++j)
|
||||
{
|
||||
var morphTarget = ExportMorphTarget(gltf, bufferIndex,
|
||||
mesh, j,
|
||||
useSparseAccessorForMorphTarget);
|
||||
|
||||
//
|
||||
// all primitive has same blendShape
|
||||
//
|
||||
for (int k = 0; k < gltfMesh.primitives.Count; ++k)
|
||||
{
|
||||
gltfMesh.primitives[k].targets.Add(morphTarget);
|
||||
gltfMesh.primitives[k].extras.targetNames.Add(mesh.GetBlendShapeName(j));
|
||||
}
|
||||
}
|
||||
|
||||
gltf.meshes.Add(gltfMesh);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,13 +1,13 @@
|
|||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public class MeshWithMaterials
|
||||
{
|
||||
public Mesh Mesh;
|
||||
public Material[] Materials;
|
||||
public List<Renderer> Renderers=new List<Renderer>(); // SkinnedMeshRenderer or MeshRenderer
|
||||
}
|
||||
}
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public class MeshWithMaterials
|
||||
{
|
||||
public Mesh Mesh;
|
||||
public Material[] Materials;
|
||||
public List<Renderer> Renderers=new List<Renderer>(); // SkinnedMeshRenderer or MeshRenderer
|
||||
}
|
||||
}
|
||||
|
|
@ -1,203 +1,203 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public static class NodeImporter
|
||||
{
|
||||
public static GameObject ImportNode(glTFNode node)
|
||||
{
|
||||
var nodeName = node.name;
|
||||
if (!string.IsNullOrEmpty(nodeName) && nodeName.Contains("/"))
|
||||
{
|
||||
Debug.LogWarningFormat("node {0} contains /. replace _", node.name);
|
||||
nodeName = nodeName.Replace("/", "_");
|
||||
}
|
||||
var go = new GameObject(nodeName);
|
||||
|
||||
//
|
||||
// transform
|
||||
//
|
||||
if (node.translation != null && node.translation.Length > 0)
|
||||
{
|
||||
go.transform.localPosition = new Vector3(
|
||||
node.translation[0],
|
||||
node.translation[1],
|
||||
node.translation[2]);
|
||||
}
|
||||
if (node.rotation != null && node.rotation.Length > 0)
|
||||
{
|
||||
go.transform.localRotation = new Quaternion(
|
||||
node.rotation[0],
|
||||
node.rotation[1],
|
||||
node.rotation[2],
|
||||
node.rotation[3]);
|
||||
}
|
||||
if (node.scale != null && node.scale.Length > 0)
|
||||
{
|
||||
go.transform.localScale = new Vector3(
|
||||
node.scale[0],
|
||||
node.scale[1],
|
||||
node.scale[2]);
|
||||
}
|
||||
if (node.matrix != null && node.matrix.Length > 0)
|
||||
{
|
||||
var m = UnityExtensions.MatrixFromArray(node.matrix);
|
||||
go.transform.localRotation = m.ExtractRotation();
|
||||
go.transform.localPosition = m.ExtractPosition();
|
||||
go.transform.localScale = m.ExtractScale();
|
||||
}
|
||||
return go;
|
||||
}
|
||||
|
||||
public class TransformWithSkin
|
||||
{
|
||||
public Transform Transform;
|
||||
public GameObject GameObject { get { return Transform.gameObject; } }
|
||||
public int? SkinIndex;
|
||||
}
|
||||
|
||||
public static TransformWithSkin BuildHierarchy(ImporterContext context, int i)
|
||||
{
|
||||
var go = context.Nodes[i].gameObject;
|
||||
if (string.IsNullOrEmpty(go.name))
|
||||
{
|
||||
go.name = string.Format("node{0:000}", i);
|
||||
}
|
||||
|
||||
var nodeWithSkin = new TransformWithSkin
|
||||
{
|
||||
Transform = go.transform,
|
||||
};
|
||||
|
||||
//
|
||||
// build hierachy
|
||||
//
|
||||
var node = context.GLTF.nodes[i];
|
||||
if (node.children != null)
|
||||
{
|
||||
foreach (var child in node.children)
|
||||
{
|
||||
context.Nodes[child].transform.SetParent(context.Nodes[i].transform,
|
||||
false // node has local transform
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// attach mesh
|
||||
//
|
||||
if (node.mesh != -1)
|
||||
{
|
||||
var mesh = context.Meshes[node.mesh];
|
||||
if (mesh.Mesh.blendShapeCount == 0 && node.skin == -1)
|
||||
{
|
||||
// without blendshape and bone skinning
|
||||
var filter = go.AddComponent<MeshFilter>();
|
||||
filter.sharedMesh = mesh.Mesh;
|
||||
var renderer = go.AddComponent<MeshRenderer>();
|
||||
renderer.sharedMaterials = mesh.Materials;
|
||||
// invisible in loading
|
||||
renderer.enabled = false;
|
||||
mesh.Renderers.Add(renderer);
|
||||
}
|
||||
else
|
||||
{
|
||||
var renderer = go.AddComponent<SkinnedMeshRenderer>();
|
||||
|
||||
if (node.skin != -1)
|
||||
{
|
||||
nodeWithSkin.SkinIndex = node.skin;
|
||||
}
|
||||
|
||||
renderer.sharedMesh = mesh.Mesh;
|
||||
renderer.sharedMaterials = mesh.Materials;
|
||||
// invisible in loading
|
||||
renderer.enabled = false;
|
||||
mesh.Renderers.Add(renderer);
|
||||
}
|
||||
}
|
||||
|
||||
return nodeWithSkin;
|
||||
}
|
||||
|
||||
//
|
||||
// fix node's coordinate. z-back to z-forward
|
||||
//
|
||||
public static void FixCoordinate(ImporterContext context, List<TransformWithSkin> nodes)
|
||||
{
|
||||
var globalTransformMap = nodes.ToDictionary(x => x.Transform, x => new PosRot
|
||||
{
|
||||
Position = x.Transform.position,
|
||||
Rotation = x.Transform.rotation,
|
||||
});
|
||||
foreach (var x in context.GLTF.rootnodes)
|
||||
{
|
||||
// fix nodes coordinate
|
||||
// reverse Z in global
|
||||
var t = nodes[x].Transform;
|
||||
//t.SetParent(root.transform, false);
|
||||
|
||||
foreach (var transform in t.Traverse())
|
||||
{
|
||||
var g = globalTransformMap[transform];
|
||||
transform.position = g.Position.ReverseZ();
|
||||
transform.rotation = g.Rotation.ReverseZ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetupSkinning(ImporterContext context, List<TransformWithSkin> nodes, int i)
|
||||
{
|
||||
var x = nodes[i];
|
||||
var skinnedMeshRenderer = x.Transform.GetComponent<SkinnedMeshRenderer>();
|
||||
if (skinnedMeshRenderer != null)
|
||||
{
|
||||
var mesh = skinnedMeshRenderer.sharedMesh;
|
||||
if (x.SkinIndex.HasValue)
|
||||
{
|
||||
if (mesh == null) throw new Exception();
|
||||
if (skinnedMeshRenderer == null) throw new Exception();
|
||||
|
||||
if (x.SkinIndex.Value < context.GLTF.skins.Count)
|
||||
{
|
||||
var skin = context.GLTF.skins[x.SkinIndex.Value];
|
||||
|
||||
skinnedMeshRenderer.sharedMesh = null;
|
||||
|
||||
var joints = skin.joints.Select(y => nodes[y].Transform).ToArray();
|
||||
skinnedMeshRenderer.bones = joints;
|
||||
|
||||
if (skin.skeleton >= 0 && skin.skeleton < nodes.Count)
|
||||
{
|
||||
skinnedMeshRenderer.rootBone = nodes[skin.skeleton].Transform;
|
||||
}
|
||||
|
||||
if (skin.inverseBindMatrices != -1)
|
||||
{
|
||||
// BlendShape only ?
|
||||
#if false
|
||||
// https://docs.unity3d.com/ScriptReference/Mesh-bindposes.html
|
||||
var hipsParent = nodes[0].Transform;
|
||||
var calculatedBindPoses = joints.Select(y => y.worldToLocalMatrix * hipsParent.localToWorldMatrix).ToArray();
|
||||
mesh.bindposes = calculatedBindPoses;
|
||||
#else
|
||||
var bindPoses = context.GLTF.GetArrayFromAccessor<Matrix4x4>(skin.inverseBindMatrices)
|
||||
.Select(y => y.ReverseZ())
|
||||
.ToArray()
|
||||
;
|
||||
mesh.bindposes = bindPoses;
|
||||
#endif
|
||||
}
|
||||
|
||||
skinnedMeshRenderer.sharedMesh = mesh;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public static class NodeImporter
|
||||
{
|
||||
public static GameObject ImportNode(glTFNode node)
|
||||
{
|
||||
var nodeName = node.name;
|
||||
if (!string.IsNullOrEmpty(nodeName) && nodeName.Contains("/"))
|
||||
{
|
||||
Debug.LogWarningFormat("node {0} contains /. replace _", node.name);
|
||||
nodeName = nodeName.Replace("/", "_");
|
||||
}
|
||||
var go = new GameObject(nodeName);
|
||||
|
||||
//
|
||||
// transform
|
||||
//
|
||||
if (node.translation != null && node.translation.Length > 0)
|
||||
{
|
||||
go.transform.localPosition = new Vector3(
|
||||
node.translation[0],
|
||||
node.translation[1],
|
||||
node.translation[2]);
|
||||
}
|
||||
if (node.rotation != null && node.rotation.Length > 0)
|
||||
{
|
||||
go.transform.localRotation = new Quaternion(
|
||||
node.rotation[0],
|
||||
node.rotation[1],
|
||||
node.rotation[2],
|
||||
node.rotation[3]);
|
||||
}
|
||||
if (node.scale != null && node.scale.Length > 0)
|
||||
{
|
||||
go.transform.localScale = new Vector3(
|
||||
node.scale[0],
|
||||
node.scale[1],
|
||||
node.scale[2]);
|
||||
}
|
||||
if (node.matrix != null && node.matrix.Length > 0)
|
||||
{
|
||||
var m = UnityExtensions.MatrixFromArray(node.matrix);
|
||||
go.transform.localRotation = m.ExtractRotation();
|
||||
go.transform.localPosition = m.ExtractPosition();
|
||||
go.transform.localScale = m.ExtractScale();
|
||||
}
|
||||
return go;
|
||||
}
|
||||
|
||||
public class TransformWithSkin
|
||||
{
|
||||
public Transform Transform;
|
||||
public GameObject GameObject { get { return Transform.gameObject; } }
|
||||
public int? SkinIndex;
|
||||
}
|
||||
|
||||
public static TransformWithSkin BuildHierarchy(ImporterContext context, int i)
|
||||
{
|
||||
var go = context.Nodes[i].gameObject;
|
||||
if (string.IsNullOrEmpty(go.name))
|
||||
{
|
||||
go.name = string.Format("node{0:000}", i);
|
||||
}
|
||||
|
||||
var nodeWithSkin = new TransformWithSkin
|
||||
{
|
||||
Transform = go.transform,
|
||||
};
|
||||
|
||||
//
|
||||
// build hierachy
|
||||
//
|
||||
var node = context.GLTF.nodes[i];
|
||||
if (node.children != null)
|
||||
{
|
||||
foreach (var child in node.children)
|
||||
{
|
||||
context.Nodes[child].transform.SetParent(context.Nodes[i].transform,
|
||||
false // node has local transform
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// attach mesh
|
||||
//
|
||||
if (node.mesh != -1)
|
||||
{
|
||||
var mesh = context.Meshes[node.mesh];
|
||||
if (mesh.Mesh.blendShapeCount == 0 && node.skin == -1)
|
||||
{
|
||||
// without blendshape and bone skinning
|
||||
var filter = go.AddComponent<MeshFilter>();
|
||||
filter.sharedMesh = mesh.Mesh;
|
||||
var renderer = go.AddComponent<MeshRenderer>();
|
||||
renderer.sharedMaterials = mesh.Materials;
|
||||
// invisible in loading
|
||||
renderer.enabled = false;
|
||||
mesh.Renderers.Add(renderer);
|
||||
}
|
||||
else
|
||||
{
|
||||
var renderer = go.AddComponent<SkinnedMeshRenderer>();
|
||||
|
||||
if (node.skin != -1)
|
||||
{
|
||||
nodeWithSkin.SkinIndex = node.skin;
|
||||
}
|
||||
|
||||
renderer.sharedMesh = mesh.Mesh;
|
||||
renderer.sharedMaterials = mesh.Materials;
|
||||
// invisible in loading
|
||||
renderer.enabled = false;
|
||||
mesh.Renderers.Add(renderer);
|
||||
}
|
||||
}
|
||||
|
||||
return nodeWithSkin;
|
||||
}
|
||||
|
||||
//
|
||||
// fix node's coordinate. z-back to z-forward
|
||||
//
|
||||
public static void FixCoordinate(ImporterContext context, List<TransformWithSkin> nodes)
|
||||
{
|
||||
var globalTransformMap = nodes.ToDictionary(x => x.Transform, x => new PosRot
|
||||
{
|
||||
Position = x.Transform.position,
|
||||
Rotation = x.Transform.rotation,
|
||||
});
|
||||
foreach (var x in context.GLTF.rootnodes)
|
||||
{
|
||||
// fix nodes coordinate
|
||||
// reverse Z in global
|
||||
var t = nodes[x].Transform;
|
||||
//t.SetParent(root.transform, false);
|
||||
|
||||
foreach (var transform in t.Traverse())
|
||||
{
|
||||
var g = globalTransformMap[transform];
|
||||
transform.position = g.Position.ReverseZ();
|
||||
transform.rotation = g.Rotation.ReverseZ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetupSkinning(ImporterContext context, List<TransformWithSkin> nodes, int i)
|
||||
{
|
||||
var x = nodes[i];
|
||||
var skinnedMeshRenderer = x.Transform.GetComponent<SkinnedMeshRenderer>();
|
||||
if (skinnedMeshRenderer != null)
|
||||
{
|
||||
var mesh = skinnedMeshRenderer.sharedMesh;
|
||||
if (x.SkinIndex.HasValue)
|
||||
{
|
||||
if (mesh == null) throw new Exception();
|
||||
if (skinnedMeshRenderer == null) throw new Exception();
|
||||
|
||||
if (x.SkinIndex.Value < context.GLTF.skins.Count)
|
||||
{
|
||||
var skin = context.GLTF.skins[x.SkinIndex.Value];
|
||||
|
||||
skinnedMeshRenderer.sharedMesh = null;
|
||||
|
||||
var joints = skin.joints.Select(y => nodes[y].Transform).ToArray();
|
||||
skinnedMeshRenderer.bones = joints;
|
||||
|
||||
if (skin.skeleton >= 0 && skin.skeleton < nodes.Count)
|
||||
{
|
||||
skinnedMeshRenderer.rootBone = nodes[skin.skeleton].Transform;
|
||||
}
|
||||
|
||||
if (skin.inverseBindMatrices != -1)
|
||||
{
|
||||
// BlendShape only ?
|
||||
#if false
|
||||
// https://docs.unity3d.com/ScriptReference/Mesh-bindposes.html
|
||||
var hipsParent = nodes[0].Transform;
|
||||
var calculatedBindPoses = joints.Select(y => y.worldToLocalMatrix * hipsParent.localToWorldMatrix).ToArray();
|
||||
mesh.bindposes = calculatedBindPoses;
|
||||
#else
|
||||
var bindPoses = context.GLTF.GetArrayFromAccessor<Matrix4x4>(skin.inverseBindMatrices)
|
||||
.Select(y => y.ReverseZ())
|
||||
.ToArray()
|
||||
;
|
||||
mesh.bindposes = bindPoses;
|
||||
#endif
|
||||
}
|
||||
|
||||
skinnedMeshRenderer.sharedMesh = mesh;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,133 +1,133 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
|
||||
namespace UniGLTF.ShaderPropExporter
|
||||
{
|
||||
public class PreExportShadersAttribute : Attribute { }
|
||||
public class PreExportShaderAttribute : Attribute { }
|
||||
|
||||
public struct SupportedShader
|
||||
{
|
||||
public string TargetFolder;
|
||||
public string ShaderName;
|
||||
|
||||
public SupportedShader(string targetFolder, string shaderName)
|
||||
{
|
||||
TargetFolder = targetFolder;
|
||||
ShaderName = shaderName;
|
||||
}
|
||||
}
|
||||
|
||||
public static partial class PreShaderPropExporter
|
||||
{
|
||||
const string TARGET_FOLDER = "UniGLTF/Core/Scripts";
|
||||
|
||||
#pragma warning disable 414
|
||||
[PreExportShaders]
|
||||
static SupportedShader[] SupportedShaders = new SupportedShader[]
|
||||
{
|
||||
new SupportedShader(TARGET_FOLDER, "Standard"),
|
||||
new SupportedShader(TARGET_FOLDER, "Unlit/Color"),
|
||||
new SupportedShader(TARGET_FOLDER, "Unlit/Texture"),
|
||||
new SupportedShader(TARGET_FOLDER, "Unlit/Transparent"),
|
||||
new SupportedShader(TARGET_FOLDER, "Unlit/Transparent Cutout"),
|
||||
new SupportedShader(TARGET_FOLDER, "UniGLTF/UniUnlit"),
|
||||
};
|
||||
#pragma warning restore 414
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[MenuItem(UniGLTFVersion.UNIGLTF_VERSION + "/PreExport ShaderProps")]
|
||||
public static void PreExport()
|
||||
{
|
||||
foreach (var fi in typeof(PreShaderPropExporter).GetFields(
|
||||
BindingFlags.Static
|
||||
| BindingFlags.Public
|
||||
| BindingFlags.NonPublic))
|
||||
{
|
||||
var attr = fi.GetCustomAttributes(true).FirstOrDefault(y => y is PreExportShadersAttribute);
|
||||
if (attr != null)
|
||||
{
|
||||
var supportedShaders = fi.GetValue(null) as SupportedShader[];
|
||||
foreach (var supported in supportedShaders)
|
||||
{
|
||||
PreExport(supported);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static string EscapeShaderName(string name)
|
||||
{
|
||||
return name.Replace("/", "_").Replace(" ", "_");
|
||||
}
|
||||
|
||||
static UnityPath GetExportDir(string target)
|
||||
{
|
||||
foreach (var x in UnityPath.FromUnityPath("Assets").TravserseDir())
|
||||
{
|
||||
if (x.Value.EndsWith(target))
|
||||
{
|
||||
var dir = x.Child("PreExportShaderProps");
|
||||
dir.EnsureFolder();
|
||||
return dir;
|
||||
}
|
||||
}
|
||||
throw new Exception(target + " not found");
|
||||
}
|
||||
|
||||
static void PreExport(SupportedShader supportedShader)
|
||||
{
|
||||
var path = GetExportDir(supportedShader.TargetFolder).Child(EscapeShaderName(supportedShader.ShaderName) + ".cs");
|
||||
Debug.LogFormat("PreExport: {0}", path.FullPath);
|
||||
|
||||
var shader = Shader.Find(supportedShader.ShaderName);
|
||||
var props = ShaderProps.FromShader(shader);
|
||||
|
||||
File.WriteAllText(path.FullPath, props.ToString(shader.name));
|
||||
}
|
||||
#endif
|
||||
|
||||
#region Runtime
|
||||
static Dictionary<string, ShaderProps> m_shaderPropMap;
|
||||
|
||||
public static ShaderProps GetPropsForSupportedShader(string shaderName)
|
||||
{
|
||||
if (m_shaderPropMap == null)
|
||||
{
|
||||
m_shaderPropMap = new Dictionary<string, ShaderProps>();
|
||||
foreach (var prop in typeof(PreShaderPropExporter).GetProperties(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic))
|
||||
{
|
||||
if (prop.GetCustomAttributes(typeof(PreExportShaderAttribute), true).Any())
|
||||
{
|
||||
var kv = (KeyValuePair<string, ShaderProps>)prop.GetValue(null, null);
|
||||
m_shaderPropMap.Add(kv.Key, kv.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ShaderProps props;
|
||||
if (m_shaderPropMap.TryGetValue(shaderName, out props))
|
||||
{
|
||||
return props;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
// fallback
|
||||
Debug.LogWarningFormat("{0} is not predefined shader. Use ShaderUtil", shaderName);
|
||||
var shader = Shader.Find(shaderName);
|
||||
return ShaderProps.FromShader(shader);
|
||||
#else
|
||||
return null;
|
||||
#endif
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
|
||||
namespace UniGLTF.ShaderPropExporter
|
||||
{
|
||||
public class PreExportShadersAttribute : Attribute { }
|
||||
public class PreExportShaderAttribute : Attribute { }
|
||||
|
||||
public struct SupportedShader
|
||||
{
|
||||
public string TargetFolder;
|
||||
public string ShaderName;
|
||||
|
||||
public SupportedShader(string targetFolder, string shaderName)
|
||||
{
|
||||
TargetFolder = targetFolder;
|
||||
ShaderName = shaderName;
|
||||
}
|
||||
}
|
||||
|
||||
public static partial class PreShaderPropExporter
|
||||
{
|
||||
const string TARGET_FOLDER = "UniGLTF/Core/Scripts";
|
||||
|
||||
#pragma warning disable 414
|
||||
[PreExportShaders]
|
||||
static SupportedShader[] SupportedShaders = new SupportedShader[]
|
||||
{
|
||||
new SupportedShader(TARGET_FOLDER, "Standard"),
|
||||
new SupportedShader(TARGET_FOLDER, "Unlit/Color"),
|
||||
new SupportedShader(TARGET_FOLDER, "Unlit/Texture"),
|
||||
new SupportedShader(TARGET_FOLDER, "Unlit/Transparent"),
|
||||
new SupportedShader(TARGET_FOLDER, "Unlit/Transparent Cutout"),
|
||||
new SupportedShader(TARGET_FOLDER, "UniGLTF/UniUnlit"),
|
||||
};
|
||||
#pragma warning restore 414
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[MenuItem(UniGLTFVersion.UNIGLTF_VERSION + "/PreExport ShaderProps")]
|
||||
public static void PreExport()
|
||||
{
|
||||
foreach (var fi in typeof(PreShaderPropExporter).GetFields(
|
||||
BindingFlags.Static
|
||||
| BindingFlags.Public
|
||||
| BindingFlags.NonPublic))
|
||||
{
|
||||
var attr = fi.GetCustomAttributes(true).FirstOrDefault(y => y is PreExportShadersAttribute);
|
||||
if (attr != null)
|
||||
{
|
||||
var supportedShaders = fi.GetValue(null) as SupportedShader[];
|
||||
foreach (var supported in supportedShaders)
|
||||
{
|
||||
PreExport(supported);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static string EscapeShaderName(string name)
|
||||
{
|
||||
return name.Replace("/", "_").Replace(" ", "_");
|
||||
}
|
||||
|
||||
static UnityPath GetExportDir(string target)
|
||||
{
|
||||
foreach (var x in UnityPath.FromUnityPath("Assets").TravserseDir())
|
||||
{
|
||||
if (x.Value.EndsWith(target))
|
||||
{
|
||||
var dir = x.Child("PreExportShaderProps");
|
||||
dir.EnsureFolder();
|
||||
return dir;
|
||||
}
|
||||
}
|
||||
throw new Exception(target + " not found");
|
||||
}
|
||||
|
||||
static void PreExport(SupportedShader supportedShader)
|
||||
{
|
||||
var path = GetExportDir(supportedShader.TargetFolder).Child(EscapeShaderName(supportedShader.ShaderName) + ".cs");
|
||||
Debug.LogFormat("PreExport: {0}", path.FullPath);
|
||||
|
||||
var shader = Shader.Find(supportedShader.ShaderName);
|
||||
var props = ShaderProps.FromShader(shader);
|
||||
|
||||
File.WriteAllText(path.FullPath, props.ToString(shader.name));
|
||||
}
|
||||
#endif
|
||||
|
||||
#region Runtime
|
||||
static Dictionary<string, ShaderProps> m_shaderPropMap;
|
||||
|
||||
public static ShaderProps GetPropsForSupportedShader(string shaderName)
|
||||
{
|
||||
if (m_shaderPropMap == null)
|
||||
{
|
||||
m_shaderPropMap = new Dictionary<string, ShaderProps>();
|
||||
foreach (var prop in typeof(PreShaderPropExporter).GetProperties(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic))
|
||||
{
|
||||
if (prop.GetCustomAttributes(typeof(PreExportShaderAttribute), true).Any())
|
||||
{
|
||||
var kv = (KeyValuePair<string, ShaderProps>)prop.GetValue(null, null);
|
||||
m_shaderPropMap.Add(kv.Key, kv.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ShaderProps props;
|
||||
if (m_shaderPropMap.TryGetValue(shaderName, out props))
|
||||
{
|
||||
return props;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
// fallback
|
||||
Debug.LogWarningFormat("{0} is not predefined shader. Use ShaderUtil", shaderName);
|
||||
var shader = Shader.Find(shaderName);
|
||||
return ShaderProps.FromShader(shader);
|
||||
#else
|
||||
return null;
|
||||
#endif
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user