mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-08-26 12:55:18 -05:00
Merge pull request #755 from ousttrue/feature/glb_coordinate
gltf の読み書きで反転軸を指定できるようにする
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
{
|
||||
"name": "UniGLTF.Editor",
|
||||
"references": [
|
||||
"UniGLTF"
|
||||
"UniGLTF",
|
||||
"MeshUtility.Editor"
|
||||
],
|
||||
"optionalUnityReferences": [],
|
||||
"includePlatforms": [
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.IO;
|
||||
#if false
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -21,8 +22,10 @@ namespace UniGLTF
|
||||
//
|
||||
// load into scene
|
||||
//
|
||||
var context = new ImporterContext();
|
||||
context.Load(path);
|
||||
var parser = new GltfParser();
|
||||
parser.ParsePath(path);
|
||||
var context = new ImporterContext(parser);
|
||||
context.Load();
|
||||
context.ShowMeshes();
|
||||
Selection.activeGameObject = context.Root;
|
||||
}
|
||||
@@ -49,3 +52,4 @@ namespace UniGLTF
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
8
Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter.meta
Normal file
8
Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 552c42899d5f1664b8fba3faef53f3eb
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,101 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Experimental.AssetImporters;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
[ScriptedImporter(1, "glb")]
|
||||
public class GltfScriptedImporter : ScriptedImporter
|
||||
{
|
||||
[SerializeField]
|
||||
Axises m_reverseAxis = default;
|
||||
|
||||
const string TextureDirName = "Textures";
|
||||
const string MaterialDirName = "Materials";
|
||||
|
||||
public override void OnImportAsset(AssetImportContext ctx)
|
||||
{
|
||||
Debug.Log("OnImportAsset to " + ctx.assetPath);
|
||||
|
||||
try
|
||||
{
|
||||
// Parse
|
||||
var parser = new GltfParser();
|
||||
parser.ParsePath(ctx.assetPath);
|
||||
|
||||
// Build Unity Model
|
||||
var externalObjectMap = GetExternalObjectMap()
|
||||
.Select(kv => (kv.Key.name, kv.Value))
|
||||
;
|
||||
var context = new ImporterContext(parser, externalObjectMap);
|
||||
context.InvertAxis = m_reverseAxis;
|
||||
context.Load();
|
||||
context.ShowMeshes();
|
||||
|
||||
// Texture
|
||||
foreach (var info in context.TextureFactory.Textures)
|
||||
{
|
||||
if (!info.IsUsed)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (!info.IsExternal)
|
||||
{
|
||||
var texture = info.Texture;
|
||||
ctx.AddObjectToAsset(texture.name, texture);
|
||||
}
|
||||
}
|
||||
|
||||
// Material
|
||||
foreach (var info in context.MaterialFactory.Materials)
|
||||
{
|
||||
if (!info.UseExternal)
|
||||
{
|
||||
var material = info.Asset;
|
||||
ctx.AddObjectToAsset(material.name, material);
|
||||
}
|
||||
}
|
||||
|
||||
// Mesh
|
||||
foreach (var mesh in context.Meshes.Select(x => x.Mesh))
|
||||
{
|
||||
ctx.AddObjectToAsset(mesh.name, mesh);
|
||||
}
|
||||
|
||||
// Animation
|
||||
foreach (var clip in context.AnimationClips)
|
||||
{
|
||||
ctx.AddObjectToAsset(clip.name, clip);
|
||||
}
|
||||
|
||||
// Root
|
||||
ctx.AddObjectToAsset(context.Root.name, context.Root);
|
||||
ctx.SetMainObject(context.Root);
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Debug.LogError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void ExtractMaterialsAndTextures()
|
||||
{
|
||||
this.ExtractTextures(TextureDirName, () =>
|
||||
{
|
||||
this.ExtractAssets<UnityEngine.Material>(MaterialDirName, ".mat");
|
||||
AssetDatabase.ImportAsset(assetPath, ImportAssetOptions.ForceUpdate);
|
||||
});
|
||||
}
|
||||
|
||||
public void SetExternalUnityObject<T>(UnityEditor.AssetImporter.SourceAssetIdentifier sourceAssetIdentifier, T obj) where T : UnityEngine.Object
|
||||
{
|
||||
this.AddRemap(sourceAssetIdentifier, obj);
|
||||
AssetDatabase.WriteImportSettingsIfDirty(this.assetPath);
|
||||
AssetDatabase.ImportAsset(this.assetPath, ImportAssetOptions.ForceUpdate);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5f9566aa8f690614f872fc63691397e9
|
||||
guid: aecd2106718f2444db3ca21345da2cef
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
@@ -0,0 +1,137 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Experimental.AssetImporters;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
[CustomEditor(typeof(GltfScriptedImporter))]
|
||||
public class GltfScriptedImporterEditorGUI : ScriptedImporterEditor
|
||||
{
|
||||
GltfScriptedImporter m_importer;
|
||||
GltfParser m_parser;
|
||||
|
||||
public override void OnEnable()
|
||||
{
|
||||
m_importer = target as GltfScriptedImporter;
|
||||
m_parser = new GltfParser();
|
||||
m_parser.ParsePath(m_importer.assetPath);
|
||||
}
|
||||
|
||||
enum Tabs
|
||||
{
|
||||
Model,
|
||||
Animation,
|
||||
Materials,
|
||||
}
|
||||
static Tabs s_currentTab;
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
s_currentTab = MeshUtility.TabBar.OnGUI(s_currentTab);
|
||||
GUILayout.Space(10);
|
||||
|
||||
switch (s_currentTab)
|
||||
{
|
||||
case Tabs.Model:
|
||||
base.OnInspectorGUI();
|
||||
break;
|
||||
|
||||
case Tabs.Animation:
|
||||
OnGUIAnimation(m_importer, m_parser);
|
||||
break;
|
||||
|
||||
case Tabs.Materials:
|
||||
OnGUIMaterial(m_importer, m_parser);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static bool s_foldMaterials;
|
||||
static bool s_foldTextures;
|
||||
|
||||
class TmpGuiEnable : IDisposable
|
||||
{
|
||||
bool m_backup;
|
||||
public TmpGuiEnable(bool enable)
|
||||
{
|
||||
m_backup = GUI.enabled;
|
||||
GUI.enabled = enable;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
GUI.enabled = m_backup;
|
||||
}
|
||||
}
|
||||
|
||||
static void OnGUIMaterial(GltfScriptedImporter importer, GltfParser parser)
|
||||
{
|
||||
var canExtract = !importer.GetExternalObjectMap().Any(x => x.Value is Material || x.Value is Texture2D);
|
||||
using (new TmpGuiEnable(canExtract))
|
||||
{
|
||||
if (GUILayout.Button("Extract Materials And Textures ..."))
|
||||
{
|
||||
importer.ExtractMaterialsAndTextures();
|
||||
}
|
||||
}
|
||||
|
||||
// ObjectMap
|
||||
s_foldMaterials = EditorGUILayout.Foldout(s_foldMaterials, "Remapped Materials");
|
||||
if (s_foldMaterials)
|
||||
{
|
||||
DrawRemapGUI<UnityEngine.Material>(importer, parser.GLTF.materials.Select(x => x.name));
|
||||
}
|
||||
|
||||
s_foldTextures = EditorGUILayout.Foldout(s_foldTextures, "Remapped Textures");
|
||||
if (s_foldTextures)
|
||||
{
|
||||
DrawRemapGUI<UnityEngine.Texture2D>(importer, parser.EnumerateTextures().Select(x => x.Name));
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Clear"))
|
||||
{
|
||||
importer.ClearExternalObjects<UnityEngine.Material>();
|
||||
importer.ClearExternalObjects<UnityEngine.Texture2D>();
|
||||
}
|
||||
}
|
||||
|
||||
static void DrawRemapGUI<T>(GltfScriptedImporter importer, IEnumerable<string> names) where T : UnityEngine.Object
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
var map = importer.GetExternalObjectMap()
|
||||
.Select(x => (x.Key.name, x.Value as T))
|
||||
.Where(x => x.Item2 != null)
|
||||
.ToDictionary(x => x.Item1, x => x.Item2)
|
||||
;
|
||||
foreach (var name in names)
|
||||
{
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
throw new System.ArgumentNullException();
|
||||
}
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.PrefixLabel(name);
|
||||
map.TryGetValue(name, out T value);
|
||||
var asset = EditorGUILayout.ObjectField(value, typeof(T), true) as T;
|
||||
if (asset != value)
|
||||
{
|
||||
importer.SetExternalUnityObject(new AssetImporter.SourceAssetIdentifier(value), asset);
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
|
||||
static void OnGUIAnimation(GltfScriptedImporter importer, GltfParser parser)
|
||||
{
|
||||
foreach (var a in parser.GLTF.animations)
|
||||
{
|
||||
GUILayout.Label(a.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d4faa0a7a13c9c1489b5eed3a9575a01
|
||||
guid: 706590752e82d004e99da97aff535f67
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
@@ -0,0 +1,200 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEditor.Experimental.AssetImporters;
|
||||
using UnityEditor;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public static class ScriptedImporterExtension
|
||||
{
|
||||
public static void ClearExternalObjects<T>(this ScriptedImporter importer) where T : UnityEngine.Object
|
||||
{
|
||||
foreach (var extarnalObject in importer.GetExternalObjectMap().Where(x => x.Key.type == typeof(T)))
|
||||
{
|
||||
importer.RemoveRemap(extarnalObject.Key);
|
||||
}
|
||||
|
||||
AssetDatabase.WriteImportSettingsIfDirty(importer.assetPath);
|
||||
AssetDatabase.ImportAsset(importer.assetPath, ImportAssetOptions.ForceUpdate);
|
||||
}
|
||||
|
||||
public static void ClearExtarnalObjects(this ScriptedImporter importer)
|
||||
{
|
||||
foreach (var extarnalObject in importer.GetExternalObjectMap())
|
||||
{
|
||||
importer.RemoveRemap(extarnalObject.Key);
|
||||
}
|
||||
|
||||
AssetDatabase.WriteImportSettingsIfDirty(importer.assetPath);
|
||||
AssetDatabase.ImportAsset(importer.assetPath, ImportAssetOptions.ForceUpdate);
|
||||
}
|
||||
|
||||
private static T GetSubAsset<T>(this ScriptedImporter importer, string assetPath) where T : UnityEngine.Object
|
||||
{
|
||||
return importer.GetSubAssets<T>(assetPath)
|
||||
.FirstOrDefault();
|
||||
}
|
||||
|
||||
public static IEnumerable<T> GetSubAssets<T>(this ScriptedImporter importer, string assetPath) where T : UnityEngine.Object
|
||||
{
|
||||
return AssetDatabase
|
||||
.LoadAllAssetsAtPath(assetPath)
|
||||
.Where(x => AssetDatabase.IsSubAsset(x))
|
||||
.Where(x => x is T)
|
||||
.Select(x => x as T);
|
||||
}
|
||||
|
||||
private static void ExtractFromAsset(UnityEngine.Object subAsset, string destinationPath, bool isForceUpdate)
|
||||
{
|
||||
string assetPath = AssetDatabase.GetAssetPath(subAsset);
|
||||
|
||||
var clone = UnityEngine.Object.Instantiate(subAsset);
|
||||
AssetDatabase.CreateAsset(clone, destinationPath);
|
||||
|
||||
var assetImporter = AssetImporter.GetAtPath(assetPath);
|
||||
assetImporter.AddRemap(new AssetImporter.SourceAssetIdentifier(subAsset), clone);
|
||||
|
||||
if (isForceUpdate)
|
||||
{
|
||||
AssetDatabase.WriteImportSettingsIfDirty(assetPath);
|
||||
AssetDatabase.ImportAsset(assetPath, ImportAssetOptions.ForceUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ExtractAssets<T>(this ScriptedImporter importer, string dirName, string extension) where T : UnityEngine.Object
|
||||
{
|
||||
if (string.IsNullOrEmpty(importer.assetPath))
|
||||
return;
|
||||
|
||||
var subAssets = importer.GetSubAssets<T>(importer.assetPath);
|
||||
|
||||
var path = string.Format("{0}/{1}.{2}",
|
||||
Path.GetDirectoryName(importer.assetPath),
|
||||
Path.GetFileNameWithoutExtension(importer.assetPath),
|
||||
dirName
|
||||
);
|
||||
|
||||
var info = importer.SafeCreateDirectory(path);
|
||||
|
||||
foreach (var asset in subAssets)
|
||||
{
|
||||
ExtractFromAsset(asset, string.Format("{0}/{1}{2}", path, asset.name, extension), false);
|
||||
}
|
||||
}
|
||||
|
||||
struct TextureInfo
|
||||
{
|
||||
public string Path;
|
||||
public bool sRGB;
|
||||
public bool IsNormalMap;
|
||||
}
|
||||
|
||||
class TextureExtractor
|
||||
{
|
||||
GltfParser m_parser;
|
||||
public GltfParser Parser => m_parser;
|
||||
|
||||
public glTF GLTF => m_parser.GLTF;
|
||||
|
||||
public readonly List<TextureInfo> Textures = new List<TextureInfo>();
|
||||
UnityEngine.Texture2D[] m_subAssets;
|
||||
string m_path;
|
||||
|
||||
public TextureExtractor(ScriptedImporter importer)
|
||||
{
|
||||
// parse GLTF
|
||||
m_parser = new GltfParser();
|
||||
m_parser.ParsePath(importer.assetPath);
|
||||
|
||||
m_path = $"{Path.GetDirectoryName(importer.assetPath)}/{Path.GetFileNameWithoutExtension(importer.assetPath)}.Textures";
|
||||
m_subAssets = importer.GetSubAssets<UnityEngine.Texture2D>(importer.assetPath).ToArray();
|
||||
}
|
||||
|
||||
static Regex s_mimeTypeReg = new Regex("image/(?<mime>.*)$");
|
||||
|
||||
public void Extract(GetTextureParam param)
|
||||
{
|
||||
var subAsset = m_subAssets.FirstOrDefault(x => x.name == param.Name);
|
||||
var targetPath = string.Format("{0}/{1}{2}",
|
||||
m_path,
|
||||
param.Name,
|
||||
".png"
|
||||
);
|
||||
File.WriteAllBytes(targetPath, subAsset.EncodeToPNG().ToArray());
|
||||
AssetDatabase.ImportAsset(targetPath);
|
||||
|
||||
Textures.Add(new TextureInfo
|
||||
{
|
||||
Path = targetPath,
|
||||
sRGB = true,
|
||||
IsNormalMap = param.TextureType == GetTextureParam.NORMAL_PROP,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static void ExtractTextures(this ScriptedImporter importer, string dirName, Action onCompleted = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(importer.assetPath))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var path = string.Format("{0}/{1}.{2}",
|
||||
Path.GetDirectoryName(importer.assetPath),
|
||||
Path.GetFileNameWithoutExtension(importer.assetPath),
|
||||
dirName
|
||||
);
|
||||
importer.SafeCreateDirectory(path);
|
||||
|
||||
// Reload Model
|
||||
var extractor = new TextureExtractor(importer);
|
||||
|
||||
foreach (var material in extractor.GLTF.materials)
|
||||
{
|
||||
foreach (var x in extractor.Parser.EnumerateTextures(material))
|
||||
{
|
||||
extractor.Extract(x);
|
||||
}
|
||||
}
|
||||
|
||||
EditorApplication.delayCall += () =>
|
||||
{
|
||||
foreach (var extracted in extractor.Textures)
|
||||
{
|
||||
// TextureImporter
|
||||
var targetTextureImporter = AssetImporter.GetAtPath(extracted.Path) as TextureImporter;
|
||||
targetTextureImporter.sRGBTexture = extracted.sRGB;
|
||||
if (extracted.IsNormalMap)
|
||||
{
|
||||
targetTextureImporter.textureType = TextureImporterType.NormalMap;
|
||||
}
|
||||
targetTextureImporter.SaveAndReimport();
|
||||
|
||||
// remap
|
||||
var externalObject = AssetDatabase.LoadAssetAtPath<UnityEngine.Texture2D>(extracted.Path);
|
||||
importer.AddRemap(new AssetImporter.SourceAssetIdentifier(typeof(UnityEngine.Texture2D), externalObject.name), externalObject);
|
||||
}
|
||||
|
||||
AssetDatabase.ImportAsset(importer.assetPath, ImportAssetOptions.ForceUpdate);
|
||||
|
||||
if (onCompleted != null)
|
||||
{
|
||||
onCompleted();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static DirectoryInfo SafeCreateDirectory(this ScriptedImporter importer, string path)
|
||||
{
|
||||
if (Directory.Exists(path))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return Directory.CreateDirectory(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: db36517c11c455e4b94d9cbb8c1cc3ff
|
||||
guid: 1c57d58453713684bb3888c33177ed78
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
#if false
|
||||
using System;
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
@@ -44,8 +45,9 @@ namespace UniGLTF
|
||||
return;
|
||||
}
|
||||
|
||||
var context = new ImporterContext();
|
||||
context.Parse(src);
|
||||
var parser = new GltfParser();
|
||||
parser.ParsePath(src);
|
||||
var context = new ImporterContext(parser);
|
||||
|
||||
// Extract textures to assets folder
|
||||
context.ExtractImages(prefabPath);
|
||||
@@ -84,3 +86,4 @@ namespace UniGLTF
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -45,11 +45,21 @@ namespace UniGLTF
|
||||
return new Vector4(v.x, v.y, -v.z, v.w);
|
||||
}
|
||||
|
||||
public static Vector4 ReverseX(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);
|
||||
}
|
||||
|
||||
public static Vector3 ReverseX(this Vector3 v)
|
||||
{
|
||||
return new Vector3(-v.x, v.y, v.z);
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
public static Vector2 ReverseY(this Vector2 v)
|
||||
{
|
||||
@@ -69,6 +79,14 @@ namespace UniGLTF
|
||||
return Quaternion.AngleAxis(-angle, ReverseZ(axis));
|
||||
}
|
||||
|
||||
public static Quaternion ReverseX(this Quaternion q)
|
||||
{
|
||||
float angle;
|
||||
Vector3 axis;
|
||||
q.ToAngleAxis(out angle, out axis);
|
||||
return Quaternion.AngleAxis(-angle, ReverseX(axis));
|
||||
}
|
||||
|
||||
public static Matrix4x4 Matrix4x4FromColumns(Vector4 c0, Vector4 c1, Vector4 c2, Vector4 c3)
|
||||
{
|
||||
#if UNITY_2017_1_OR_NEWER
|
||||
@@ -100,6 +118,12 @@ namespace UniGLTF
|
||||
return m;
|
||||
}
|
||||
|
||||
public static Matrix4x4 ReverseX(this Matrix4x4 m)
|
||||
{
|
||||
m.SetTRS(m.ExtractPosition().ReverseX(), m.ExtractRotation().ReverseX(), m.ExtractScale());
|
||||
return m;
|
||||
}
|
||||
|
||||
public static Matrix4x4 MatrixFromArray(float[] values)
|
||||
{
|
||||
var m = new Matrix4x4();
|
||||
|
||||
@@ -325,7 +325,8 @@ namespace UniGLTF
|
||||
var bufferCount = vertexAccessor.count * vertexAccessor.TypeCount;
|
||||
|
||||
float[] result = null;
|
||||
if(vertexAccessor.bufferView != -1){
|
||||
if (vertexAccessor.bufferView != -1)
|
||||
{
|
||||
var attrib = new float[vertexAccessor.count * vertexAccessor.TypeCount];
|
||||
var view = self.bufferViews[vertexAccessor.bufferView];
|
||||
var segment = self.buffers[view.buffer].GetBytes();
|
||||
@@ -333,8 +334,9 @@ namespace UniGLTF
|
||||
bytes.MarshalCopyTo(attrib);
|
||||
result = attrib;
|
||||
}
|
||||
else{
|
||||
result = new float[bufferCount];
|
||||
else
|
||||
{
|
||||
result = new float[bufferCount];
|
||||
}
|
||||
|
||||
var sparse = vertexAccessor.sparse;
|
||||
@@ -354,28 +356,15 @@ namespace UniGLTF
|
||||
return result;
|
||||
}
|
||||
|
||||
public static ArraySegment<Byte> GetImageBytes(this glTF self, IStorage storage, int imageIndex, out string textureName)
|
||||
public static ArraySegment<Byte> GetImageBytes(this glTF self, IStorage storage, int imageIndex)
|
||||
{
|
||||
var image = self.images[imageIndex];
|
||||
if (string.IsNullOrEmpty(image.uri))
|
||||
{
|
||||
//
|
||||
// use buffer view (GLB)
|
||||
//
|
||||
//m_imageBytes = ToArray(byteSegment);
|
||||
textureName = !string.IsNullOrEmpty(image.name) ? image.name : string.Format("{0:00}#GLB", imageIndex);
|
||||
return self.GetViewBytes(image.bufferView);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (image.uri.FastStartsWith("data:"))
|
||||
{
|
||||
textureName = !string.IsNullOrEmpty(image.name) ? image.name : string.Format("{0:00}#Base64Embedded", imageIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
textureName = !string.IsNullOrEmpty(image.name) ? image.name : Path.GetFileNameWithoutExtension(image.uri);
|
||||
}
|
||||
return storage.Get(image.uri);
|
||||
}
|
||||
}
|
||||
@@ -441,7 +430,7 @@ namespace UniGLTF
|
||||
// remove unused extenions
|
||||
var json = f.ToString().ParseAsJson().ToString(" ");
|
||||
self.RemoveUnusedExtensions(json);
|
||||
|
||||
|
||||
return Glb.Create(json, self.buffers[0].GetBytes()).ToBytes();
|
||||
}
|
||||
|
||||
|
||||
@@ -67,16 +67,6 @@ namespace UniGLTF
|
||||
[JsonSchema(MinItems = 1, ExplicitIgnorableItemLength = 0)]
|
||||
public List<glTFImage> images = new List<glTFImage>();
|
||||
|
||||
public int GetImageIndexFromTextureIndex(int textureIndex)
|
||||
{
|
||||
return textures[textureIndex].source;
|
||||
}
|
||||
|
||||
public glTFImage GetImageFromTextureIndex(int textureIndex)
|
||||
{
|
||||
return images[GetImageIndexFromTextureIndex(textureIndex)];
|
||||
}
|
||||
|
||||
public glTFTextureSampler GetSamplerFromTextureIndex(int textureIndex)
|
||||
{
|
||||
var samplerIndex = textures[textureIndex].sampler;
|
||||
|
||||
@@ -79,10 +79,16 @@ namespace UniGLTF.AltTask
|
||||
public Awaitable(Task task)
|
||||
{
|
||||
_task = task;
|
||||
if (_task.Exception != null)
|
||||
{
|
||||
throw _task.Exception;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsCompleted => _task.IsCompleted;
|
||||
|
||||
public Exception Exception => _task.Exception;
|
||||
|
||||
public IAwaiter GetAwaiter()
|
||||
{
|
||||
return new Awaiter(this);
|
||||
@@ -126,6 +132,10 @@ namespace UniGLTF.AltTask
|
||||
|
||||
public void GetResult()
|
||||
{
|
||||
if (m_task.Exception != null)
|
||||
{
|
||||
throw m_task.Exception;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnCompleted(Action continuation)
|
||||
|
||||
@@ -70,11 +70,15 @@ namespace UniGLTF.AltTask
|
||||
public Awaitable(Task<T> task)
|
||||
{
|
||||
_task = task;
|
||||
if (_task.Exception != null)
|
||||
{
|
||||
throw _task.Exception;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public bool IsCompleted => _task.IsCompleted;
|
||||
public T Result => _task.Result;
|
||||
public Exception Exception => _task.Exception;
|
||||
|
||||
public IAwaiter<T> GetAwaiter()
|
||||
{
|
||||
@@ -110,6 +114,10 @@ namespace UniGLTF.AltTask
|
||||
|
||||
public T GetResult()
|
||||
{
|
||||
if (m_task.Exception != null)
|
||||
{
|
||||
throw m_task.Exception;
|
||||
}
|
||||
return m_task.Result;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ using System;
|
||||
|
||||
namespace UniGLTF.AltTask
|
||||
{
|
||||
public static class LoopAwaitable
|
||||
public static class NextFrameAwaitable
|
||||
{
|
||||
// TODO
|
||||
// loop スレッド使わないようにしたい
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 81795a4f6e605d74787f604354a8565f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -64,7 +64,7 @@ namespace UniGLTF
|
||||
|
||||
}
|
||||
|
||||
public delegate float[] ReverseZ(float[] current, float[] last);
|
||||
public delegate float[] ReverseFunc(float[] current, float[] last);
|
||||
public static void SetAnimationCurve(
|
||||
AnimationClip targetClip,
|
||||
string relativePath,
|
||||
@@ -73,7 +73,7 @@ namespace UniGLTF
|
||||
float[] output,
|
||||
string interpolation,
|
||||
Type curveType,
|
||||
ReverseZ reverse)
|
||||
ReverseFunc reverse)
|
||||
{
|
||||
var tangentMode = GetTangentMode(interpolation);
|
||||
|
||||
@@ -164,18 +164,18 @@ namespace UniGLTF
|
||||
|
||||
private static string RelativePathFrom(List<glTFNode> nodes, glTFNode root, glTFNode target, List<string> path)
|
||||
{
|
||||
if(path.Count == 0) path.Add(target.name);
|
||||
if (path.Count == 0) path.Add(target.name);
|
||||
|
||||
var targetIndex = nodes.IndexOf(target);
|
||||
foreach (var parent in nodes)
|
||||
{
|
||||
if(parent.children == null || parent.children.Length == 0) continue;
|
||||
if (parent.children == null || parent.children.Length == 0) continue;
|
||||
|
||||
foreach(var child in parent.children)
|
||||
foreach (var child in parent.children)
|
||||
{
|
||||
if(child != targetIndex) continue;
|
||||
if (child != targetIndex) continue;
|
||||
|
||||
if(parent == root) return string.Join("/", path);
|
||||
if (parent == root) return string.Join("/", path);
|
||||
|
||||
path.Insert(0, parent.name);
|
||||
return RelativePathFrom(nodes, root, parent, path);
|
||||
@@ -185,7 +185,7 @@ namespace UniGLTF
|
||||
return string.Join("/", path);
|
||||
}
|
||||
|
||||
public static AnimationClip ConvertAnimationClip(glTF gltf, glTFAnimation animation, glTFNode root = null)
|
||||
public static AnimationClip ConvertAnimationClip(glTF gltf, glTFAnimation animation, AxisInverter inverter, glTFNode root = null)
|
||||
{
|
||||
var clip = new AnimationClip();
|
||||
clip.ClearCurves();
|
||||
@@ -215,7 +215,7 @@ namespace UniGLTF
|
||||
(values, last) =>
|
||||
{
|
||||
Vector3 temp = new Vector3(values[0], values[1], values[2]);
|
||||
return temp.ReverseZ().ToArray();
|
||||
return inverter.InvertVector3(temp).ToArray();
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -239,7 +239,7 @@ namespace UniGLTF
|
||||
{
|
||||
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 AnimationImporterUtil.GetShortest(lastQuaternion, currentQuaternion.ReverseZ()).ToArray();
|
||||
return AnimationImporterUtil.GetShortest(lastQuaternion, inverter.InvertQuaternion(currentQuaternion)).ToArray();
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
35
Assets/UniGLTF/Runtime/UniGLTF/IO/Axises.cs
Normal file
35
Assets/UniGLTF/Runtime/UniGLTF/IO/Axises.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public enum Axises
|
||||
{
|
||||
Z,
|
||||
X,
|
||||
}
|
||||
|
||||
public struct AxisInverter
|
||||
{
|
||||
public Func<Vector3, Vector3> InvertVector3;
|
||||
public Func<Vector4, Vector4> InvertVector4;
|
||||
public Func<Quaternion, Quaternion> InvertQuaternion;
|
||||
public Func<Matrix4x4, Matrix4x4> InvertMat4;
|
||||
|
||||
public static AxisInverter ReverseZ => new AxisInverter
|
||||
{
|
||||
InvertVector3 = x => x.ReverseZ(),
|
||||
InvertVector4 = x => x.ReverseZ(),
|
||||
InvertQuaternion = x => x.ReverseZ(),
|
||||
InvertMat4 = x => x.ReverseZ(),
|
||||
};
|
||||
|
||||
public static AxisInverter ReverseX => new AxisInverter
|
||||
{
|
||||
InvertVector3 = x => x.ReverseX(),
|
||||
InvertVector4 = x => x.ReverseX(),
|
||||
InvertQuaternion = x => x.ReverseX(),
|
||||
InvertMat4 = x => x.ReverseX(),
|
||||
};
|
||||
}
|
||||
}
|
||||
11
Assets/UniGLTF/Runtime/UniGLTF/IO/Axises.cs.meta
Normal file
11
Assets/UniGLTF/Runtime/UniGLTF/IO/Axises.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5b3b7b9629a4da242bacf52f5ca0fd80
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
436
Assets/UniGLTF/Runtime/UniGLTF/IO/GltfParser.cs
Normal file
436
Assets/UniGLTF/Runtime/UniGLTF/IO/GltfParser.cs
Normal file
@@ -0,0 +1,436 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UniJSON;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public class GltfParser
|
||||
{
|
||||
/// <summary>
|
||||
/// JSON source
|
||||
/// </summary>
|
||||
public String Json;
|
||||
|
||||
/// <summary>
|
||||
/// GLTF parsed from JSON
|
||||
/// </summary>
|
||||
public glTF GLTF;
|
||||
|
||||
/// <summary>
|
||||
/// URI access
|
||||
/// </summary>
|
||||
public IStorage Storage;
|
||||
|
||||
public static bool IsGeneratedUniGLTFAndOlderThan(string generatorVersion, int major, int minor)
|
||||
{
|
||||
if (string.IsNullOrEmpty(generatorVersion)) return false;
|
||||
if (generatorVersion == "UniGLTF") return true;
|
||||
if (!generatorVersion.FastStartsWith("UniGLTF-")) return false;
|
||||
|
||||
try
|
||||
{
|
||||
var splitted = generatorVersion.Substring(8).Split('.');
|
||||
var generatorMajor = int.Parse(splitted[0]);
|
||||
var generatorMinor = int.Parse(splitted[1]);
|
||||
|
||||
if (generatorMajor < major)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (generatorMajor > major)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (generatorMinor >= minor)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogWarningFormat("{0}: {1}", generatorVersion, ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsGeneratedUniGLTFAndOlder(int major, int minor)
|
||||
{
|
||||
if (GLTF == null) return false;
|
||||
if (GLTF.asset == null) return false;
|
||||
return IsGeneratedUniGLTFAndOlderThan(GLTF.asset.generator, major, minor);
|
||||
}
|
||||
|
||||
#region Parse
|
||||
public void ParsePath(string path)
|
||||
{
|
||||
Parse(path, File.ReadAllBytes(path));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse gltf json or Parse json chunk of glb
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <param name="bytes"></param>
|
||||
public virtual void Parse(string path, Byte[] bytes)
|
||||
{
|
||||
var ext = Path.GetExtension(path).ToLower();
|
||||
switch (ext)
|
||||
{
|
||||
case ".gltf":
|
||||
ParseJson(Encoding.UTF8.GetString(bytes), new FileSystemStorage(Path.GetDirectoryName(path)));
|
||||
break;
|
||||
|
||||
case ".zip":
|
||||
{
|
||||
var zipArchive = Zip.ZipArchiveStorage.Parse(bytes);
|
||||
var gltf = zipArchive.Entries.FirstOrDefault(x => x.FileName.ToLower().EndsWith(".gltf"));
|
||||
if (gltf == null)
|
||||
{
|
||||
throw new Exception("no gltf in archive");
|
||||
}
|
||||
var jsonBytes = zipArchive.Extract(gltf);
|
||||
var json = Encoding.UTF8.GetString(jsonBytes);
|
||||
ParseJson(json, zipArchive);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ParseGlb(bytes);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="bytes"></param>
|
||||
public void ParseGlb(Byte[] bytes)
|
||||
{
|
||||
var chunks = glbImporter.ParseGlbChunks(bytes);
|
||||
|
||||
if (chunks.Count != 2)
|
||||
{
|
||||
throw new Exception("unknown chunk count: " + chunks.Count);
|
||||
}
|
||||
|
||||
if (chunks[0].ChunkType != GlbChunkType.JSON)
|
||||
{
|
||||
throw new Exception("chunk 0 is not JSON");
|
||||
}
|
||||
|
||||
if (chunks[1].ChunkType != GlbChunkType.BIN)
|
||||
{
|
||||
throw new Exception("chunk 1 is not BIN");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var jsonBytes = chunks[0].Bytes;
|
||||
ParseJson(Encoding.UTF8.GetString(jsonBytes.Array, jsonBytes.Offset, jsonBytes.Count),
|
||||
new SimpleStorage(chunks[1].Bytes));
|
||||
}
|
||||
catch (StackOverflowException ex)
|
||||
{
|
||||
throw new Exception("[UniVRM Import Error] json parsing failed, nesting is too deep.\n" + ex);
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void ParseJson(string json, IStorage storage)
|
||||
{
|
||||
Json = json;
|
||||
Storage = storage;
|
||||
GLTF = GltfDeserializer.Deserialize(json.ParseAsJson());
|
||||
if (GLTF.asset.version != "2.0")
|
||||
{
|
||||
throw new UniGLTFException("unknown gltf version {0}", GLTF.asset.version);
|
||||
}
|
||||
|
||||
// Version Compatibility
|
||||
RestoreOlderVersionValues();
|
||||
|
||||
FixMeshNameUnique();
|
||||
FixTextureNameUnique();
|
||||
FixMaterialNameUnique();
|
||||
FixNodeName();
|
||||
|
||||
// parepare byte buffer
|
||||
//GLTF.baseDir = System.IO.Path.GetDirectoryName(Path);
|
||||
foreach (var buffer in GLTF.buffers)
|
||||
{
|
||||
buffer.OpenStorage(storage);
|
||||
}
|
||||
}
|
||||
|
||||
void FixMeshNameUnique()
|
||||
{
|
||||
var used = new HashSet<string>();
|
||||
foreach (var mesh in GLTF.meshes)
|
||||
{
|
||||
if (string.IsNullOrEmpty(mesh.name))
|
||||
{
|
||||
// empty
|
||||
mesh.name = "mesh_" + Guid.NewGuid().ToString("N");
|
||||
Debug.LogWarning($"no name: => {mesh.name}");
|
||||
used.Add(mesh.name);
|
||||
}
|
||||
else
|
||||
{
|
||||
var lower = mesh.name.ToLower();
|
||||
if (used.Contains(lower))
|
||||
{
|
||||
// rename
|
||||
var uname = lower + "_" + Guid.NewGuid().ToString("N");
|
||||
Debug.LogWarning($"same name: {lower} => {uname}");
|
||||
mesh.name = uname;
|
||||
lower = uname;
|
||||
}
|
||||
used.Add(lower);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RenameImageFromTexture(int i)
|
||||
{
|
||||
foreach (var texture in GLTF.textures)
|
||||
{
|
||||
if (texture.source == i)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(texture.name))
|
||||
{
|
||||
GLTF.images[i].name = texture.name;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// gltfTexture.name を Unity Asset 名として運用する。
|
||||
/// ユニークである必要がある。
|
||||
/// </summary>
|
||||
void FixTextureNameUnique()
|
||||
{
|
||||
var used = new HashSet<string>();
|
||||
for (int i = 0; i < GLTF.textures.Count; ++i)
|
||||
{
|
||||
var gltfTexture = GLTF.textures[i];
|
||||
if (string.IsNullOrEmpty(gltfTexture.name))
|
||||
{
|
||||
// use image name
|
||||
gltfTexture.name = GLTF.images[gltfTexture.source].name;
|
||||
}
|
||||
if (string.IsNullOrEmpty(gltfTexture.name))
|
||||
{
|
||||
var newName = $"texture_{i}";
|
||||
if (!used.Add(newName))
|
||||
{
|
||||
newName = "texture_" + Guid.NewGuid().ToString("N");
|
||||
if (!used.Add(newName))
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
}
|
||||
gltfTexture.name = newName;
|
||||
}
|
||||
else
|
||||
{
|
||||
var lower = gltfTexture.name.ToLower();
|
||||
if (used.Contains(lower))
|
||||
{
|
||||
// rename
|
||||
var uname = lower + "_" + Guid.NewGuid().ToString("N");
|
||||
Debug.LogWarning($"same name: {lower} => {uname}");
|
||||
gltfTexture.name = uname;
|
||||
lower = uname;
|
||||
}
|
||||
used.Add(lower);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void FixMaterialNameUnique()
|
||||
{
|
||||
foreach (var material in GLTF.materials)
|
||||
{
|
||||
var originalName = material.name;
|
||||
int j = 2;
|
||||
while (GLTF.materials.Any(x => x != material && x.name == material.name))
|
||||
{
|
||||
material.name = string.Format("{0}({1})", originalName, j++);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// rename empty name to $"{index}"
|
||||
/// </summary>
|
||||
void FixNodeName()
|
||||
{
|
||||
for (var i = 0; i < GLTF.nodes.Count; ++i)
|
||||
{
|
||||
var node = GLTF.nodes[i];
|
||||
if (string.IsNullOrWhiteSpace(node.name))
|
||||
{
|
||||
node.name = $"{i}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RestoreOlderVersionValues()
|
||||
{
|
||||
var parsed = UniJSON.JsonParser.Parse(Json);
|
||||
for (int i = 0; i < GLTF.images.Count; ++i)
|
||||
{
|
||||
if (string.IsNullOrEmpty(GLTF.images[i].name))
|
||||
{
|
||||
try
|
||||
{
|
||||
var extraName = parsed["images"][i]["extra"]["name"].Value.GetString();
|
||||
if (!string.IsNullOrEmpty(extraName))
|
||||
{
|
||||
//Debug.LogFormat("restore texturename: {0}", extraName);
|
||||
GLTF.images[i].name = extraName;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
public static void AppendImageExtension(glTFImage texture, string extension)
|
||||
{
|
||||
if (!texture.name.EndsWith(extension))
|
||||
{
|
||||
texture.name = texture.name + extension;
|
||||
}
|
||||
}
|
||||
|
||||
public string GetTextureExtension(int imageIndex)
|
||||
{
|
||||
foreach (var m in GLTF.materials)
|
||||
{
|
||||
if (m.pbrMetallicRoughness != null)
|
||||
{
|
||||
// base color
|
||||
if (m.pbrMetallicRoughness?.baseColorTexture != null)
|
||||
{
|
||||
if (m.pbrMetallicRoughness.baseColorTexture.index == imageIndex)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
// metallic roughness
|
||||
if (m.pbrMetallicRoughness?.metallicRoughnessTexture != null)
|
||||
{
|
||||
if (m.pbrMetallicRoughness.metallicRoughnessTexture.index == imageIndex)
|
||||
{
|
||||
return ".metallicRoughness";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// emission
|
||||
if (m.emissiveTexture != null)
|
||||
{
|
||||
if (m.emissiveTexture.index == imageIndex)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
// normal
|
||||
if (m.normalTexture != null)
|
||||
{
|
||||
if (m.normalTexture.index == imageIndex)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
// occlusion
|
||||
if (m.occlusionTexture != null)
|
||||
{
|
||||
if (m.occlusionTexture.index == imageIndex)
|
||||
{
|
||||
return ".occlusion";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
public IEnumerable<GetTextureParam> EnumerateTextures(glTFMaterial m)
|
||||
{
|
||||
if (m.pbrMetallicRoughness != null)
|
||||
{
|
||||
// base color
|
||||
if (m.pbrMetallicRoughness?.baseColorTexture != null)
|
||||
{
|
||||
yield return PBRMaterialItem.BaseColorTexture(GLTF, m);
|
||||
}
|
||||
|
||||
// metallic roughness
|
||||
if (m.pbrMetallicRoughness?.metallicRoughnessTexture != null)
|
||||
{
|
||||
yield return PBRMaterialItem.MetallicRoughnessTexture(GLTF, m);
|
||||
}
|
||||
}
|
||||
|
||||
// emission
|
||||
if (m.emissiveTexture != null)
|
||||
{
|
||||
yield return GetTextureParam.Create(GLTF, m.emissiveTexture.index);
|
||||
}
|
||||
|
||||
// normal
|
||||
if (m.normalTexture != null)
|
||||
{
|
||||
yield return PBRMaterialItem.NormalTexture(GLTF, m);
|
||||
}
|
||||
|
||||
// occlusion
|
||||
if (m.occlusionTexture != null)
|
||||
{
|
||||
yield return PBRMaterialItem.OcclusionTexture(GLTF, m);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<GetTextureParam> EnumerateTextures()
|
||||
{
|
||||
var used = new HashSet<string>();
|
||||
for (int i = 0; i < GLTF.materials.Count; ++i)
|
||||
{
|
||||
var m = GLTF.materials[i];
|
||||
foreach (var x in EnumerateTextures(m))
|
||||
{
|
||||
if (used.Add(x.Name))
|
||||
{
|
||||
yield return x;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/UniGLTF/Runtime/UniGLTF/IO/GltfParser.cs.meta
Normal file
11
Assets/UniGLTF/Runtime/UniGLTF/IO/GltfParser.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ae3083233546b58449904dca65e76005
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -3,8 +3,6 @@ using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using UniJSON;
|
||||
using UniGLTF.AltTask;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
@@ -12,76 +10,11 @@ using UnityEditor;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// GLTF importer
|
||||
/// </summary>
|
||||
public class ImporterContext : IDisposable
|
||||
{
|
||||
#region MeasureTime
|
||||
bool m_showSpeedLog
|
||||
#if VRM_DEVELOP
|
||||
= true
|
||||
#endif
|
||||
;
|
||||
public bool ShowSpeedLog
|
||||
{
|
||||
set { m_showSpeedLog = value; }
|
||||
}
|
||||
|
||||
public struct KeyElapsed
|
||||
{
|
||||
public string Key;
|
||||
public TimeSpan Elapsed;
|
||||
public KeyElapsed(string key, TimeSpan elapsed)
|
||||
{
|
||||
Key = key;
|
||||
Elapsed = elapsed;
|
||||
}
|
||||
}
|
||||
|
||||
public struct MeasureScope : IDisposable
|
||||
{
|
||||
Action m_onDispose;
|
||||
public MeasureScope(Action onDispose)
|
||||
{
|
||||
m_onDispose = onDispose;
|
||||
}
|
||||
public void Dispose()
|
||||
{
|
||||
m_onDispose();
|
||||
}
|
||||
}
|
||||
|
||||
public List<KeyElapsed> m_speedReports = new List<KeyElapsed>();
|
||||
|
||||
public IDisposable MeasureTime(string key)
|
||||
{
|
||||
var sw = System.Diagnostics.Stopwatch.StartNew();
|
||||
return new MeasureScope(() =>
|
||||
{
|
||||
m_speedReports.Add(new KeyElapsed(key, sw.Elapsed));
|
||||
});
|
||||
}
|
||||
|
||||
public string GetSpeedLog()
|
||||
{
|
||||
var total = TimeSpan.Zero;
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine("【SpeedLog】");
|
||||
foreach (var kv in m_speedReports)
|
||||
{
|
||||
sb.AppendLine(string.Format("{0}: {1}ms", kv.Key, (int)kv.Elapsed.TotalMilliseconds));
|
||||
total += kv.Elapsed;
|
||||
}
|
||||
sb.AppendLine(string.Format("total: {0}ms", (int)total.TotalMilliseconds));
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Animation
|
||||
protected IAnimationImporter m_animationImporter;
|
||||
public void SetAnimationImporter(IAnimationImporter animationImporter)
|
||||
@@ -108,258 +41,54 @@ namespace UniGLTF
|
||||
TextureFactory m_textureFactory;
|
||||
public TextureFactory TextureFactory => m_textureFactory;
|
||||
|
||||
public ImporterContext()
|
||||
public ImporterContext(GltfParser parser, IEnumerable<(string, UnityEngine.Object)> externalObjectMap = null)
|
||||
{
|
||||
m_parser = parser;
|
||||
m_textureFactory = new TextureFactory(GLTF, Storage, externalObjectMap);
|
||||
m_materialFactory = new MaterialFactory(GLTF, Storage, externalObjectMap);
|
||||
}
|
||||
|
||||
#region Source
|
||||
|
||||
/// <summary>
|
||||
/// JSON source
|
||||
/// </summary>
|
||||
public String Json;
|
||||
|
||||
/// <summary>
|
||||
/// GLTF parsed from JSON
|
||||
/// </summary>
|
||||
public glTF GLTF; // parsed
|
||||
|
||||
public static bool IsGeneratedUniGLTFAndOlderThan(string generatorVersion, int major, int minor)
|
||||
{
|
||||
if (string.IsNullOrEmpty(generatorVersion)) return false;
|
||||
if (generatorVersion == "UniGLTF") return true;
|
||||
if (!generatorVersion.FastStartsWith("UniGLTF-")) return false;
|
||||
|
||||
try
|
||||
{
|
||||
var splitted = generatorVersion.Substring(8).Split('.');
|
||||
var generatorMajor = int.Parse(splitted[0]);
|
||||
var generatorMinor = int.Parse(splitted[1]);
|
||||
|
||||
if (generatorMajor < major)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (generatorMajor > major)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (generatorMinor >= minor)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogWarningFormat("{0}: {1}", generatorVersion, ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsGeneratedUniGLTFAndOlder(int major, int minor)
|
||||
{
|
||||
if (GLTF == null) return false;
|
||||
if (GLTF.asset == null) return false;
|
||||
return IsGeneratedUniGLTFAndOlderThan(GLTF.asset.generator, major, minor);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// URI access
|
||||
/// </summary>
|
||||
public IStorage Storage;
|
||||
GltfParser m_parser;
|
||||
public GltfParser Parser => m_parser;
|
||||
public String Json => m_parser.Json;
|
||||
public glTF GLTF => m_parser.GLTF;
|
||||
public IStorage Storage => m_parser.Storage;
|
||||
#endregion
|
||||
|
||||
#region Parse
|
||||
public void Parse(string path)
|
||||
{
|
||||
Parse(path, File.ReadAllBytes(path));
|
||||
}
|
||||
// configuration
|
||||
|
||||
/// <summary>
|
||||
/// Parse gltf json or Parse json chunk of glb
|
||||
/// GLTF から Unity に変換するときに反転させる軸
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <param name="bytes"></param>
|
||||
public virtual void Parse(string path, Byte[] bytes)
|
||||
public Axises InvertAxis = Axises.Z;
|
||||
|
||||
#region Load. Build unity objects
|
||||
public virtual async Awaitable LoadAsync(Func<string, IDisposable> MeasureTime = null)
|
||||
{
|
||||
var ext = Path.GetExtension(path).ToLower();
|
||||
switch (ext)
|
||||
if (MeasureTime == null)
|
||||
{
|
||||
case ".gltf":
|
||||
ParseJson(Encoding.UTF8.GetString(bytes), new FileSystemStorage(Path.GetDirectoryName(path)));
|
||||
MeasureTime = new ImporterContextSpeedLog().MeasureTime;
|
||||
}
|
||||
|
||||
AxisInverter inverter = default;
|
||||
switch (InvertAxis)
|
||||
{
|
||||
case Axises.Z:
|
||||
inverter = AxisInverter.ReverseZ;
|
||||
break;
|
||||
|
||||
case ".zip":
|
||||
{
|
||||
var zipArchive = Zip.ZipArchiveStorage.Parse(bytes);
|
||||
var gltf = zipArchive.Entries.FirstOrDefault(x => x.FileName.ToLower().EndsWith(".gltf"));
|
||||
if (gltf == null)
|
||||
{
|
||||
throw new Exception("no gltf in archive");
|
||||
}
|
||||
var jsonBytes = zipArchive.Extract(gltf);
|
||||
var json = Encoding.UTF8.GetString(jsonBytes);
|
||||
ParseJson(json, zipArchive);
|
||||
}
|
||||
break;
|
||||
|
||||
case ".glb":
|
||||
ParseGlb(bytes);
|
||||
case Axises.X:
|
||||
inverter = AxisInverter.ReverseX;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="bytes"></param>
|
||||
public void ParseGlb(Byte[] bytes)
|
||||
{
|
||||
var chunks = glbImporter.ParseGlbChunks(bytes);
|
||||
|
||||
if (chunks.Count != 2)
|
||||
{
|
||||
throw new Exception("unknown chunk count: " + chunks.Count);
|
||||
}
|
||||
|
||||
if (chunks[0].ChunkType != GlbChunkType.JSON)
|
||||
{
|
||||
throw new Exception("chunk 0 is not JSON");
|
||||
}
|
||||
|
||||
if (chunks[1].ChunkType != GlbChunkType.BIN)
|
||||
{
|
||||
throw new Exception("chunk 1 is not BIN");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var jsonBytes = chunks[0].Bytes;
|
||||
ParseJson(Encoding.UTF8.GetString(jsonBytes.Array, jsonBytes.Offset, jsonBytes.Count),
|
||||
new SimpleStorage(chunks[1].Bytes));
|
||||
}
|
||||
catch (StackOverflowException ex)
|
||||
{
|
||||
throw new Exception("[UniVRM Import Error] json parsing failed, nesting is too deep.\n" + ex);
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void ParseJson(string json, IStorage storage)
|
||||
{
|
||||
Json = json;
|
||||
Storage = storage;
|
||||
GLTF = GltfDeserializer.Deserialize(json.ParseAsJson());
|
||||
if (GLTF.asset.version != "2.0")
|
||||
{
|
||||
throw new UniGLTFException("unknown gltf version {0}", GLTF.asset.version);
|
||||
}
|
||||
|
||||
m_textureFactory = new TextureFactory(GLTF, Storage);
|
||||
m_materialFactory = new MaterialFactory(GLTF, Storage);
|
||||
|
||||
// Version Compatibility
|
||||
RestoreOlderVersionValues();
|
||||
|
||||
FixUnique();
|
||||
FixNodeName();
|
||||
|
||||
// parepare byte buffer
|
||||
//GLTF.baseDir = System.IO.Path.GetDirectoryName(Path);
|
||||
foreach (var buffer in GLTF.buffers)
|
||||
{
|
||||
buffer.OpenStorage(storage);
|
||||
}
|
||||
}
|
||||
|
||||
void FixUnique()
|
||||
{
|
||||
var used = new HashSet<string>();
|
||||
foreach (var mesh in GLTF.meshes)
|
||||
{
|
||||
if (string.IsNullOrEmpty(mesh.name))
|
||||
{
|
||||
mesh.name = "mesh_" + Guid.NewGuid().ToString("N");
|
||||
used.Add(mesh.name);
|
||||
}
|
||||
else
|
||||
{
|
||||
var lname = mesh.name.ToLower();
|
||||
if (used.Contains(lname))
|
||||
{
|
||||
// rename
|
||||
var uname = lname + "_" + Guid.NewGuid().ToString("N");
|
||||
Debug.LogWarning($"same name: {lname} => {uname}");
|
||||
mesh.name = uname;
|
||||
lname = uname;
|
||||
}
|
||||
|
||||
used.Add(lname);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// rename empty name to $"{index}"
|
||||
/// </summary>
|
||||
void FixNodeName()
|
||||
{
|
||||
for (var i = 0; i < GLTF.nodes.Count; ++i)
|
||||
{
|
||||
var node = GLTF.nodes[i];
|
||||
if (string.IsNullOrWhiteSpace(node.name))
|
||||
{
|
||||
node.name = $"{i}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RestoreOlderVersionValues()
|
||||
{
|
||||
var parsed = UniJSON.JsonParser.Parse(Json);
|
||||
for (int i = 0; i < GLTF.images.Count; ++i)
|
||||
{
|
||||
if (string.IsNullOrEmpty(GLTF.images[i].name))
|
||||
{
|
||||
try
|
||||
{
|
||||
var extraName = parsed["images"][i]["extra"]["name"].Value.GetString();
|
||||
if (!string.IsNullOrEmpty(extraName))
|
||||
{
|
||||
//Debug.LogFormat("restore texturename: {0}", extraName);
|
||||
GLTF.images[i].name = extraName;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Load. Build unity objects
|
||||
|
||||
public bool EnableLoadBalancing;
|
||||
|
||||
public virtual async Awaitable LoadAsync()
|
||||
{
|
||||
if (Root == null)
|
||||
{
|
||||
Root = new GameObject("_root_");
|
||||
Root = new GameObject("GLTF");
|
||||
}
|
||||
|
||||
// UniGLTF does not support draco
|
||||
@@ -369,17 +98,30 @@ namespace UniGLTF
|
||||
throw new UniGLTFNotSupportedException("draco is not supported");
|
||||
}
|
||||
|
||||
await m_materialFactory.LoadMaterialsAsync(m_textureFactory.GetTextureAsync);
|
||||
// using (MeasureTime("LoadTextures"))
|
||||
// {
|
||||
// for (int i = 0; i < GLTF.materials.Count; ++i)
|
||||
// {
|
||||
// foreach (var param in MaterialFactory.EnumerateGetTextureparam(i))
|
||||
// {
|
||||
// await m_textureFactory.GetTextureAsync(GLTF, param);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
using (MeasureTime("LoadMaterials"))
|
||||
{
|
||||
await m_materialFactory.LoadMaterialsAsync(m_textureFactory.GetTextureAsync);
|
||||
}
|
||||
|
||||
// meshes
|
||||
var meshImporter = new MeshImporter();
|
||||
for (int i = 0; i < GLTF.meshes.Count; ++i)
|
||||
{
|
||||
var index = i;
|
||||
using (MeasureTime("ReadMesh"))
|
||||
{
|
||||
var x = meshImporter.ReadMesh(this, index);
|
||||
var y = await BuildMeshAsync(x, index);
|
||||
var x = meshImporter.ReadMesh(this, index, inverter);
|
||||
var y = await BuildMeshAsync(MeasureTime, x, index);
|
||||
Meshes.Add(y);
|
||||
}
|
||||
}
|
||||
@@ -391,7 +133,7 @@ namespace UniGLTF
|
||||
Nodes.Add(NodeImporter.ImportNode(GLTF.nodes[i], i).transform);
|
||||
}
|
||||
}
|
||||
await LoopAwaitable.Create();
|
||||
await NextFrameAwaitable.Create();
|
||||
|
||||
using (MeasureTime("BuildHierarchy"))
|
||||
{
|
||||
@@ -401,12 +143,12 @@ namespace UniGLTF
|
||||
nodes.Add(NodeImporter.BuildHierarchy(this, i));
|
||||
}
|
||||
|
||||
NodeImporter.FixCoordinate(this, nodes);
|
||||
NodeImporter.FixCoordinate(this, nodes, inverter);
|
||||
|
||||
// skinning
|
||||
for (int i = 0; i < nodes.Count; ++i)
|
||||
{
|
||||
NodeImporter.SetupSkinning(this, nodes, i);
|
||||
NodeImporter.SetupSkinning(this, nodes, i, inverter);
|
||||
}
|
||||
|
||||
// connect root
|
||||
@@ -416,41 +158,26 @@ namespace UniGLTF
|
||||
t.SetParent(Root.transform, false);
|
||||
}
|
||||
}
|
||||
await LoopAwaitable.Create();
|
||||
await NextFrameAwaitable.Create();
|
||||
|
||||
using (MeasureTime("AnimationImporter"))
|
||||
{
|
||||
AnimationImporter.Import(this);
|
||||
}
|
||||
|
||||
await OnLoadModel();
|
||||
|
||||
if (m_showSpeedLog)
|
||||
{
|
||||
Debug.Log(GetSpeedLog());
|
||||
}
|
||||
await OnLoadModel(MeasureTime);
|
||||
}
|
||||
|
||||
protected virtual async Awaitable OnLoadModel()
|
||||
protected virtual async Awaitable OnLoadModel(Func<string, IDisposable> MeasureTime)
|
||||
{
|
||||
Root.name = "GLTF";
|
||||
await LoopAwaitable.Create();
|
||||
// do nothing
|
||||
}
|
||||
|
||||
async Awaitable<MeshWithMaterials> BuildMeshAsync(MeshImporter.MeshContext x, int i)
|
||||
async Awaitable<MeshWithMaterials> BuildMeshAsync(Func<string, IDisposable> MeasureTime, MeshImporter.MeshContext x, int i)
|
||||
{
|
||||
using (MeasureTime("BuildMesh"))
|
||||
{
|
||||
MeshWithMaterials meshWithMaterials;
|
||||
if (EnableLoadBalancing)
|
||||
{
|
||||
meshWithMaterials = await MeshImporter.BuildMeshAsync(MaterialFactory, x);
|
||||
}
|
||||
else
|
||||
{
|
||||
meshWithMaterials = MeshImporter.BuildMesh(MaterialFactory, x);
|
||||
}
|
||||
|
||||
var meshWithMaterials = await MeshImporter.BuildMeshAsync(MaterialFactory, x);
|
||||
var mesh = meshWithMaterials.Mesh;
|
||||
|
||||
// mesh name
|
||||
@@ -664,30 +391,29 @@ namespace UniGLTF
|
||||
// https://answers.unity.com/questions/647615/how-to-update-import-settings-for-newly-created-as.html
|
||||
//
|
||||
int created = 0;
|
||||
//for (int i = 0; i < GLTF.textures.Count; ++i)
|
||||
for (int i = 0; i < GLTF.images.Count; ++i)
|
||||
for (int i = 0; i < GLTF.textures.Count; ++i)
|
||||
{
|
||||
folder.EnsureFolder();
|
||||
|
||||
//var x = GLTF.textures[i];
|
||||
var image = GLTF.images[i];
|
||||
var src = Storage.GetPath(image.uri);
|
||||
var gltfTexture = GLTF.textures[i];
|
||||
var gltfImage = GLTF.images[gltfTexture.source];
|
||||
var src = Storage.GetPath(gltfImage.uri);
|
||||
if (UnityPath.FromFullpath(src).IsUnderAssetsFolder)
|
||||
{
|
||||
// asset is exists.
|
||||
}
|
||||
else
|
||||
{
|
||||
string textureName;
|
||||
var byteSegment = GLTF.GetImageBytes(Storage, i, out textureName);
|
||||
var byteSegment = GLTF.GetImageBytes(Storage, gltfTexture.source);
|
||||
var textureName = gltfTexture.name;
|
||||
|
||||
// path
|
||||
var dst = folder.Child(textureName + image.GetExt());
|
||||
var dst = folder.Child(textureName + gltfImage.GetExt());
|
||||
File.WriteAllBytes(dst.FullPath, byteSegment.ToArray());
|
||||
dst.ImportAsset();
|
||||
|
||||
// make relative path from PrefabParentDir
|
||||
image.uri = dst.Value.Substring(prefabParentDir.Value.Length + 1);
|
||||
gltfImage.uri = dst.Value.Substring(prefabParentDir.Value.Length + 1);
|
||||
++created;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,40 +1,20 @@
|
||||
using System.IO;
|
||||
using UniGLTF.AltTask;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public static class ImporterContextExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// ReadAllBytes, Parse, Create GameObject
|
||||
/// </summary>
|
||||
/// <param name="path">allbytes</param>
|
||||
public static void Load(this ImporterContext self, string path)
|
||||
{
|
||||
var bytes = File.ReadAllBytes(path);
|
||||
self.Load(path, bytes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse, Create GameObject
|
||||
/// </summary>
|
||||
/// <param name="path">gltf or glb path</param>
|
||||
/// <param name="bytes">allbytes</param>
|
||||
public static void Load(this ImporterContext self, string path, byte[] bytes)
|
||||
{
|
||||
self.Parse(path, bytes);
|
||||
self.Load();
|
||||
self.Root.name = Path.GetFileNameWithoutExtension(path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Build unity objects from parsed gltf
|
||||
/// </summary>
|
||||
public static void Load(this ImporterContext self)
|
||||
{
|
||||
var meassureTime = new ImporterContextSpeedLog();
|
||||
using (var queue = TaskQueue.Create())
|
||||
{
|
||||
var task = self.LoadAsync();
|
||||
var task = self.LoadAsync(meassureTime.MeasureTime);
|
||||
|
||||
// 中断された await を消化する
|
||||
while (!task.IsCompleted)
|
||||
@@ -43,6 +23,10 @@ namespace UniGLTF
|
||||
queue.ExecuteOneCallback();
|
||||
}
|
||||
}
|
||||
|
||||
#if VRM_DEVELOP
|
||||
Debug.Log(meassureTime.GetSpeedLog());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
60
Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContextSpeedLog.cs
Normal file
60
Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContextSpeedLog.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public class ImporterContextSpeedLog
|
||||
{
|
||||
public struct KeyElapsed
|
||||
{
|
||||
public string Key;
|
||||
public TimeSpan Elapsed;
|
||||
public KeyElapsed(string key, TimeSpan elapsed)
|
||||
{
|
||||
Key = key;
|
||||
Elapsed = elapsed;
|
||||
}
|
||||
}
|
||||
|
||||
public struct MeasureScope : IDisposable
|
||||
{
|
||||
Action m_onDispose;
|
||||
public MeasureScope(Action onDispose)
|
||||
{
|
||||
m_onDispose = onDispose;
|
||||
}
|
||||
public void Dispose()
|
||||
{
|
||||
m_onDispose();
|
||||
}
|
||||
}
|
||||
|
||||
public List<KeyElapsed> m_speedReports = new List<KeyElapsed>();
|
||||
|
||||
public IDisposable MeasureTime(string key)
|
||||
{
|
||||
var sw = System.Diagnostics.Stopwatch.StartNew();
|
||||
return new MeasureScope(() =>
|
||||
{
|
||||
m_speedReports.Add(new KeyElapsed(key, sw.Elapsed));
|
||||
});
|
||||
}
|
||||
|
||||
public string GetSpeedLog()
|
||||
{
|
||||
var total = TimeSpan.Zero;
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine("【SpeedLog】");
|
||||
foreach (var kv in m_speedReports)
|
||||
{
|
||||
sb.AppendLine(string.Format("{0}: {1}ms", kv.Key, (int)kv.Elapsed.TotalMilliseconds));
|
||||
total += kv.Elapsed;
|
||||
}
|
||||
sb.AppendLine(string.Format("total: {0}ms", (int)total.TotalMilliseconds));
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e99bb16028e30ce4b972caecca5343b1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -10,13 +10,38 @@ namespace UniGLTF
|
||||
{
|
||||
glTF m_gltf;
|
||||
IStorage m_storage;
|
||||
public MaterialFactory(glTF gltf, IStorage storage)
|
||||
Dictionary<string, Material> m_externalMap;
|
||||
public bool TryGetExternal(int index, out Material external)
|
||||
{
|
||||
if (m_externalMap != null)
|
||||
{
|
||||
var gltfMaterial = m_gltf.materials[index];
|
||||
if (m_externalMap.TryGetValue(gltfMaterial.name, out external))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
external = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
public MaterialFactory(glTF gltf, IStorage storage,
|
||||
IEnumerable<(string, UnityEngine.Object)> externalMap)
|
||||
{
|
||||
m_gltf = gltf;
|
||||
m_storage = storage;
|
||||
if (externalMap != null)
|
||||
{
|
||||
m_externalMap = externalMap
|
||||
.Select(kv => (kv.Item1, kv.Item2 as Material))
|
||||
.Where(kv => kv.Item2 != null)
|
||||
.ToDictionary(kv => kv.Item1, kv => kv.Item2)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
public delegate Awaitable<Material> CreateMaterialAsyncFunc(glTF glTF, int i, GetTextureAsyncFunc getTexture);
|
||||
public delegate Awaitable<Material> CreateMaterialAsyncFunc(glTF gltf, int i, GetTextureAsyncFunc getTexture);
|
||||
CreateMaterialAsyncFunc m_createMaterialAsync;
|
||||
public CreateMaterialAsyncFunc CreateMaterialAsync
|
||||
{
|
||||
@@ -34,8 +59,20 @@ namespace UniGLTF
|
||||
}
|
||||
}
|
||||
|
||||
List<Material> m_materials = new List<Material>();
|
||||
public IReadOnlyList<Material> Materials => m_materials;
|
||||
public struct MaterialLoadInfo
|
||||
{
|
||||
public readonly Material Asset;
|
||||
public readonly bool UseExternal;
|
||||
|
||||
public MaterialLoadInfo(Material asset, bool useExternal)
|
||||
{
|
||||
Asset = asset;
|
||||
UseExternal = useExternal;
|
||||
}
|
||||
}
|
||||
|
||||
List<MaterialLoadInfo> m_materials = new List<MaterialLoadInfo>();
|
||||
public IReadOnlyList<MaterialLoadInfo> Materials => m_materials;
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var x in ObjectsForSubAsset())
|
||||
@@ -48,41 +85,42 @@ namespace UniGLTF
|
||||
{
|
||||
foreach (var x in m_materials)
|
||||
{
|
||||
yield return x;
|
||||
yield return x.Asset;
|
||||
}
|
||||
}
|
||||
|
||||
public void AddMaterial(Material material)
|
||||
{
|
||||
var originalName = material.name;
|
||||
int j = 2;
|
||||
while (m_materials.Any(x => x.name == material.name))
|
||||
{
|
||||
material.name = string.Format("{0}({1})", originalName, j++);
|
||||
}
|
||||
m_materials.Add(material);
|
||||
}
|
||||
public Material GetMaterial(int index)
|
||||
{
|
||||
if (index < 0) return null;
|
||||
if (index >= m_materials.Count) return null;
|
||||
return m_materials[index];
|
||||
return m_materials[index].Asset;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// テクスチャ生成
|
||||
/// </summary>
|
||||
/// <param name="getTexture"></param>
|
||||
/// <returns></returns>
|
||||
public async Awaitable LoadMaterialsAsync(GetTextureAsyncFunc getTexture)
|
||||
{
|
||||
if (m_gltf.materials == null || m_gltf.materials.Count == 0)
|
||||
{
|
||||
// no material. work around.
|
||||
var material = await CreateMaterialAsync(m_gltf, 0, getTexture);
|
||||
AddMaterial(material);
|
||||
m_materials.Add(new MaterialLoadInfo(material, false));
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
||||
for (int i = 0; i < m_gltf.materials.Count; ++i)
|
||||
{
|
||||
for (int i = 0; i < m_gltf.materials.Count; ++i)
|
||||
if (TryGetExternal(i, out Material material))
|
||||
{
|
||||
var material = await CreateMaterialAsync(m_gltf, i, getTexture);
|
||||
AddMaterial(material);
|
||||
m_materials.Add(new MaterialLoadInfo(material, true));
|
||||
continue;
|
||||
}
|
||||
|
||||
material = await CreateMaterialAsync(m_gltf, i, getTexture);
|
||||
m_materials.Add(new MaterialLoadInfo(material, false));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,21 +163,20 @@ namespace UniGLTF
|
||||
|
||||
public static Awaitable<Material> DefaultCreateMaterialAsync(glTF gltf, int i, GetTextureAsyncFunc getTexture)
|
||||
{
|
||||
|
||||
if (i < 0 || i >= gltf.materials.Count)
|
||||
{
|
||||
UnityEngine.Debug.LogWarning("glTFMaterial is empty");
|
||||
return PBRMaterialItem.CreateAsync(i, null, getTexture);
|
||||
return PBRMaterialItem.CreateAsync(gltf, i, getTexture);
|
||||
}
|
||||
var x = gltf.materials[i];
|
||||
|
||||
if (glTF_KHR_materials_unlit.IsEnable(x))
|
||||
{
|
||||
var hasVertexColor = gltf.MaterialHasVertexColor(i);
|
||||
return UnlitMaterialItem.CreateAsync(i, x, getTexture, hasVertexColor);
|
||||
return UnlitMaterialItem.CreateAsync(gltf, i, getTexture, hasVertexColor);
|
||||
}
|
||||
|
||||
return PBRMaterialItem.CreateAsync(i, x, getTexture);
|
||||
return PBRMaterialItem.CreateAsync(gltf, i, getTexture);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -158,5 +195,22 @@ namespace UniGLTF
|
||||
var task = DefaultCreateMaterialAsync(gltf, i, null);
|
||||
return task.Result;
|
||||
}
|
||||
|
||||
public IEnumerable<GetTextureParam> EnumerateGetTextureparam(int i)
|
||||
{
|
||||
var m = m_gltf.materials[i];
|
||||
|
||||
// color texture
|
||||
var colorIndex = m.pbrMetallicRoughness?.baseColorTexture?.index;
|
||||
if (colorIndex.HasValue)
|
||||
{
|
||||
yield return GetTextureParam.Create(m_gltf, i);
|
||||
}
|
||||
|
||||
if (!glTF_KHR_materials_unlit.IsEnable(m))
|
||||
{
|
||||
// PBR
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,12 +43,35 @@ namespace UniGLTF
|
||||
Transparent
|
||||
}
|
||||
|
||||
public static async Awaitable<Material> CreateAsync(int i, glTFMaterial src, GetTextureAsyncFunc getTexture)
|
||||
public static GetTextureParam BaseColorTexture(glTF gltf, glTFMaterial src)
|
||||
{
|
||||
return GetTextureParam.Create(gltf, src.pbrMetallicRoughness.baseColorTexture.index);
|
||||
}
|
||||
|
||||
public static GetTextureParam MetallicRoughnessTexture(glTF gltf, glTFMaterial src)
|
||||
{
|
||||
return GetTextureParam.CreateMetallic(gltf,
|
||||
src.pbrMetallicRoughness.metallicRoughnessTexture.index,
|
||||
src.pbrMetallicRoughness.metallicFactor);
|
||||
}
|
||||
|
||||
public static GetTextureParam OcclusionTexture(glTF gltf, glTFMaterial src)
|
||||
{
|
||||
return GetTextureParam.CreateOcclusion(gltf, src.occlusionTexture.index);
|
||||
}
|
||||
|
||||
public static GetTextureParam NormalTexture(glTF gltf, glTFMaterial src)
|
||||
{
|
||||
return GetTextureParam.CreateNormal(gltf, src.normalTexture.index);
|
||||
}
|
||||
|
||||
public static async Awaitable<Material> CreateAsync(glTF gltf, int i, GetTextureAsyncFunc getTexture)
|
||||
{
|
||||
if (getTexture == null)
|
||||
{
|
||||
getTexture = _ => Awaitable.FromResult<Texture2D>(null);
|
||||
getTexture = (_x, _y) => Awaitable.FromResult<Texture2D>(null);
|
||||
}
|
||||
var src = gltf.materials[i];
|
||||
|
||||
var material = MaterialFactory.CreateMaterial(i, src, ShaderName);
|
||||
|
||||
@@ -65,7 +88,7 @@ namespace UniGLTF
|
||||
|
||||
if (src.pbrMetallicRoughness.baseColorTexture != null && src.pbrMetallicRoughness.baseColorTexture.index != -1)
|
||||
{
|
||||
material.mainTexture = await getTexture(GetTextureParam.Create(src.pbrMetallicRoughness.baseColorTexture.index));
|
||||
material.mainTexture = await getTexture(gltf, BaseColorTexture(gltf, src));
|
||||
|
||||
// Texture Offset and Scale
|
||||
MaterialFactory.SetTextureOffsetAndScale(material, src.pbrMetallicRoughness.baseColorTexture, "_MainTex");
|
||||
@@ -75,9 +98,7 @@ namespace UniGLTF
|
||||
{
|
||||
material.EnableKeyword("_METALLICGLOSSMAP");
|
||||
|
||||
var texture = await getTexture(GetTextureParam.CreateMetallic(
|
||||
src.pbrMetallicRoughness.metallicRoughnessTexture.index,
|
||||
src.pbrMetallicRoughness.metallicFactor));
|
||||
var texture = await getTexture(gltf, MetallicRoughnessTexture(gltf, src));
|
||||
if (texture != null)
|
||||
{
|
||||
material.SetTexture(GetTextureParam.METALLIC_GLOSS_PROP, texture);
|
||||
@@ -100,7 +121,7 @@ namespace UniGLTF
|
||||
if (src.normalTexture != null && src.normalTexture.index != -1)
|
||||
{
|
||||
material.EnableKeyword("_NORMALMAP");
|
||||
var texture = await getTexture(GetTextureParam.CreateNormal(src.normalTexture.index));
|
||||
var texture = await getTexture(gltf, NormalTexture(gltf, src));
|
||||
if (texture != null)
|
||||
{
|
||||
material.SetTexture(GetTextureParam.NORMAL_PROP, texture);
|
||||
@@ -113,7 +134,7 @@ namespace UniGLTF
|
||||
|
||||
if (src.occlusionTexture != null && src.occlusionTexture.index != -1)
|
||||
{
|
||||
var texture = await getTexture(GetTextureParam.CreateOcclusion(src.occlusionTexture.index));
|
||||
var texture = await getTexture(gltf, OcclusionTexture(gltf, src));
|
||||
if (texture != null)
|
||||
{
|
||||
material.SetTexture(GetTextureParam.OCCLUSION_PROP, texture);
|
||||
@@ -137,7 +158,7 @@ namespace UniGLTF
|
||||
|
||||
if (src.emissiveTexture != null && src.emissiveTexture.index != -1)
|
||||
{
|
||||
var texture = await getTexture(GetTextureParam.Create(src.emissiveTexture.index));
|
||||
var texture = await getTexture(gltf, GetTextureParam.Create(gltf, src.emissiveTexture.index));
|
||||
if (texture != null)
|
||||
{
|
||||
material.SetTexture("_EmissionMap", texture);
|
||||
|
||||
@@ -7,19 +7,20 @@ namespace UniGLTF
|
||||
{
|
||||
public const string ShaderName = "UniGLTF/UniUnlit";
|
||||
|
||||
public static async Awaitable<Material> CreateAsync(int i, glTFMaterial src, GetTextureAsyncFunc getTexture, bool hasVertexColor)
|
||||
public static async Awaitable<Material> CreateAsync(glTF gltf, int i, GetTextureAsyncFunc getTexture, bool hasVertexColor)
|
||||
{
|
||||
if (getTexture == null)
|
||||
{
|
||||
getTexture = _ => Awaitable.FromResult<Texture2D>(null);
|
||||
getTexture = (_x, _y) => Awaitable.FromResult<Texture2D>(default);
|
||||
}
|
||||
|
||||
var src = gltf.materials[i];
|
||||
var material = MaterialFactory.CreateMaterial(i, src, ShaderName);
|
||||
|
||||
// texture
|
||||
if (src.pbrMetallicRoughness.baseColorTexture != null)
|
||||
{
|
||||
material.mainTexture = await getTexture(GetTextureParam.Create(src.pbrMetallicRoughness.baseColorTexture.index));
|
||||
material.mainTexture = await getTexture(gltf, GetTextureParam.Create(gltf, src.pbrMetallicRoughness.baseColorTexture.index));
|
||||
|
||||
// Texture Offset and Scale
|
||||
MaterialFactory.SetTextureOffsetAndScale(material, src.pbrMetallicRoughness.baseColorTexture, "_MainTex");
|
||||
|
||||
@@ -8,8 +8,6 @@ using UnityEngine;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
|
||||
|
||||
public class MeshImporter
|
||||
{
|
||||
const float FRAME_WEIGHT = 100.0f;
|
||||
@@ -109,7 +107,7 @@ namespace UniGLTF
|
||||
/// <param name="ctx"></param>
|
||||
/// <param name="gltfMesh"></param>
|
||||
/// <returns></returns>
|
||||
public void ImportMeshIndependentVertexBuffer(ImporterContext ctx, glTFMesh gltfMesh)
|
||||
public void ImportMeshIndependentVertexBuffer(ImporterContext ctx, glTFMesh gltfMesh, AxisInverter inverter)
|
||||
{
|
||||
foreach (var prim in gltfMesh.primitives)
|
||||
{
|
||||
@@ -119,7 +117,7 @@ namespace UniGLTF
|
||||
// position は必ずある
|
||||
var positions = ctx.GLTF.GetArrayFromAccessor<Vector3>(prim.attributes.POSITION);
|
||||
var fillLength = m_positions.Count;
|
||||
m_positions.AddRange(positions.Select(x => x.ReverseZ()));
|
||||
m_positions.AddRange(positions.Select(inverter.InvertVector3));
|
||||
|
||||
// normal
|
||||
if (prim.attributes.NORMAL != -1)
|
||||
@@ -130,7 +128,7 @@ namespace UniGLTF
|
||||
throw new Exception("different length");
|
||||
}
|
||||
FillZero(m_normals, fillLength);
|
||||
m_normals.AddRange(normals.Select(x => x.ReverseZ()));
|
||||
m_normals.AddRange(normals.Select(inverter.InvertVector3));
|
||||
}
|
||||
|
||||
#if false
|
||||
@@ -142,7 +140,7 @@ namespace UniGLTF
|
||||
throw new Exception("different length");
|
||||
}
|
||||
FillZero(tangetns, fillLength);
|
||||
tangents.AddRange(.Select(x => x.ReverseZ()));
|
||||
tangents.AddRange(.Select(inverter.InvertVector4));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -154,7 +152,7 @@ namespace UniGLTF
|
||||
{
|
||||
throw new Exception("different length");
|
||||
}
|
||||
if (ctx.IsGeneratedUniGLTFAndOlder(1, 16))
|
||||
if (ctx.Parser.IsGeneratedUniGLTFAndOlder(1, 16))
|
||||
{
|
||||
#pragma warning disable 0612
|
||||
// backward compatibility
|
||||
@@ -242,7 +240,7 @@ namespace UniGLTF
|
||||
throw new Exception("different length");
|
||||
}
|
||||
FillZero(blendShape.Positions, fillLength);
|
||||
blendShape.Positions.AddRange(array.Select(x => x.ReverseZ()).ToArray());
|
||||
blendShape.Positions.AddRange(array.Select(inverter.InvertVector3).ToArray());
|
||||
}
|
||||
if (primTarget.NORMAL != -1)
|
||||
{
|
||||
@@ -252,7 +250,7 @@ namespace UniGLTF
|
||||
throw new Exception("different length");
|
||||
}
|
||||
FillZero(blendShape.Normals, fillLength);
|
||||
blendShape.Normals.AddRange(array.Select(x => x.ReverseZ()).ToArray());
|
||||
blendShape.Normals.AddRange(array.Select(inverter.InvertVector3).ToArray());
|
||||
}
|
||||
if (primTarget.TANGENT != -1)
|
||||
{
|
||||
@@ -262,7 +260,7 @@ namespace UniGLTF
|
||||
throw new Exception("different length");
|
||||
}
|
||||
FillZero(blendShape.Tangents, fillLength);
|
||||
blendShape.Tangents.AddRange(array.Select(x => x.ReverseZ()).ToArray());
|
||||
blendShape.Tangents.AddRange(array.Select(inverter.InvertVector3).ToArray());
|
||||
}
|
||||
m_blendShapes.Add(blendShape);
|
||||
}
|
||||
@@ -293,31 +291,31 @@ namespace UniGLTF
|
||||
/// <param name="ctx"></param>
|
||||
/// <param name="gltfMesh"></param>
|
||||
/// <returns></returns>
|
||||
public void ImportMeshSharingVertexBuffer(ImporterContext ctx, glTFMesh gltfMesh)
|
||||
public void ImportMeshSharingVertexBuffer(ImporterContext ctx, glTFMesh gltfMesh, AxisInverter inverter)
|
||||
{
|
||||
{
|
||||
// 同じVertexBufferを共有しているので先頭のモノを使う
|
||||
var prim = gltfMesh.primitives.First();
|
||||
m_positions.AddRange(ctx.GLTF.GetArrayFromAccessor<Vector3>(prim.attributes.POSITION).SelectInplace(x => x.ReverseZ()));
|
||||
m_positions.AddRange(ctx.GLTF.GetArrayFromAccessor<Vector3>(prim.attributes.POSITION).SelectInplace(inverter.InvertVector3));
|
||||
|
||||
// normal
|
||||
if (prim.attributes.NORMAL != -1)
|
||||
{
|
||||
m_normals.AddRange(ctx.GLTF.GetArrayFromAccessor<Vector3>(prim.attributes.NORMAL).SelectInplace(x => x.ReverseZ()));
|
||||
m_normals.AddRange(ctx.GLTF.GetArrayFromAccessor<Vector3>(prim.attributes.NORMAL).SelectInplace(inverter.InvertVector3));
|
||||
}
|
||||
|
||||
#if false
|
||||
// tangent
|
||||
if (prim.attributes.TANGENT != -1)
|
||||
{
|
||||
tangents.AddRange(ctx.GLTF.GetArrayFromAccessor<Vector4>(prim.attributes.TANGENT).SelectInplace(x => x.ReverseZ()));
|
||||
tangents.AddRange(ctx.GLTF.GetArrayFromAccessor<Vector4>(prim.attributes.TANGENT).SelectInplace(inverter.InvertVector4));
|
||||
}
|
||||
#endif
|
||||
|
||||
// uv
|
||||
if (prim.attributes.TEXCOORD_0 != -1)
|
||||
{
|
||||
if (ctx.IsGeneratedUniGLTFAndOlder(1, 16))
|
||||
if (ctx.Parser.IsGeneratedUniGLTFAndOlder(1, 16))
|
||||
{
|
||||
#pragma warning disable 0612
|
||||
// backward compatibility
|
||||
@@ -403,17 +401,17 @@ namespace UniGLTF
|
||||
if (primTarget.POSITION != -1)
|
||||
{
|
||||
blendShape.Positions.Assign(
|
||||
ctx.GLTF.GetArrayFromAccessor<Vector3>(primTarget.POSITION), x => x.ReverseZ());
|
||||
ctx.GLTF.GetArrayFromAccessor<Vector3>(primTarget.POSITION), inverter.InvertVector3);
|
||||
}
|
||||
if (primTarget.NORMAL != -1)
|
||||
{
|
||||
blendShape.Normals.Assign(
|
||||
ctx.GLTF.GetArrayFromAccessor<Vector3>(primTarget.NORMAL), x => x.ReverseZ());
|
||||
ctx.GLTF.GetArrayFromAccessor<Vector3>(primTarget.NORMAL), inverter.InvertVector3);
|
||||
}
|
||||
if (primTarget.TANGENT != -1)
|
||||
{
|
||||
blendShape.Tangents.Assign(
|
||||
ctx.GLTF.GetArrayFromAccessor<Vector3>(primTarget.TANGENT), x => x.ReverseZ());
|
||||
ctx.GLTF.GetArrayFromAccessor<Vector3>(primTarget.TANGENT), inverter.InvertVector3);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -509,18 +507,18 @@ namespace UniGLTF
|
||||
return sharedAttributes;
|
||||
}
|
||||
|
||||
public MeshContext ReadMesh(ImporterContext ctx, int meshIndex)
|
||||
public MeshContext ReadMesh(ImporterContext ctx, int meshIndex, AxisInverter inverter)
|
||||
{
|
||||
var gltfMesh = ctx.GLTF.meshes[meshIndex];
|
||||
|
||||
var meshContext = new MeshContext(gltfMesh.name, meshIndex);
|
||||
if (HasSharedVertexBuffer(gltfMesh))
|
||||
{
|
||||
meshContext.ImportMeshSharingVertexBuffer(ctx, gltfMesh);
|
||||
meshContext.ImportMeshSharingVertexBuffer(ctx, gltfMesh, inverter);
|
||||
}
|
||||
else
|
||||
{
|
||||
meshContext.ImportMeshIndependentVertexBuffer(ctx, gltfMesh);
|
||||
meshContext.ImportMeshIndependentVertexBuffer(ctx, gltfMesh, inverter);
|
||||
}
|
||||
|
||||
meshContext.RenameBlendShape(gltfMesh);
|
||||
@@ -627,42 +625,15 @@ namespace UniGLTF
|
||||
}
|
||||
}
|
||||
|
||||
public static MeshWithMaterials BuildMesh(MaterialFactory ctx, MeshImporter.MeshContext meshContext)
|
||||
{
|
||||
var (mesh, recalculateTangents) = _BuildMesh(meshContext);
|
||||
|
||||
if (recalculateTangents)
|
||||
{
|
||||
mesh.RecalculateTangents();
|
||||
}
|
||||
|
||||
// 先にすべてのマテリアルを作成済みなのでテクスチャーは生成済み。Resultを使ってよい
|
||||
var result = new MeshWithMaterials
|
||||
{
|
||||
Mesh = mesh,
|
||||
Materials = meshContext.MaterialIndices.Select(x => ctx.GetMaterial(x)).ToArray()
|
||||
};
|
||||
|
||||
if (meshContext.BlendShapes.Count > 0)
|
||||
{
|
||||
var emptyVertices = new Vector3[mesh.vertexCount];
|
||||
foreach (var blendShape in meshContext.BlendShapes)
|
||||
{
|
||||
BuildBlendShape(mesh, meshContext, blendShape, emptyVertices);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static async Awaitable<MeshWithMaterials> BuildMeshAsync(MaterialFactory ctx, MeshImporter.MeshContext meshContext)
|
||||
{
|
||||
var (mesh, recalculateTangents) = _BuildMesh(meshContext);
|
||||
|
||||
if (recalculateTangents)
|
||||
{
|
||||
await LoopAwaitable.Create();
|
||||
await NextFrameAwaitable.Create();
|
||||
mesh.RecalculateTangents();
|
||||
await LoopAwaitable.Create();
|
||||
await NextFrameAwaitable.Create();
|
||||
}
|
||||
|
||||
// 先にすべてのマテリアルを作成済みなのでテクスチャーは生成済み。Resultを使ってよい
|
||||
@@ -672,7 +643,7 @@ namespace UniGLTF
|
||||
Materials = meshContext.MaterialIndices.Select(x => ctx.GetMaterial(x)).ToArray()
|
||||
};
|
||||
|
||||
await LoopAwaitable.Create();
|
||||
await NextFrameAwaitable.Create();
|
||||
if (meshContext.BlendShapes.Count > 0)
|
||||
{
|
||||
var emptyVertices = new Vector3[mesh.vertexCount];
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace UniGLTF
|
||||
Debug.LogWarningFormat("node {0} contains /. replace _", node.name);
|
||||
nodeName = nodeName.Replace("/", "_");
|
||||
}
|
||||
if(string.IsNullOrEmpty(nodeName))
|
||||
if (string.IsNullOrEmpty(nodeName))
|
||||
{
|
||||
nodeName = string.Format("nodeIndex_{0}", nodeIndex);
|
||||
}
|
||||
@@ -131,7 +131,7 @@ namespace UniGLTF
|
||||
//
|
||||
// fix node's coordinate. z-back to z-forward
|
||||
//
|
||||
public static void FixCoordinate(ImporterContext context, List<TransformWithSkin> nodes)
|
||||
public static void FixCoordinate(ImporterContext context, List<TransformWithSkin> nodes, AxisInverter inverter)
|
||||
{
|
||||
var globalTransformMap = nodes.ToDictionary(x => x.Transform, x => new PosRot
|
||||
{
|
||||
@@ -148,13 +148,13 @@ namespace UniGLTF
|
||||
foreach (var transform in t.Traverse())
|
||||
{
|
||||
var g = globalTransformMap[transform];
|
||||
transform.position = g.Position.ReverseZ();
|
||||
transform.rotation = g.Rotation.ReverseZ();
|
||||
transform.position = inverter.InvertVector3(g.Position);
|
||||
transform.rotation = inverter.InvertQuaternion(g.Rotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetupSkinning(ImporterContext context, List<TransformWithSkin> nodes, int i)
|
||||
public static void SetupSkinning(ImporterContext context, List<TransformWithSkin> nodes, int i, AxisInverter inverter)
|
||||
{
|
||||
var x = nodes[i];
|
||||
var skinnedMeshRenderer = x.Transform.GetComponent<SkinnedMeshRenderer>();
|
||||
@@ -181,7 +181,7 @@ namespace UniGLTF
|
||||
if (skin.inverseBindMatrices != -1)
|
||||
{
|
||||
var bindPoses = context.GLTF.GetArrayFromAccessor<Matrix4x4>(skin.inverseBindMatrices)
|
||||
.Select(y => y.ReverseZ())
|
||||
.Select(inverter.InvertMat4)
|
||||
.ToArray()
|
||||
;
|
||||
mesh.bindposes = bindPoses;
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace UniGLTF
|
||||
if (context.GLTF.animations != null && context.GLTF.animations.Any())
|
||||
{
|
||||
var animation = context.Root.AddComponent<Animation>();
|
||||
context.AnimationClips = ImportAnimationClips(context.GLTF);
|
||||
context.AnimationClips = ImportAnimationClips(context.GLTF, context.InvertAxis);
|
||||
|
||||
foreach (var clip in context.AnimationClips)
|
||||
{
|
||||
@@ -25,7 +25,7 @@ namespace UniGLTF
|
||||
}
|
||||
}
|
||||
|
||||
private List<AnimationClip> ImportAnimationClips(glTF gltf)
|
||||
private List<AnimationClip> ImportAnimationClips(glTF gltf, Axises invertAxis)
|
||||
{
|
||||
var animationClips = new List<AnimationClip>();
|
||||
for (var i = 0; i < gltf.animations.Count; ++i)
|
||||
@@ -46,7 +46,23 @@ namespace UniGLTF
|
||||
animation.name = $"animation:{i}";
|
||||
}
|
||||
|
||||
animationClips.Add(AnimationImporterUtil.ConvertAnimationClip(gltf, animation));
|
||||
AxisInverter inverter = default;
|
||||
switch (invertAxis)
|
||||
{
|
||||
case Axises.X:
|
||||
inverter = AxisInverter.ReverseX;
|
||||
break;
|
||||
|
||||
case Axises.Z:
|
||||
inverter = AxisInverter.ReverseZ;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new System.Exception();
|
||||
|
||||
}
|
||||
|
||||
animationClips.Add(AnimationImporterUtil.ConvertAnimationClip(gltf, animation, inverter));
|
||||
}
|
||||
|
||||
return animationClips;
|
||||
|
||||
@@ -31,22 +31,6 @@ namespace UniGLTF
|
||||
return copyTexture;
|
||||
}
|
||||
|
||||
public static void AppendTextureExtension(Texture texture, string extension)
|
||||
{
|
||||
if (!texture.name.EndsWith(extension))
|
||||
{
|
||||
texture.name = texture.name + extension;
|
||||
}
|
||||
}
|
||||
|
||||
public static void RemoveTextureExtension(Texture texture, string extension)
|
||||
{
|
||||
if (texture.name.EndsWith(extension))
|
||||
{
|
||||
texture.name = texture.name.Replace(extension, "");
|
||||
}
|
||||
}
|
||||
|
||||
struct ColorSpaceScope : IDisposable
|
||||
{
|
||||
bool m_sRGBWrite;
|
||||
@@ -194,8 +178,6 @@ namespace UniGLTF
|
||||
|
||||
public class MetallicRoughnessConverter : ITextureConverter
|
||||
{
|
||||
private const string m_extension = ".metallicRoughness";
|
||||
|
||||
private float _smoothnessOrRoughness;
|
||||
|
||||
public MetallicRoughnessConverter(float smoothnessOrRoughness)
|
||||
@@ -206,14 +188,12 @@ namespace UniGLTF
|
||||
public Texture2D GetImportTexture(Texture2D texture)
|
||||
{
|
||||
var converted = TextureConverter.Convert(texture, glTFTextureTypes.Metallic, Import, null);
|
||||
TextureConverter.AppendTextureExtension(converted, m_extension);
|
||||
return converted;
|
||||
}
|
||||
|
||||
public Texture2D GetExportTexture(Texture2D texture)
|
||||
{
|
||||
var converted = TextureConverter.Convert(texture, glTFTextureTypes.Metallic, Export, null);
|
||||
TextureConverter.RemoveTextureExtension(converted, m_extension);
|
||||
return converted;
|
||||
}
|
||||
|
||||
@@ -260,8 +240,6 @@ namespace UniGLTF
|
||||
|
||||
public class NormalConverter : ITextureConverter
|
||||
{
|
||||
private const string m_extension = ".normal";
|
||||
|
||||
private Material m_decoder;
|
||||
private Material GetDecoder()
|
||||
{
|
||||
@@ -288,7 +266,6 @@ namespace UniGLTF
|
||||
{
|
||||
var mat = GetEncoder();
|
||||
var converted = TextureConverter.Convert(texture, glTFTextureTypes.Normal, null, mat);
|
||||
TextureConverter.AppendTextureExtension(converted, m_extension);
|
||||
return converted;
|
||||
}
|
||||
|
||||
@@ -298,26 +275,22 @@ namespace UniGLTF
|
||||
{
|
||||
var mat = GetDecoder();
|
||||
var converted = TextureConverter.Convert(texture, glTFTextureTypes.Normal, null, mat);
|
||||
TextureConverter.RemoveTextureExtension(converted, m_extension);
|
||||
return converted;
|
||||
}
|
||||
}
|
||||
|
||||
public class OcclusionConverter : ITextureConverter
|
||||
{
|
||||
private const string m_extension = ".occlusion";
|
||||
|
||||
public Texture2D GetImportTexture(Texture2D texture)
|
||||
{
|
||||
var converted = TextureConverter.Convert(texture, glTFTextureTypes.Occlusion, Import, null);
|
||||
TextureConverter.AppendTextureExtension(converted, m_extension);
|
||||
return converted;
|
||||
}
|
||||
|
||||
public Texture2D GetExportTexture(Texture2D texture)
|
||||
{
|
||||
var converted = TextureConverter.Convert(texture, glTFTextureTypes.Occlusion, Export, null);
|
||||
TextureConverter.RemoveTextureExtension(converted, m_extension);
|
||||
return converted;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using System;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
@@ -9,6 +8,7 @@ namespace UniGLTF
|
||||
public const string METALLIC_GLOSS_PROP = "_MetallicGlossMap";
|
||||
public const string OCCLUSION_PROP = "_OcclusionMap";
|
||||
|
||||
public readonly string Name;
|
||||
public readonly string TextureType;
|
||||
public readonly float MetallicFactor;
|
||||
public readonly ushort? Index0;
|
||||
@@ -18,8 +18,14 @@ namespace UniGLTF
|
||||
public readonly ushort? Index4;
|
||||
public readonly ushort? Index5;
|
||||
|
||||
public GetTextureParam(string textureType, float metallicFactor, int i0, int i1, int i2, int i3, int i4, int i5)
|
||||
public GetTextureParam(string name, string textureType, float metallicFactor, int i0, int i1, int i2, int i3, int i4, int i5)
|
||||
{
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
throw new ArgumentNullException();
|
||||
}
|
||||
Name = name;
|
||||
|
||||
TextureType = textureType;
|
||||
MetallicFactor = metallicFactor;
|
||||
Index0 = (ushort)i0;
|
||||
@@ -30,25 +36,46 @@ namespace UniGLTF
|
||||
Index5 = (ushort)i5;
|
||||
}
|
||||
|
||||
public static GetTextureParam Create(int index)
|
||||
public static GetTextureParam Create(glTF gltf, int textureIndex)
|
||||
{
|
||||
return new GetTextureParam(default, default, index, default, default, default, default, default);
|
||||
var name = gltf.textures[textureIndex].name;
|
||||
return new GetTextureParam(name, default, default, textureIndex, default, default, default, default, default);
|
||||
}
|
||||
|
||||
public static GetTextureParam CreateNormal(int index)
|
||||
public static GetTextureParam Create(glTF gltf, int index, string prop)
|
||||
{
|
||||
return new GetTextureParam(NORMAL_PROP, default, index, default, default, default, default, default);
|
||||
switch (prop)
|
||||
{
|
||||
case NORMAL_PROP:
|
||||
return CreateNormal(gltf, index);
|
||||
|
||||
case OCCLUSION_PROP:
|
||||
return CreateOcclusion(gltf, index);
|
||||
|
||||
case METALLIC_GLOSS_PROP:
|
||||
return CreateMetallic(gltf, index, 1);
|
||||
|
||||
default:
|
||||
return Create(gltf, index);
|
||||
}
|
||||
}
|
||||
|
||||
public static GetTextureParam CreateMetallic(int index, float metallicFactor)
|
||||
public static GetTextureParam CreateNormal(glTF gltf, int textureIndex)
|
||||
{
|
||||
return new GetTextureParam(METALLIC_GLOSS_PROP, metallicFactor, index, default, default, default, default, default);
|
||||
var name = gltf.textures[textureIndex].name;
|
||||
return new GetTextureParam(name, NORMAL_PROP, default, textureIndex, default, default, default, default, default);
|
||||
}
|
||||
|
||||
public static GetTextureParam CreateOcclusion(int index)
|
||||
public static GetTextureParam CreateMetallic(glTF gltf, int textureIndex, float metallicFactor)
|
||||
{
|
||||
return new GetTextureParam(OCCLUSION_PROP, default, index, default, default, default, default, default);
|
||||
var name = gltf.textures[textureIndex].name;
|
||||
return new GetTextureParam(name + ".metallicRoughness", METALLIC_GLOSS_PROP, metallicFactor, textureIndex, default, default, default, default, default);
|
||||
}
|
||||
|
||||
public static GetTextureParam CreateOcclusion(glTF gltf, int textureIndex)
|
||||
{
|
||||
var name = gltf.textures[textureIndex].name;
|
||||
return new GetTextureParam(name + ".occlusion", OCCLUSION_PROP, default, textureIndex, default, default, default, default, default);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,27 +24,25 @@ namespace UniGLTF
|
||||
}
|
||||
}
|
||||
|
||||
public static async Awaitable<Texture2D> LoadTextureAsync(glTF gltf, IStorage storage, int index)
|
||||
public static async Awaitable<Texture2D> LoadTextureAsync(glTF gltf, IStorage storage, int textureIndex)
|
||||
{
|
||||
string m_textureName = default;
|
||||
|
||||
var imageBytes = await Awaitable.Run(() =>
|
||||
{
|
||||
var imageIndex = gltf.GetImageIndexFromTextureIndex(index);
|
||||
var segments = gltf.GetImageBytes(storage, imageIndex, out m_textureName);
|
||||
var imageIndex = gltf.textures[textureIndex].source;
|
||||
var segments = gltf.GetImageBytes(storage, imageIndex);
|
||||
return ToArray(segments);
|
||||
});
|
||||
|
||||
//
|
||||
// texture from image(png etc) bytes
|
||||
//
|
||||
var textureType = TextureIO.GetglTFTextureType(gltf, index);
|
||||
var textureType = TextureIO.GetglTFTextureType(gltf, textureIndex);
|
||||
var colorSpace = TextureIO.GetColorSpace(textureType);
|
||||
var isLinear = colorSpace == RenderTextureReadWrite.Linear;
|
||||
var sampler = gltf.GetSamplerFromTextureIndex(index);
|
||||
var sampler = gltf.GetSamplerFromTextureIndex(textureIndex);
|
||||
|
||||
var texture = new Texture2D(2, 2, TextureFormat.ARGB32, false, isLinear);
|
||||
texture.name = m_textureName;
|
||||
texture.name = gltf.textures[textureIndex].name;
|
||||
if (imageBytes != null)
|
||||
{
|
||||
texture.LoadImage(imageBytes);
|
||||
|
||||
@@ -1,28 +1,82 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using UniGLTF.AltTask;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using System.Linq;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public delegate Awaitable<Texture2D> GetTextureAsyncFunc(GetTextureParam param);
|
||||
public class TextureFactory : IDisposable
|
||||
[Flags]
|
||||
public enum TextureLoadFlags
|
||||
{
|
||||
None = 0,
|
||||
Used = 1,
|
||||
External = 1 << 1,
|
||||
}
|
||||
|
||||
public struct TextureLoadInfo
|
||||
{
|
||||
public readonly Texture2D Texture;
|
||||
public readonly TextureLoadFlags Flags;
|
||||
public bool IsUsed => Flags.HasFlag(TextureLoadFlags.Used);
|
||||
public bool IsExternal => Flags.HasFlag(TextureLoadFlags.External);
|
||||
|
||||
public TextureLoadInfo(Texture2D texture, bool used, bool isExternal)
|
||||
{
|
||||
Texture = texture;
|
||||
var flags = TextureLoadFlags.None;
|
||||
if (used)
|
||||
{
|
||||
flags |= TextureLoadFlags.Used;
|
||||
}
|
||||
if (isExternal)
|
||||
{
|
||||
flags |= TextureLoadFlags.External;
|
||||
}
|
||||
Flags = flags;
|
||||
}
|
||||
}
|
||||
|
||||
public delegate Awaitable<Texture2D> GetTextureAsyncFunc(glTF gltf, GetTextureParam param);
|
||||
public class TextureFactory : IDisposable
|
||||
{
|
||||
glTF m_gltf;
|
||||
IStorage m_storage;
|
||||
Dictionary<string, Texture2D> m_externalMap;
|
||||
public bool TryGetExternal(GetTextureParam param, bool used, out Texture2D external)
|
||||
{
|
||||
if (param.Index0.HasValue && m_externalMap != null)
|
||||
{
|
||||
if (m_externalMap.TryGetValue(param.Name, out external))
|
||||
{
|
||||
// Debug.Log($"use external: {param.Name}");
|
||||
m_textureCache.Add(param.Name, new TextureLoadInfo(external, used, true));
|
||||
return external;
|
||||
}
|
||||
}
|
||||
external = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
public UnityPath ImageBaseDir { get; set; }
|
||||
|
||||
public TextureFactory(glTF gltf, IStorage storage)
|
||||
public TextureFactory(glTF gltf, IStorage storage,
|
||||
IEnumerable<(string, UnityEngine.Object)> externalMap)
|
||||
{
|
||||
m_gltf = gltf;
|
||||
m_storage = storage;
|
||||
if (externalMap != null)
|
||||
{
|
||||
m_externalMap = externalMap
|
||||
.Select(kv => (kv.Item1, kv.Item2 as Texture2D))
|
||||
.Where(kv => kv.Item2 != null)
|
||||
.ToDictionary(kv => kv.Item1, kv => kv.Item2);
|
||||
}
|
||||
}
|
||||
|
||||
List<Texture2D> m_textuers = new List<Texture2D>();
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var x in ObjectsForSubAsset())
|
||||
@@ -35,21 +89,35 @@ namespace UniGLTF
|
||||
{
|
||||
foreach (var kv in m_textureCache)
|
||||
{
|
||||
yield return kv.Value;
|
||||
yield return kv.Value.Texture;
|
||||
}
|
||||
}
|
||||
|
||||
Dictionary<GetTextureParam, Texture2D> m_textureCache = new Dictionary<GetTextureParam, Texture2D>();
|
||||
Dictionary<string, TextureLoadInfo> m_textureCache = new Dictionary<string, TextureLoadInfo>();
|
||||
|
||||
public virtual Awaitable<Texture2D> LoadTextureAsync(int index)
|
||||
public IEnumerable<TextureLoadInfo> Textures => m_textureCache.Values;
|
||||
|
||||
public virtual async Awaitable<TextureLoadInfo> LoadTextureAsync(int index, bool used)
|
||||
{
|
||||
#if UNIGLTF_USE_WEBREQUEST_TEXTURELOADER
|
||||
return UnityWebRequestTextureLoader.LoadTextureAsync(index);
|
||||
#else
|
||||
return GltfTextureLoader.LoadTextureAsync(m_gltf, m_storage, index);
|
||||
var texture = await GltfTextureLoader.LoadTextureAsync(m_gltf, m_storage, index);
|
||||
return new TextureLoadInfo(texture, used, false);
|
||||
#endif
|
||||
}
|
||||
|
||||
async Awaitable<TextureLoadInfo> GetOrCreateBaseTexture(glTF gltf, int textureIndex, bool used)
|
||||
{
|
||||
var name = gltf.textures[textureIndex].name;
|
||||
if (!m_textureCache.TryGetValue(name, out TextureLoadInfo cacheInfo))
|
||||
{
|
||||
cacheInfo = await LoadTextureAsync(textureIndex, used);
|
||||
m_textureCache.Add(name, cacheInfo);
|
||||
}
|
||||
return cacheInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// テクスチャーをロード、必要であれば変換して返す。
|
||||
/// 同じものはキャッシュを返す
|
||||
@@ -58,20 +126,15 @@ namespace UniGLTF
|
||||
/// <param name="roughnessFactor">METALLIC_GLOSS_PROPの追加パラメーター</param>
|
||||
/// <param name="indices">gltf の texture index</param>
|
||||
/// <returns></returns>
|
||||
public async Awaitable<Texture2D> GetTextureAsync(GetTextureParam param)
|
||||
public async Awaitable<Texture2D> GetTextureAsync(glTF gltf, GetTextureParam param)
|
||||
{
|
||||
if (m_textureCache.TryGetValue(param, out Texture2D texture))
|
||||
if (m_textureCache.TryGetValue(param.Name, out TextureLoadInfo cacheInfo))
|
||||
{
|
||||
return texture;
|
||||
return cacheInfo.Texture;
|
||||
}
|
||||
|
||||
if (TryGetExternal(param, true, out Texture2D external))
|
||||
{
|
||||
var defaultParam = GetTextureParam.Create(param.Index0.Value);
|
||||
if (!m_textureCache.TryGetValue(defaultParam, out texture))
|
||||
{
|
||||
texture = await LoadTextureAsync(param.Index0.Value);
|
||||
m_textureCache.Add(defaultParam, texture);
|
||||
}
|
||||
return external;
|
||||
}
|
||||
|
||||
switch (param.TextureType)
|
||||
@@ -80,48 +143,55 @@ namespace UniGLTF
|
||||
{
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
var converted = new NormalConverter().GetImportTexture(texture);
|
||||
m_textureCache.Add(param, converted);
|
||||
return converted;
|
||||
var baseTexture = await GetOrCreateBaseTexture(gltf, param.Index0.Value, false);
|
||||
var converted = new NormalConverter().GetImportTexture(baseTexture.Texture);
|
||||
var info = new TextureLoadInfo(converted, true, false);
|
||||
m_textureCache.Add(param.Name, info);
|
||||
return info.Texture;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
var textureAssetPath = AssetDatabase.GetAssetPath(texture);
|
||||
if (!string.IsNullOrEmpty(textureAssetPath))
|
||||
{
|
||||
TextureIO.MarkTextureAssetAsNormalMap(textureAssetPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarningFormat("no asset for {0}", texture);
|
||||
}
|
||||
var info = await LoadTextureAsync(param.Index0.Value, true);
|
||||
var name = gltf.textures[param.Index0.Value].name;
|
||||
m_textureCache.Add(name, info);
|
||||
|
||||
var textureAssetPath = AssetDatabase.GetAssetPath(info.Texture);
|
||||
TextureIO.MarkTextureAssetAsNormalMap(textureAssetPath);
|
||||
#endif
|
||||
m_textureCache.Add(param, texture);
|
||||
return texture;
|
||||
return info.Texture;
|
||||
}
|
||||
}
|
||||
|
||||
case GetTextureParam.METALLIC_GLOSS_PROP:
|
||||
{
|
||||
// Bake roughnessFactor values into a texture.
|
||||
var converted = new MetallicRoughnessConverter(param.MetallicFactor).GetImportTexture(texture);
|
||||
m_textureCache.Add(param, converted);
|
||||
return converted;
|
||||
var baseTexture = await GetOrCreateBaseTexture(gltf, param.Index0.Value, false);
|
||||
var converted = new MetallicRoughnessConverter(param.MetallicFactor).GetImportTexture(baseTexture.Texture);
|
||||
converted.name = param.Name;
|
||||
var info = new TextureLoadInfo(converted, true, false);
|
||||
m_textureCache.Add(param.Name, info);
|
||||
return info.Texture;
|
||||
}
|
||||
|
||||
case GetTextureParam.OCCLUSION_PROP:
|
||||
{
|
||||
var converted = new OcclusionConverter().GetImportTexture(texture);
|
||||
m_textureCache.Add(param, converted);
|
||||
return converted;
|
||||
var baseTexture = await GetOrCreateBaseTexture(gltf, param.Index0.Value, false);
|
||||
var converted = new OcclusionConverter().GetImportTexture(baseTexture.Texture);
|
||||
converted.name = param.Name;
|
||||
var info = new TextureLoadInfo(converted, true, false);
|
||||
m_textureCache.Add(param.Name, info);
|
||||
return info.Texture;
|
||||
}
|
||||
|
||||
default:
|
||||
return texture;
|
||||
}
|
||||
{
|
||||
var baseTexture = await GetOrCreateBaseTexture(gltf, param.Index0.Value, true);
|
||||
return baseTexture.Texture;
|
||||
}
|
||||
|
||||
throw new NotImplementedException();
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,8 +55,8 @@ namespace UniGLTF
|
||||
|
||||
public IEnumerator ProcessOnMainThread(glTF gltf, IStorage storage, bool isLinear, glTFTextureSampler sampler)
|
||||
{
|
||||
var imageIndex = gltf.GetImageIndexFromTextureIndex(m_textureIndex);
|
||||
var bytes = gltf.GetImageBytes(storage, imageIndex, out m_textureName);
|
||||
var gltfTexture = gltf.textures[m_textureIndex];
|
||||
var bytes = gltf.GetImageBytes(storage, gltfTexture.source);
|
||||
|
||||
// tmp file
|
||||
var tmp = Path.GetTempFileName();
|
||||
|
||||
@@ -98,7 +98,7 @@ namespace UniGLTF
|
||||
public void UniGLTFSimpleSceneTest()
|
||||
{
|
||||
var go = CreateSimpleScene();
|
||||
var context = new ImporterContext();
|
||||
ImporterContext context = default;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -117,9 +117,12 @@ namespace UniGLTF
|
||||
json = gltf.ToJson();
|
||||
}
|
||||
|
||||
// parse
|
||||
var parser = new GltfParser();
|
||||
parser.ParseJson(json, new SimpleStorage(new ArraySegment<byte>()));
|
||||
|
||||
// import
|
||||
context.ParseJson(json, new SimpleStorage(new ArraySegment<byte>()));
|
||||
//Debug.LogFormat("{0}", context.Json);
|
||||
context = new ImporterContext(parser);
|
||||
context.Load();
|
||||
|
||||
AssertAreEqual(go.transform, context.Root.transform);
|
||||
@@ -128,7 +131,10 @@ namespace UniGLTF
|
||||
{
|
||||
//Debug.LogFormat("Destroy, {0}", go.name);
|
||||
GameObject.DestroyImmediate(go);
|
||||
context.EditorDestroyRootAndAssets();
|
||||
if (context != null)
|
||||
{
|
||||
context.EditorDestroyRootAndAssets();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,12 +197,12 @@ namespace UniGLTF
|
||||
[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));
|
||||
Assert.False(GltfParser.IsGeneratedUniGLTFAndOlderThan("hoge", 1, 16));
|
||||
Assert.False(GltfParser.IsGeneratedUniGLTFAndOlderThan("UniGLTF-1.16", 1, 16));
|
||||
Assert.True(GltfParser.IsGeneratedUniGLTFAndOlderThan("UniGLTF-1.15", 1, 16));
|
||||
Assert.False(GltfParser.IsGeneratedUniGLTFAndOlderThan("UniGLTF-11.16", 1, 16));
|
||||
Assert.True(GltfParser.IsGeneratedUniGLTFAndOlderThan("UniGLTF-0.16", 1, 16));
|
||||
Assert.True(GltfParser.IsGeneratedUniGLTFAndOlderThan("UniGLTF", 1, 16));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -439,7 +445,7 @@ namespace UniGLTF
|
||||
public void SkinTestEmptyName()
|
||||
{
|
||||
var model = new glTFSkin()
|
||||
{
|
||||
{
|
||||
name = "",
|
||||
inverseBindMatrices = 4,
|
||||
joints = new int[] { 1 },
|
||||
@@ -559,8 +565,9 @@ namespace UniGLTF
|
||||
|
||||
// import
|
||||
{
|
||||
var context = new ImporterContext();
|
||||
context.ParseJson(json, new SimpleStorage(new ArraySegment<byte>(new byte[1024 * 1024])));
|
||||
var parser = new GltfParser();
|
||||
parser.ParseJson(json, new SimpleStorage(new ArraySegment<byte>(new byte[1024 * 1024])));
|
||||
var context = new ImporterContext(parser);
|
||||
//Debug.LogFormat("{0}", context.Json);
|
||||
context.Load();
|
||||
|
||||
@@ -577,9 +584,10 @@ namespace UniGLTF
|
||||
|
||||
// import new version
|
||||
{
|
||||
var context = new ImporterContext();
|
||||
context.ParseJson(json, new SimpleStorage(new ArraySegment<byte>(new byte[1024 * 1024])));
|
||||
var parser = new GltfParser();
|
||||
parser.ParseJson(json, new SimpleStorage(new ArraySegment<byte>(new byte[1024 * 1024])));
|
||||
//Debug.LogFormat("{0}", context.Json);
|
||||
var context = new ImporterContext(parser);
|
||||
context.Load();
|
||||
|
||||
var importedRed = context.Root.transform.GetChild(0);
|
||||
|
||||
@@ -42,8 +42,10 @@ namespace VRM.Samples
|
||||
public void ImportExportTest()
|
||||
{
|
||||
var path = AliciaPath;
|
||||
var context = new VRMImporterContext();
|
||||
context.ParseGlb(File.ReadAllBytes(path));
|
||||
var parser = new GltfParser();
|
||||
parser.ParseGlb(File.ReadAllBytes(path));
|
||||
|
||||
var context = new VRMImporterContext(parser);
|
||||
context.Load();
|
||||
context.ShowMeshes();
|
||||
context.EnableUpdateWhenOffscreen();
|
||||
@@ -114,8 +116,9 @@ namespace VRM.Samples
|
||||
public void MeshCopyTest()
|
||||
{
|
||||
var path = AliciaPath;
|
||||
var context = new VRMImporterContext();
|
||||
context.ParseGlb(File.ReadAllBytes(path));
|
||||
var parser = new GltfParser();
|
||||
parser.ParseGlb(File.ReadAllBytes(path));
|
||||
var context = new VRMImporterContext(parser);
|
||||
context.Load();
|
||||
context.ShowMeshes();
|
||||
context.EnableUpdateWhenOffscreen();
|
||||
@@ -133,8 +136,9 @@ namespace VRM.Samples
|
||||
{
|
||||
// Aliciaを古いデシリアライザでロードする
|
||||
var path = AliciaPath;
|
||||
var context = new VRMImporterContext();
|
||||
context.ParseGlb(File.ReadAllBytes(path));
|
||||
var parser = new GltfParser();
|
||||
parser.ParseGlb(File.ReadAllBytes(path));
|
||||
var context = new VRMImporterContext(parser);
|
||||
var oldJson = context.GLTF.ToJson().ParseAsJson().ToString(" ");
|
||||
|
||||
// 生成シリアライザでJSON化する
|
||||
|
||||
@@ -46,11 +46,11 @@ namespace VRM.Samples
|
||||
var bytes = File.ReadAllBytes(path);
|
||||
// なんらかの方法でByte列を得た
|
||||
|
||||
var context = new VRMImporterContext();
|
||||
|
||||
// GLB形式でJSONを取得しParseします
|
||||
context.ParseGlb(bytes);
|
||||
var parser = new GltfParser();
|
||||
parser.ParseGlb(bytes);
|
||||
|
||||
var context = new VRMImporterContext(parser);
|
||||
|
||||
// metaを取得(todo: thumbnailテクスチャのロード)
|
||||
var meta = await context.ReadMetaAsync();
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
#pragma warning disable 0414
|
||||
using System.IO;
|
||||
using UniGLTF;
|
||||
using UniGLTF.AltTask;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace VRM.Samples
|
||||
{
|
||||
|
||||
|
||||
public class VRMRuntimeLoader : MonoBehaviour
|
||||
{
|
||||
[SerializeField]
|
||||
@@ -89,33 +86,33 @@ namespace VRM.Samples
|
||||
var bytes = File.ReadAllBytes(path);
|
||||
// なんらかの方法でByte列を得た
|
||||
|
||||
var context = new VRMImporterContext();
|
||||
|
||||
// GLB形式でJSONを取得しParseします
|
||||
context.ParseGlb(bytes);
|
||||
var parser = new GltfParser();
|
||||
parser.Parse(path, bytes);
|
||||
|
||||
var context = new VRMImporterContext(parser);
|
||||
|
||||
// metaを取得(todo: thumbnailテクスチャのロード)
|
||||
var meta = await context.ReadMetaAsync();
|
||||
Debug.LogFormat("meta: title:{0}", meta.Title);
|
||||
|
||||
|
||||
// ParseしたJSONをシーンオブジェクトに変換していく
|
||||
if (m_loadAsync)
|
||||
{
|
||||
await LoadAsync(context);
|
||||
await context.LoadAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
context.LoadAsync();
|
||||
OnLoaded(context);
|
||||
context.Load();
|
||||
}
|
||||
|
||||
OnLoaded(context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// メタが不要な場合のローダー
|
||||
/// </summary>
|
||||
void LoadVRMClicked_without_meta()
|
||||
async void LoadVRMClicked_without_meta()
|
||||
{
|
||||
#if UNITY_STANDALONE_WIN
|
||||
var path = FileDialogForWindows.FileDialog("open VRM", ".vrm");
|
||||
@@ -129,55 +126,23 @@ namespace VRM.Samples
|
||||
return;
|
||||
}
|
||||
|
||||
#if true
|
||||
var bytes = File.ReadAllBytes(path);
|
||||
// なんらかの方法でByte列を得た
|
||||
|
||||
var context = new VRMImporterContext();
|
||||
|
||||
// GLB形式でJSONを取得しParseします
|
||||
context.ParseGlb(bytes);
|
||||
var parser = new GltfParser();
|
||||
parser.ParseGlb(bytes);
|
||||
|
||||
var context = new VRMImporterContext(parser);
|
||||
if (m_loadAsync)
|
||||
{
|
||||
// ローカルファイルシステムからロードします
|
||||
LoadAsync(context);
|
||||
await context.LoadAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Load();
|
||||
OnLoaded(context);
|
||||
}
|
||||
|
||||
#else
|
||||
// ParseしたJSONをシーンオブジェクトに変換していく
|
||||
if (m_loadAsync)
|
||||
{
|
||||
// ローカルファイルシステムからロードします
|
||||
VRMImporter.LoadVrmAsync(path, OnLoaded);
|
||||
}
|
||||
else
|
||||
{
|
||||
var root=VRMImporter.LoadFromPath(path);
|
||||
OnLoaded(root);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
async Awaitable LoadAsync(VRMImporterContext context)
|
||||
{
|
||||
#if true
|
||||
var now = Time.time;
|
||||
await context.LoadAsync();
|
||||
|
||||
var delta = Time.time - now;
|
||||
Debug.LogFormat("LoadAsync {0:0.0} seconds", delta);
|
||||
OnLoaded(context);
|
||||
#else
|
||||
// ローカルファイルシステムからロードします
|
||||
VRMImporter.LoadVrmAsync(path, OnLoaded);
|
||||
#endif
|
||||
}
|
||||
|
||||
void LoadBVHClicked()
|
||||
|
||||
@@ -309,15 +309,15 @@ namespace VRM.Samples
|
||||
{
|
||||
case ".vrm":
|
||||
{
|
||||
var context = new VRMImporterContext();
|
||||
var file = File.ReadAllBytes(path);
|
||||
context.ParseGlb(file);
|
||||
|
||||
var parser = new GltfParser();
|
||||
parser.ParseGlb(file);
|
||||
|
||||
var context = new VRMImporterContext(parser);
|
||||
await m_texts.UpdateMetaAsync(context);
|
||||
#if true
|
||||
await context.LoadAsync();
|
||||
#else
|
||||
context.Load();
|
||||
#endif
|
||||
|
||||
context.ShowMeshes();
|
||||
context.EnableUpdateWhenOffscreen();
|
||||
context.ShowMeshes();
|
||||
@@ -327,9 +327,11 @@ namespace VRM.Samples
|
||||
|
||||
case ".glb":
|
||||
{
|
||||
var context = new UniGLTF.ImporterContext();
|
||||
var file = File.ReadAllBytes(path);
|
||||
context.ParseGlb(file);
|
||||
var parser = new GltfParser();
|
||||
parser.ParseGlb(file);
|
||||
|
||||
var context = new UniGLTF.ImporterContext(parser);
|
||||
context.Load();
|
||||
context.ShowMeshes();
|
||||
context.EnableUpdateWhenOffscreen();
|
||||
@@ -341,8 +343,10 @@ namespace VRM.Samples
|
||||
case ".gltf":
|
||||
case ".zip":
|
||||
{
|
||||
var context = new UniGLTF.ImporterContext();
|
||||
context.Parse(path);
|
||||
var parser = new GltfParser();
|
||||
parser.ParsePath(path);
|
||||
|
||||
var context = new UniGLTF.ImporterContext(parser);
|
||||
context.Load();
|
||||
context.ShowMeshes();
|
||||
context.EnableUpdateWhenOffscreen();
|
||||
|
||||
@@ -20,8 +20,10 @@ namespace VRM
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
// load into scene
|
||||
var context = new VRMImporterContext();
|
||||
context.Load(path);
|
||||
var parser = new GltfParser();
|
||||
parser.ParsePath(path);
|
||||
var context = new VRMImporterContext(parser);
|
||||
context.Load();
|
||||
context.ShowMeshes();
|
||||
context.EnableUpdateWhenOffscreen();
|
||||
Selection.activeGameObject = context.Root;
|
||||
@@ -48,8 +50,9 @@ namespace VRM
|
||||
|
||||
// import as asset
|
||||
var prefabPath = UnityPath.FromUnityPath(assetPath);
|
||||
var context = new VRMImporterContext();
|
||||
context.ParseGlb(File.ReadAllBytes(path));
|
||||
var parser = new GltfParser();
|
||||
parser.ParseGlb(File.ReadAllBytes(path));
|
||||
var context = new VRMImporterContext(parser);
|
||||
context.ExtractImages(prefabPath);
|
||||
|
||||
EditorApplication.delayCall += () =>
|
||||
|
||||
@@ -36,11 +36,11 @@ namespace VRM
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
var context = new VRMImporterContext();
|
||||
|
||||
var parser = new GltfParser();
|
||||
try
|
||||
{
|
||||
context.ParseGlb(File.ReadAllBytes(path.FullPath));
|
||||
parser.ParseGlb(File.ReadAllBytes(path.FullPath));
|
||||
}
|
||||
catch (KeyNotFoundException)
|
||||
{
|
||||
@@ -52,6 +52,7 @@ namespace VRM
|
||||
var prefabPath = path.Parent.Child(path.FileNameWithoutExtension + ".prefab");
|
||||
|
||||
// save texture assets !
|
||||
var context = new VRMImporterContext(parser);
|
||||
context.ExtractImages(prefabPath);
|
||||
|
||||
EditorApplication.delayCall += () =>
|
||||
|
||||
@@ -15,30 +15,8 @@ namespace VRM
|
||||
{
|
||||
public VRM.glTF_VRM_extensions VRM { get; private set; }
|
||||
|
||||
public VRMImporterContext()
|
||||
public VRMImporterContext(GltfParser parser) : base(parser)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Parse(string path, byte[] bytes)
|
||||
{
|
||||
var ext = Path.GetExtension(path).ToLower();
|
||||
switch (ext)
|
||||
{
|
||||
case ".vrm":
|
||||
ParseGlb(bytes);
|
||||
break;
|
||||
|
||||
default:
|
||||
base.Parse(path, bytes);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void ParseJson(string json, IStorage storage)
|
||||
{
|
||||
// parse GLTF part(core + unlit, textureTransform, targetNames)
|
||||
base.ParseJson(json, storage);
|
||||
|
||||
// parse VRM part
|
||||
if (glTF_VRM_extensions.TryDeserilize(GLTF.extensions, out glTF_VRM_extensions vrm))
|
||||
{
|
||||
@@ -53,7 +31,7 @@ namespace VRM
|
||||
}
|
||||
|
||||
#region OnLoad
|
||||
protected override async Awaitable OnLoadModel()
|
||||
protected override async Awaitable OnLoadModel(Func<string, IDisposable> MeasureTime)
|
||||
{
|
||||
Root.name = "VRM";
|
||||
|
||||
@@ -61,26 +39,26 @@ namespace VRM
|
||||
{
|
||||
await LoadMetaAsync();
|
||||
}
|
||||
await LoopAwaitable.Create();
|
||||
await NextFrameAwaitable.Create();
|
||||
|
||||
using (MeasureTime("VRM LoadHumanoid"))
|
||||
{
|
||||
LoadHumanoid();
|
||||
}
|
||||
await LoopAwaitable.Create();
|
||||
await NextFrameAwaitable.Create();
|
||||
|
||||
using (MeasureTime("VRM LoadBlendShapeMaster"))
|
||||
{
|
||||
LoadBlendShapeMaster();
|
||||
}
|
||||
await LoopAwaitable.Create();
|
||||
await NextFrameAwaitable.Create();
|
||||
|
||||
using (MeasureTime("VRM LoadSecondary"))
|
||||
{
|
||||
VRMSpringUtility.LoadSecondary(Root.transform, Nodes,
|
||||
VRM.secondaryAnimation);
|
||||
}
|
||||
await LoopAwaitable.Create();
|
||||
await NextFrameAwaitable.Create();
|
||||
|
||||
using (MeasureTime("VRM LoadFirstPerson"))
|
||||
{
|
||||
@@ -196,6 +174,7 @@ namespace VRM
|
||||
}
|
||||
|
||||
var material = MaterialFactory.Materials
|
||||
.Select(y => y.Asset)
|
||||
.FirstOrDefault(y => y.name == x.materialName);
|
||||
var propertyName = x.propertyName;
|
||||
if (x.propertyName.FastEndsWith("_ST_S")
|
||||
@@ -307,7 +286,7 @@ namespace VRM
|
||||
meta.ContactInformation = gltfMeta.contactInformation;
|
||||
meta.Reference = gltfMeta.reference;
|
||||
meta.Title = gltfMeta.title;
|
||||
meta.Thumbnail = await TextureFactory.GetTextureAsync(GetTextureParam.Create(gltfMeta.texture));
|
||||
meta.Thumbnail = await TextureFactory.GetTextureAsync(GLTF, GetTextureParam.Create(GLTF, gltfMeta.texture));
|
||||
meta.AllowedUser = gltfMeta.allowedUser;
|
||||
meta.ViolentUssage = gltfMeta.violentUssage;
|
||||
meta.SexualUssage = gltfMeta.sexualUssage;
|
||||
|
||||
@@ -71,7 +71,8 @@ namespace VRM
|
||||
}
|
||||
foreach (var kv in item.textureProperties)
|
||||
{
|
||||
var texture = await getTexture(new GetTextureParam(kv.Key, default, kv.Value, default, default, default, default, default));
|
||||
var param = GetTextureParam.Create(gltf, kv.Value, kv.Key);
|
||||
var texture = await getTexture(gltf, param);
|
||||
if (texture != null)
|
||||
{
|
||||
material.SetTexture(kv.Key, texture);
|
||||
|
||||
@@ -333,9 +333,11 @@ namespace UniVRM10.Samples
|
||||
|
||||
case ".glb":
|
||||
{
|
||||
var context = new UniGLTF.ImporterContext();
|
||||
var file = File.ReadAllBytes(path);
|
||||
context.ParseGlb(file);
|
||||
var parser = new GltfParser();
|
||||
parser.ParseGlb(file);
|
||||
|
||||
var context = new UniGLTF.ImporterContext(parser);
|
||||
context.Load();
|
||||
context.ShowMeshes();
|
||||
context.EnableUpdateWhenOffscreen();
|
||||
@@ -347,8 +349,10 @@ namespace UniVRM10.Samples
|
||||
case ".gltf":
|
||||
case ".zip":
|
||||
{
|
||||
var context = new UniGLTF.ImporterContext();
|
||||
context.Parse(path);
|
||||
var parser = new GltfParser();
|
||||
parser.ParsePath(path);
|
||||
|
||||
var context = new UniGLTF.ImporterContext(parser);
|
||||
context.Load();
|
||||
context.ShowMeshes();
|
||||
context.EnableUpdateWhenOffscreen();
|
||||
|
||||
@@ -1,131 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Experimental.AssetImporters;
|
||||
using UnityEngine;
|
||||
using VrmLib;
|
||||
|
||||
namespace UniVRM10
|
||||
{
|
||||
#if flase
|
||||
[ScriptedImporter(1, "glb")]
|
||||
#endif
|
||||
public class GltfScriptedImporter : ScriptedImporter, IExternalUnityObject
|
||||
{
|
||||
const string TextureDirName = "Textures";
|
||||
const string MaterialDirName = "Materials";
|
||||
|
||||
public override void OnImportAsset(AssetImportContext ctx)
|
||||
{
|
||||
Debug.Log("OnImportAsset to " + ctx.assetPath);
|
||||
|
||||
try
|
||||
{
|
||||
// Create model
|
||||
VrmLib.Model model = CreateGlbModel(ctx.assetPath);
|
||||
Debug.Log($"ModelLoader.Load: {model}");
|
||||
|
||||
// Build Unity Model
|
||||
var assets = EditorUnityBuilder.ToUnityAsset(model, assetPath, this);
|
||||
|
||||
// Texture
|
||||
var externalTextures = this.GetExternalUnityObjects<UnityEngine.Texture2D>();
|
||||
foreach (var texture in assets.Textures)
|
||||
{
|
||||
if (texture == null)
|
||||
continue;
|
||||
|
||||
if (externalTextures.ContainsValue(texture))
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx.AddObjectToAsset(texture.name, texture);
|
||||
}
|
||||
}
|
||||
|
||||
// Material
|
||||
var externalMaterials = this.GetExternalUnityObjects<UnityEngine.Material>();
|
||||
foreach (var material in assets.Materials)
|
||||
{
|
||||
if (material == null)
|
||||
continue;
|
||||
|
||||
if (externalMaterials.ContainsValue(material))
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx.AddObjectToAsset(material.name, material);
|
||||
}
|
||||
}
|
||||
|
||||
// Mesh
|
||||
foreach (var mesh in assets.Meshes)
|
||||
{
|
||||
ctx.AddObjectToAsset(mesh.name, mesh);
|
||||
}
|
||||
|
||||
// Root
|
||||
ctx.AddObjectToAsset(assets.Root.name, assets.Root);
|
||||
ctx.SetMainObject(assets.Root);
|
||||
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Debug.LogError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private Model CreateGlbModel(string path)
|
||||
{
|
||||
var bytes = File.ReadAllBytes(path);
|
||||
if (!UniGLTF.Glb.TryParse(bytes, out UniGLTF.Glb glb, out Exception ex))
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
|
||||
VrmLib.Model model = null;
|
||||
VrmLib.IVrmStorage storage;
|
||||
storage = new Vrm10Storage(glb.Json.Bytes, glb.Binary.Bytes);
|
||||
model = VrmLib.ModelLoader.Load(storage, Path.GetFileNameWithoutExtension(path));
|
||||
model.ConvertCoordinate(VrmLib.Coordinates.Unity);
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
public void ExtractTextures()
|
||||
{
|
||||
this.ExtractTextures(TextureDirName, (path) => { return CreateGlbModel(path); });
|
||||
AssetDatabase.ImportAsset(assetPath, ImportAssetOptions.ForceUpdate);
|
||||
}
|
||||
|
||||
public void ExtractMaterials()
|
||||
{
|
||||
this.ExtractAssets<UnityEngine.Material>(MaterialDirName, ".mat");
|
||||
AssetDatabase.ImportAsset(assetPath, ImportAssetOptions.ForceUpdate);
|
||||
}
|
||||
|
||||
public void ExtractMaterialsAndTextures()
|
||||
{
|
||||
this.ExtractTextures(TextureDirName, (path) => { return CreateGlbModel(path); }, () => { this.ExtractAssets<UnityEngine.Material>(MaterialDirName, ".mat"); });
|
||||
AssetDatabase.ImportAsset(assetPath, ImportAssetOptions.ForceUpdate);
|
||||
}
|
||||
|
||||
public Dictionary<string, T> GetExternalUnityObjects<T>() where T : UnityEngine.Object
|
||||
{
|
||||
return this.GetExternalObjectMap().Where(x => x.Key.type == typeof(T)).ToDictionary(x => x.Key.name, x => (T)x.Value);
|
||||
}
|
||||
|
||||
public void SetExternalUnityObject<T>(UnityEditor.AssetImporter.SourceAssetIdentifier sourceAssetIdentifier, T obj) where T : UnityEngine.Object
|
||||
{
|
||||
this.AddRemap(sourceAssetIdentifier, obj);
|
||||
AssetDatabase.WriteImportSettingsIfDirty(this.assetPath);
|
||||
AssetDatabase.ImportAsset(this.assetPath, ImportAssetOptions.ForceUpdate);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Experimental.AssetImporters;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniVRM10
|
||||
{
|
||||
[CustomEditor(typeof(GltfScriptedImporter))]
|
||||
public class GltfScriptedImporterEditorGUI : ScriptedImporterEditor
|
||||
{
|
||||
|
||||
private bool _isOpen = true;
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
var importer = target as GltfScriptedImporter;
|
||||
|
||||
EditorGUILayout.LabelField("Extract settings");
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.PrefixLabel("Materials And Textures");
|
||||
GUI.enabled = !(importer.GetExternalUnityObjects<UnityEngine.Material>().Any()
|
||||
&& importer.GetExternalUnityObjects<UnityEngine.Texture2D>().Any());
|
||||
if (GUILayout.Button("Extract"))
|
||||
{
|
||||
importer.ExtractMaterialsAndTextures();
|
||||
}
|
||||
GUI.enabled = !GUI.enabled;
|
||||
if (GUILayout.Button("Clear"))
|
||||
{
|
||||
importer.ClearExternalObjects<UnityEngine.Material>();
|
||||
importer.ClearExternalObjects<UnityEngine.Texture2D>();
|
||||
}
|
||||
GUI.enabled = true;
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
// ObjectMap
|
||||
DrawRemapGUI<UnityEngine.Material>("Material Remap", importer);
|
||||
DrawRemapGUI<UnityEngine.Texture2D>("Texture Remap", importer);
|
||||
|
||||
base.OnInspectorGUI();
|
||||
}
|
||||
|
||||
private void DrawRemapGUI<T>(string title, GltfScriptedImporter importer) where T: UnityEngine.Object
|
||||
{
|
||||
EditorGUILayout.Foldout(_isOpen, title);
|
||||
EditorGUI.indentLevel++;
|
||||
var objects = importer.GetExternalObjectMap().Where(x => x.Key.type == typeof(T));
|
||||
foreach (var obj in objects)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.PrefixLabel(obj.Key.name);
|
||||
var asset = EditorGUILayout.ObjectField(obj.Value, obj.Key.type, true) as T;
|
||||
if(asset != obj.Value)
|
||||
{
|
||||
importer.SetExternalUnityObject(obj.Key, asset);
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user