Change directory structures: Move UniGLTF/Core/* -> UniGLTF/*. Remove UniGLTF/Core

This commit is contained in:
yutopp 2018-12-28 21:30:24 +09:00
parent f9e0e26786
commit 216ef2f867
150 changed files with 10492 additions and 10502 deletions

View File

@ -1,10 +0,0 @@
fileFormatVersion: 2
guid: d2d37db807d5f0946b5d264a870ac053
folderAsset: yes
timeCreated: 1517139118
licenseType: Free
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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);
}
}
}
}

View File

@ -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);
}
}
}

View File

@ -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));
}
}
}
}

View File

@ -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

View File

@ -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();
}
};
}
}
}

View File

@ -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));
}
}
}

View File

@ -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();
}
}
}

View File

@ -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;
}
}
}

View File

@ -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>();
}
}
}

View File

@ -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;
}
}
}

View File

@ -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);
}
}
}

View File

@ -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();
}
}
}

View File

@ -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);
}
}
}
}

View File

@ -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> { }
}

View File

@ -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> { }
}

View File

@ -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();
}
}
}
}

View File

@ -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> { }
}

View File

@ -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();
}
}
}

View File

@ -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();
}
}
}

View File

@ -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();
}
}
}

View File

@ -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,
}
}

View File

@ -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;
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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;
}
}

View File

@ -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
};
}
}
}

View File

@ -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);
}
}
}
}

View File

@ -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);
}
}
}
}
}

View File

@ -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);
}
}
}
}

View File

@ -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);
}
}
}

View File

@ -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();
}
}
}
}

View File

@ -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
}
}

View File

@ -1,3 +1,3 @@
fileFormatVersion: 2
guid: 1af21722605d44f58deebfcfca642b32
fileFormatVersion: 2
guid: 1af21722605d44f58deebfcfca642b32
timeCreated: 1537442711

View File

@ -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
}
}

View File

@ -1,3 +1,3 @@
fileFormatVersion: 2
guid: 015ae41bf6cb4428b8257ead79772908
fileFormatVersion: 2
guid: 015ae41bf6cb4428b8257ead79772908
timeCreated: 1537443293

View File

@ -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();
}
}
}
}
}

View File

@ -1,3 +1,3 @@
fileFormatVersion: 2
guid: d602384685dd4f179350052013659720
fileFormatVersion: 2
guid: d602384685dd4f179350052013659720
timeCreated: 1537445972

View File

@ -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
}
}

View File

@ -1,3 +1,3 @@
fileFormatVersion: 2
guid: e27ef4fb768e49f591c2bb5eadd3b19b
fileFormatVersion: 2
guid: e27ef4fb768e49f591c2bb5eadd3b19b
timeCreated: 1537442737

View File

@ -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;
}
}
}
}

View File

@ -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("\\", "/");
}
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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);
}
}
}
}

View File

@ -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
}
}

View File

@ -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;
}
}
}
}
}
}

View File

@ -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