mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-05-12 13:34:39 -05:00
Merge pull request #774 from ousttrue/texture_importer
ImporterContextの整理
This commit is contained in:
commit
a7c453bbd6
|
|
@ -1,249 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
/// <summary>
|
||||
/// Editor で Asset 化する場合専用
|
||||
///
|
||||
/// GameObject を prefab 化するので、prefab の元になった GameObject は破棄対象となる。
|
||||
///
|
||||
/// </summary>
|
||||
public class EditorImporterContext : IDisposable
|
||||
{
|
||||
ImporterContext m_context;
|
||||
|
||||
public EditorImporterContext(ImporterContext context)
|
||||
{
|
||||
m_context = context;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
m_context.Dispose();
|
||||
|
||||
if (m_context.Root != null)
|
||||
{
|
||||
// Destroy the GameObject that became the basis of Prefab
|
||||
GameObject.DestroyImmediate(m_context.Root);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual IEnumerable<UnityEngine.Object> ObjectsForSubAsset()
|
||||
{
|
||||
foreach (var x in m_context.TextureFactory.ObjectsForSubAsset())
|
||||
{
|
||||
yield return x;
|
||||
}
|
||||
foreach (var x in m_context.MaterialFactory.ObjectsForSubAsset())
|
||||
{
|
||||
yield return x;
|
||||
}
|
||||
foreach (var x in m_context.Meshes) { yield return x.Mesh; }
|
||||
foreach (var x in m_context.AnimationClips) { yield return x; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destroy assets that created ImporterContext. This function is clean up for importer error.
|
||||
/// </summary>
|
||||
public virtual void EditorDestroyRootAndAssets()
|
||||
{
|
||||
// Remove hierarchy
|
||||
if (m_context.Root != null) GameObject.DestroyImmediate(m_context.Root);
|
||||
|
||||
// Remove resources. materials, textures meshes etc...
|
||||
foreach (var o in ObjectsForSubAsset())
|
||||
{
|
||||
UnityEngine.Object.DestroyImmediate(o, true);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual UnityPath GetAssetPath(UnityPath prefabPath, UnityEngine.Object o, bool meshAsSubAsset)
|
||||
{
|
||||
if (o is Material)
|
||||
{
|
||||
var materialDir = prefabPath.GetAssetFolder(".Materials");
|
||||
var materialPath = materialDir.Child(o.name.EscapeFilePath() + ".asset");
|
||||
return materialPath;
|
||||
}
|
||||
else if (o is Texture2D)
|
||||
{
|
||||
var textureDir = prefabPath.GetAssetFolder(".Textures");
|
||||
var texturePath = textureDir.Child(o.name.EscapeFilePath() + ".asset");
|
||||
return texturePath;
|
||||
}
|
||||
else if (o is Mesh && !meshAsSubAsset)
|
||||
{
|
||||
var meshDir = prefabPath.GetAssetFolder(".Meshes");
|
||||
var meshPath = meshDir.Child(o.name.EscapeFilePath() + ".asset");
|
||||
return meshPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
return default(UnityPath);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual bool AvoidOverwriteAndLoad(UnityPath assetPath, UnityEngine.Object o)
|
||||
{
|
||||
if (o is Material)
|
||||
{
|
||||
var loaded = assetPath.LoadAsset<Material>();
|
||||
|
||||
// replace component reference
|
||||
foreach (var mesh in m_context.Meshes)
|
||||
{
|
||||
foreach (var r in mesh.Renderers)
|
||||
{
|
||||
for (int i = 0; i < r.sharedMaterials.Length; ++i)
|
||||
{
|
||||
if (r.sharedMaterials.Contains(o))
|
||||
{
|
||||
r.sharedMaterials = r.sharedMaterials.Select(x => x == o ? loaded : x).ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void SaveAsAsset(UnityPath prefabPath, bool meshAsSubAsset = false)
|
||||
{
|
||||
m_context.ShowMeshes();
|
||||
|
||||
//var prefabPath = PrefabPath;
|
||||
if (prefabPath.IsFileExists)
|
||||
{
|
||||
// clear SubAssets
|
||||
foreach (var x in prefabPath.GetSubAssets().Where(x => !(x is GameObject) && !(x is Component)))
|
||||
{
|
||||
GameObject.DestroyImmediate(x, true);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// save sub assets
|
||||
//
|
||||
var paths = new List<UnityPath>(){
|
||||
prefabPath
|
||||
};
|
||||
foreach (var o in ObjectsForSubAsset())
|
||||
{
|
||||
if (!string.IsNullOrEmpty(AssetDatabase.GetAssetPath(o)))
|
||||
{
|
||||
// already exists
|
||||
continue;
|
||||
}
|
||||
|
||||
var assetPath = GetAssetPath(prefabPath, o, meshAsSubAsset);
|
||||
if (!assetPath.IsNull)
|
||||
{
|
||||
if (assetPath.IsFileExists)
|
||||
{
|
||||
if (AvoidOverwriteAndLoad(assetPath, o))
|
||||
{
|
||||
// 上書きせずに既存のアセットからロードして置き換えた
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// アセットとして書き込む
|
||||
assetPath.Parent.EnsureFolder();
|
||||
assetPath.CreateAsset(o);
|
||||
paths.Add(assetPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
// save as subasset
|
||||
prefabPath.AddObjectToAsset(o);
|
||||
}
|
||||
}
|
||||
|
||||
// Create or update Main Asset
|
||||
if (prefabPath.IsFileExists)
|
||||
{
|
||||
Debug.LogFormat("replace prefab: {0}", prefabPath);
|
||||
var prefab = prefabPath.LoadAsset<GameObject>();
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
PrefabUtility.SaveAsPrefabAssetAndConnect(m_context.Root, prefabPath.Value, InteractionMode.AutomatedAction);
|
||||
#else
|
||||
PrefabUtility.ReplacePrefab(Root, prefab, ReplacePrefabOptions.ReplaceNameBased);
|
||||
#endif
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogFormat("create prefab: {0}", prefabPath);
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
PrefabUtility.SaveAsPrefabAssetAndConnect(m_context.Root, prefabPath.Value, InteractionMode.AutomatedAction);
|
||||
#else
|
||||
PrefabUtility.CreatePrefab(prefabPath.Value, Root);
|
||||
#endif
|
||||
}
|
||||
foreach (var x in paths)
|
||||
{
|
||||
x.ImportAsset();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extract images from glb or gltf out of Assets folder.
|
||||
/// </summary>
|
||||
/// <param name="prefabPath"></param>
|
||||
public void ExtractImages(UnityPath prefabPath)
|
||||
{
|
||||
var prefabParentDir = prefabPath.Parent;
|
||||
|
||||
// glb buffer
|
||||
var folder = prefabPath.GetAssetFolder(".Textures");
|
||||
|
||||
//
|
||||
// https://answers.unity.com/questions/647615/how-to-update-import-settings-for-newly-created-as.html
|
||||
//
|
||||
int created = 0;
|
||||
for (int i = 0; i < m_context.GLTF.textures.Count; ++i)
|
||||
{
|
||||
folder.EnsureFolder();
|
||||
|
||||
var gltfTexture = m_context.GLTF.textures[i];
|
||||
var gltfImage = m_context.GLTF.images[gltfTexture.source];
|
||||
var src = m_context.Storage.GetPath(gltfImage.uri);
|
||||
if (UnityPath.FromFullpath(src).IsUnderAssetsFolder)
|
||||
{
|
||||
// asset is exists.
|
||||
}
|
||||
else
|
||||
{
|
||||
var byteSegment = m_context.GLTF.GetImageBytes(m_context.Storage, gltfTexture.source);
|
||||
var textureName = gltfTexture.name;
|
||||
|
||||
// path
|
||||
var dst = folder.Child(textureName + gltfImage.GetExt());
|
||||
File.WriteAllBytes(dst.FullPath, byteSegment.ToArray());
|
||||
dst.ImportAsset();
|
||||
|
||||
// make relative path from PrefabParentDir
|
||||
gltfImage.uri = dst.Value.Substring(prefabParentDir.Value.Length + 1);
|
||||
++created;
|
||||
}
|
||||
}
|
||||
|
||||
if (created > 0)
|
||||
{
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
|
||||
// texture will load from assets
|
||||
m_context.TextureFactory.ImageBaseDir = prefabParentDir;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
#if false
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public static class ImporterMenu
|
||||
{
|
||||
[MenuItem(UniGLTFVersion.MENU + "/Import(gltf, glb)", priority = 20)]
|
||||
public static void ImportMenu()
|
||||
{
|
||||
var path = EditorUtility.OpenFilePanel("open gltf", "", "gltf,glb");
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
//
|
||||
// load into scene
|
||||
//
|
||||
var parser = new GltfParser();
|
||||
parser.ParsePath(path);
|
||||
var context = new ImporterContext(parser);
|
||||
context.Load();
|
||||
context.ShowMeshes();
|
||||
Selection.activeGameObject = context.Root;
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// save as asset
|
||||
//
|
||||
if (path.StartsWithUnityAssetPath())
|
||||
{
|
||||
Debug.LogWarningFormat("disallow import from folder under the Assets");
|
||||
return;
|
||||
}
|
||||
|
||||
var assetPath = EditorUtility.SaveFilePanel("save prefab", "Assets", Path.GetFileNameWithoutExtension(path), "prefab");
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// import as asset
|
||||
gltfAssetPostprocessor.ImportAsset(path, Path.GetExtension(path).ToLower(), UnityPath.FromFullpath(assetPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
using UnityEngine;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public static class EditorAnimation
|
||||
{
|
||||
public static void OnGUIAnimation(GltfParser parser)
|
||||
{
|
||||
for (int i = 0; i < parser.GLTF.animations.Count; ++i)
|
||||
{
|
||||
var a = parser.GLTF.animations[i];
|
||||
GUILayout.Label($"{i}: {a.name}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1c496f43ae12f9041a16af0489727587
|
||||
guid: 005298fbae4759b4896174bb6e129e9d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
156
Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/EditorMaterial.cs
Normal file
156
Assets/UniGLTF/Editor/UniGLTF/ScriptedImporter/EditorMaterial.cs
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Experimental.AssetImporters;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public static class EditorMaterial
|
||||
{
|
||||
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 bool s_foldMaterials;
|
||||
static bool s_foldTextures;
|
||||
|
||||
public static void OnGUIMaterial(ScriptedImporter 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 ..."))
|
||||
{
|
||||
ExtractMaterialsAndTextures(importer);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Draw ExternalObjectMap
|
||||
//
|
||||
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.ConvertedName));
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Clear"))
|
||||
{
|
||||
importer.ClearExternalObjects<UnityEngine.Material>();
|
||||
importer.ClearExternalObjects<UnityEngine.Texture2D>();
|
||||
}
|
||||
}
|
||||
|
||||
static void DrawRemapGUI<T>(ScriptedImporter 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--;
|
||||
}
|
||||
|
||||
public static void SetExternalUnityObject<T>(this ScriptedImporter self, UnityEditor.AssetImporter.SourceAssetIdentifier sourceAssetIdentifier, T obj) where T : UnityEngine.Object
|
||||
{
|
||||
self.AddRemap(sourceAssetIdentifier, obj);
|
||||
AssetDatabase.WriteImportSettingsIfDirty(self.assetPath);
|
||||
AssetDatabase.ImportAsset(self.assetPath, ImportAssetOptions.ForceUpdate);
|
||||
}
|
||||
|
||||
static void ExtractMaterialsAndTextures(ScriptedImporter self)
|
||||
{
|
||||
if (string.IsNullOrEmpty(self.assetPath))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Action<Texture2D> addRemap = externalObject =>
|
||||
{
|
||||
self.AddRemap(new AssetImporter.SourceAssetIdentifier(typeof(UnityEngine.Texture2D), externalObject.name), externalObject);
|
||||
};
|
||||
Action<IEnumerable<string>> onCompleted = _ =>
|
||||
{
|
||||
AssetDatabase.ImportAsset(self.assetPath, ImportAssetOptions.ForceUpdate);
|
||||
self.ExtractMaterials();
|
||||
AssetDatabase.ImportAsset(self.assetPath, ImportAssetOptions.ForceUpdate);
|
||||
};
|
||||
|
||||
TextureExtractor.ExtractTextures(self.assetPath,
|
||||
self.GetSubAssets<UnityEngine.Texture2D>(self.assetPath).ToArray(),
|
||||
addRemap,
|
||||
onCompleted
|
||||
);
|
||||
}
|
||||
|
||||
public static void ExtractMaterials(this ScriptedImporter importer)
|
||||
{
|
||||
if (string.IsNullOrEmpty(importer.assetPath))
|
||||
{
|
||||
return;
|
||||
}
|
||||
var path = $"{Path.GetDirectoryName(importer.assetPath)}/{Path.GetFileNameWithoutExtension(importer.assetPath)}.Materials";
|
||||
var info = TextureExtractor.SafeCreateDirectory(path);
|
||||
|
||||
foreach (var asset in importer.GetSubAssets<Material>(importer.assetPath))
|
||||
{
|
||||
ExtractSubAsset(asset, $"{path}/{asset.name}.mat", false);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ExtractSubAsset(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(clone), clone);
|
||||
|
||||
if (isForceUpdate)
|
||||
{
|
||||
AssetDatabase.WriteImportSettingsIfDirty(assetPath);
|
||||
AssetDatabase.ImportAsset(assetPath, ImportAssetOptions.ForceUpdate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,5 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ae2833922b06981439883d1e924b4cd0
|
||||
timeCreated: 1517153624
|
||||
licenseType: Free
|
||||
guid: d87d4a592573eb048916575e202af37f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
using UnityEditor.Experimental.AssetImporters;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
[ScriptedImporter(1, "glb")]
|
||||
public class GlbScriptedImporter : ScriptedImporter
|
||||
{
|
||||
[SerializeField]
|
||||
Axises m_reverseAxis = default;
|
||||
|
||||
public override void OnImportAsset(AssetImportContext ctx)
|
||||
{
|
||||
try
|
||||
{
|
||||
ScriptedImporterImpl.Import(this, ctx, m_reverseAxis);
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Debug.LogError(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7bbb264b34e75dd438622e1f29f0f46c
|
||||
timeCreated: 1517119659
|
||||
licenseType: Free
|
||||
guid: cc45016b844e7624dae3aec10fb443ea
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
using UnityEditor;
|
||||
using UnityEditor.Experimental.AssetImporters;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
[CustomEditor(typeof(GlbScriptedImporter))]
|
||||
public class GlbScriptedImporterEditorGUI : ScriptedImporterEditor
|
||||
{
|
||||
GlbScriptedImporter m_importer;
|
||||
GltfParser m_parser;
|
||||
|
||||
public override void OnEnable()
|
||||
{
|
||||
m_importer = target as GlbScriptedImporter;
|
||||
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:
|
||||
EditorAnimation.OnGUIAnimation(m_parser);
|
||||
break;
|
||||
|
||||
case Tabs.Materials:
|
||||
EditorMaterial.OnGUIMaterial(m_importer, m_parser);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ff15446e31b14ac409251c931b7c2038
|
||||
timeCreated: 1531893103
|
||||
licenseType: Free
|
||||
guid: 706590752e82d004e99da97aff535f67
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
|
|
@ -1,102 +1,25 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Experimental.AssetImporters;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
[ScriptedImporter(1, "glb")]
|
||||
[ScriptedImporter(1, "gltf")]
|
||||
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, null, 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);
|
||||
ScriptedImporterImpl.Import(this, ctx, m_reverseAxis);
|
||||
}
|
||||
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,6 +1,3 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Experimental.AssetImporters;
|
||||
using UnityEngine;
|
||||
|
|
@ -40,98 +37,13 @@ namespace UniGLTF
|
|||
break;
|
||||
|
||||
case Tabs.Animation:
|
||||
OnGUIAnimation(m_importer, m_parser);
|
||||
EditorAnimation.OnGUIAnimation(m_parser);
|
||||
break;
|
||||
|
||||
case Tabs.Materials:
|
||||
OnGUIMaterial(m_importer, m_parser);
|
||||
EditorMaterial.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: 706590752e82d004e99da97aff535f67
|
||||
guid: 16c69c858a1da5e4088d72a546a2963e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
|
|
|
|||
|
|
@ -3,9 +3,6 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using UnityEditor.Experimental.AssetImporters;
|
||||
using UnityEditor;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
|
|
@ -13,32 +10,15 @@ namespace UniGLTF
|
|||
{
|
||||
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)))
|
||||
foreach (var externalObject in importer.GetExternalObjectMap().Where(x => x.Key.type == typeof(T)))
|
||||
{
|
||||
importer.RemoveRemap(extarnalObject.Key);
|
||||
importer.RemoveRemap(externalObject.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
|
||||
|
|
@ -47,177 +27,5 @@ namespace UniGLTF
|
|||
.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);
|
||||
}
|
||||
}
|
||||
|
||||
class TextureExtractor
|
||||
{
|
||||
GltfParser m_parser;
|
||||
public GltfParser Parser => m_parser;
|
||||
|
||||
public glTF GLTF => m_parser.GLTF;
|
||||
public IStorage Storage => m_parser.Storage;
|
||||
|
||||
public readonly Dictionary<string, GetTextureParam> Textures = new Dictionary<string, GetTextureParam>();
|
||||
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);
|
||||
string targetPath = "";
|
||||
|
||||
switch (param.TextureType)
|
||||
{
|
||||
case GetTextureParam.METALLIC_GLOSS_PROP:
|
||||
case GetTextureParam.OCCLUSION_PROP:
|
||||
{
|
||||
// write converted texture
|
||||
targetPath = string.Format("{0}/{1}{2}",
|
||||
m_path,
|
||||
param.Name,
|
||||
".png"
|
||||
);
|
||||
File.WriteAllBytes(targetPath, subAsset.EncodeToPNG().ToArray());
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
// write original bytes
|
||||
targetPath = string.Format("{0}/{1}{2}",
|
||||
m_path,
|
||||
param.Name,
|
||||
".png"
|
||||
);
|
||||
var gltfTexture = GLTF.textures[param.Index0.Value];
|
||||
File.WriteAllBytes(targetPath, GLTF.GetImageBytes(Storage, gltfTexture.source).ToArray());
|
||||
break;
|
||||
}
|
||||
}
|
||||
AssetDatabase.ImportAsset(targetPath);
|
||||
Textures.Add(targetPath, param);
|
||||
}
|
||||
}
|
||||
|
||||
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 kv in extractor.Textures)
|
||||
{
|
||||
var targetPath = kv.Key;
|
||||
var param = kv.Value;
|
||||
|
||||
// TextureImporter
|
||||
var targetTextureImporter = AssetImporter.GetAtPath(targetPath) as TextureImporter;
|
||||
|
||||
switch (param.TextureType)
|
||||
{
|
||||
case GetTextureParam.OCCLUSION_PROP:
|
||||
case GetTextureParam.METALLIC_GLOSS_PROP:
|
||||
targetTextureImporter.sRGBTexture = false;
|
||||
break;
|
||||
|
||||
case GetTextureParam.NORMAL_PROP:
|
||||
targetTextureImporter.textureType = TextureImporterType.NormalMap;
|
||||
break;
|
||||
}
|
||||
|
||||
targetTextureImporter.SaveAndReimport();
|
||||
|
||||
// remap
|
||||
var externalObject = AssetDatabase.LoadAssetAtPath<UnityEngine.Texture2D>(targetPath);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,95 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Experimental.AssetImporters;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public static class ScriptedImporterImpl
|
||||
{
|
||||
/// <summary>
|
||||
/// glb をパースして、UnityObject化、さらにAsset化する
|
||||
/// </summary>
|
||||
/// <param name="scriptedImporter"></param>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="reverseAxis"></param>
|
||||
public static void Import(ScriptedImporter scriptedImporter, AssetImportContext context, Axises reverseAxis)
|
||||
{
|
||||
#if VRM_DEVELOP
|
||||
Debug.Log("OnImportAsset to " + scriptedImporter.assetPath);
|
||||
#endif
|
||||
|
||||
//
|
||||
// Parse(parse glb, parser gltf json)
|
||||
//
|
||||
var parser = new GltfParser();
|
||||
parser.ParsePath(scriptedImporter.assetPath);
|
||||
|
||||
//
|
||||
// Import(create unity objects)
|
||||
//
|
||||
var externalObjectMap = scriptedImporter.GetExternalObjectMap();
|
||||
|
||||
using (var loaded = new ImporterContext(parser, null,
|
||||
externalObjectMap.Where(x => x.Value != null).Select(x => (x.Value.name, x.Value)).Concat(
|
||||
EnumerateTexturesFromUri(externalObjectMap, parser, UnityPath.FromUnityPath(scriptedImporter.assetPath).Parent))))
|
||||
{
|
||||
loaded.InvertAxis = reverseAxis;
|
||||
loaded.Load();
|
||||
loaded.ShowMeshes();
|
||||
|
||||
loaded.TransferOwnership(o =>
|
||||
{
|
||||
#if VRM_DEVELOP
|
||||
Debug.Log($"[{o.GetType().Name}] {o.name} will not destroy");
|
||||
#endif
|
||||
|
||||
context.AddObjectToAsset(o.name, o);
|
||||
if (o is GameObject)
|
||||
{
|
||||
// Root GameObject is main object
|
||||
context.SetMainObject(loaded.Root);
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<(string, UnityEngine.Object)> EnumerateTexturesFromUri(Dictionary<AssetImporter.SourceAssetIdentifier, UnityEngine.Object> exclude,
|
||||
GltfParser parser, UnityPath dir)
|
||||
{
|
||||
foreach (var texParam in parser.EnumerateTextures())
|
||||
{
|
||||
switch (texParam.TextureType)
|
||||
{
|
||||
case GetTextureParam.METALLIC_GLOSS_PROP:
|
||||
case GetTextureParam.OCCLUSION_PROP:
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
var gltfTexture = parser.GLTF.textures.First(y => y.name == texParam.GltflName);
|
||||
var gltfImage = parser.GLTF.images[gltfTexture.source];
|
||||
if (!string.IsNullOrEmpty(gltfImage.uri))
|
||||
{
|
||||
var child = dir.Child(gltfImage.uri);
|
||||
var asset = AssetDatabase.LoadAssetAtPath<Texture2D>(child.Value);
|
||||
if (asset == null)
|
||||
{
|
||||
throw new System.IO.FileNotFoundException($"{child}");
|
||||
}
|
||||
// Debug.Log($"exists: {child}: {asset}");
|
||||
if (exclude == null || !exclude.Any(kv => kv.Value.name == asset.name))
|
||||
{
|
||||
yield return (asset.name, asset);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 85bf14b48ed135743828ee49a830b1c6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,184 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System.Linq;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public class TextureExtractor
|
||||
{
|
||||
const string TextureDirName = "Textures";
|
||||
|
||||
GltfParser m_parser;
|
||||
public GltfParser Parser => m_parser;
|
||||
|
||||
public glTF GLTF => m_parser.GLTF;
|
||||
public IStorage Storage => m_parser.Storage;
|
||||
|
||||
public readonly Dictionary<string, GetTextureParam> Textures = new Dictionary<string, GetTextureParam>();
|
||||
UnityEngine.Texture2D[] m_subAssets;
|
||||
string m_path;
|
||||
|
||||
public TextureExtractor(string assetPath, UnityEngine.Texture2D[] subAssets)
|
||||
{
|
||||
// parse GLTF
|
||||
m_parser = new GltfParser();
|
||||
m_parser.ParsePath(assetPath);
|
||||
|
||||
m_path = $"{Path.GetDirectoryName(assetPath)}/{Path.GetFileNameWithoutExtension(assetPath)}.Textures";
|
||||
SafeCreateDirectory(m_path);
|
||||
|
||||
if (assetPath == null)
|
||||
{
|
||||
throw new ArgumentNullException();
|
||||
}
|
||||
m_subAssets = subAssets;
|
||||
}
|
||||
|
||||
public static string GetExt(string mime, string uri)
|
||||
{
|
||||
switch (mime)
|
||||
{
|
||||
case "image/png": return ".png";
|
||||
case "image/jpeg": return ".jpg";
|
||||
}
|
||||
|
||||
return Path.GetExtension(uri).ToLower();
|
||||
}
|
||||
|
||||
public void Extract(GetTextureParam param, bool hasUri)
|
||||
{
|
||||
if (Textures.Values.Contains(param))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var subAsset = m_subAssets.FirstOrDefault(x => x.name == param.ConvertedName);
|
||||
string targetPath = "";
|
||||
|
||||
if (hasUri && !param.ExtractConverted)
|
||||
{
|
||||
var gltfTexture = GLTF.textures[param.Index0.Value];
|
||||
var gltfImage = GLTF.images[gltfTexture.source];
|
||||
var ext = GetExt(gltfImage.mimeType, gltfImage.uri);
|
||||
targetPath = $"{Path.GetDirectoryName(m_path)}/{param.GltflName}{ext}";
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
switch (param.TextureType)
|
||||
{
|
||||
case GetTextureParam.METALLIC_GLOSS_PROP:
|
||||
case GetTextureParam.OCCLUSION_PROP:
|
||||
{
|
||||
// write converted texture
|
||||
targetPath = $"{m_path}/{param.ConvertedName}.png";
|
||||
File.WriteAllBytes(targetPath, subAsset.EncodeToPNG().ToArray());
|
||||
AssetDatabase.ImportAsset(targetPath);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
// write original bytes
|
||||
var gltfTexture = GLTF.textures[param.Index0.Value];
|
||||
var gltfImage = GLTF.images[gltfTexture.source];
|
||||
var ext = GetExt(gltfImage.mimeType, gltfImage.uri);
|
||||
targetPath = $"{m_path}/{param.GltflName}{ext}";
|
||||
File.WriteAllBytes(targetPath, GLTF.GetImageBytes(Storage, gltfTexture.source).ToArray());
|
||||
AssetDatabase.ImportAsset(targetPath);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Textures.Add(targetPath, param);
|
||||
}
|
||||
|
||||
public static DirectoryInfo SafeCreateDirectory(string path)
|
||||
{
|
||||
if (Directory.Exists(path))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return Directory.CreateDirectory(path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// * Texture(.png etc...)をディスクに書き出す
|
||||
/// * EditorApplication.delayCall で処理を進めて 書き出した画像が Asset として成立するのを待つ
|
||||
/// * 書き出した Asset から TextureImporter を取得して設定する
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="importer"></param>
|
||||
/// <param name="dirName"></param>
|
||||
/// <param name="onCompleted"></param>
|
||||
public static void ExtractTextures(string assetPath, Texture2D[] subAssets, Action<Texture2D> addRemap, Action<IEnumerable<string>> onCompleted = null)
|
||||
{
|
||||
var extractor = new TextureExtractor(assetPath, subAssets);
|
||||
var normalMaps = new List<string>();
|
||||
foreach (var material in extractor.GLTF.materials)
|
||||
{
|
||||
foreach (var x in extractor.Parser.EnumerateTextures(material))
|
||||
{
|
||||
var gltfTexture = extractor.GLTF.textures[x.Index0.Value];
|
||||
var gltfImage = extractor.GLTF.images[gltfTexture.source];
|
||||
extractor.Extract(x, !string.IsNullOrEmpty(gltfImage.uri));
|
||||
}
|
||||
}
|
||||
|
||||
EditorApplication.delayCall += () =>
|
||||
{
|
||||
foreach (var kv in extractor.Textures)
|
||||
{
|
||||
var targetPath = kv.Key;
|
||||
var param = kv.Value;
|
||||
|
||||
// TextureImporter
|
||||
var targetTextureImporter = AssetImporter.GetAtPath(targetPath) as TextureImporter;
|
||||
if (targetTextureImporter != null)
|
||||
{
|
||||
switch (param.TextureType)
|
||||
{
|
||||
case GetTextureParam.OCCLUSION_PROP:
|
||||
case GetTextureParam.METALLIC_GLOSS_PROP:
|
||||
#if VRM_DEVELOP
|
||||
Debug.Log($"{targetPath} => linear");
|
||||
#endif
|
||||
targetTextureImporter.sRGBTexture = false;
|
||||
targetTextureImporter.SaveAndReimport();
|
||||
break;
|
||||
|
||||
case GetTextureParam.NORMAL_PROP:
|
||||
#if VRM_DEVELOP
|
||||
Debug.Log($"{targetPath} => normalmap");
|
||||
#endif
|
||||
targetTextureImporter.textureType = TextureImporterType.NormalMap;
|
||||
targetTextureImporter.SaveAndReimport();
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new FileNotFoundException(targetPath);
|
||||
}
|
||||
|
||||
// remap
|
||||
var externalObject = AssetDatabase.LoadAssetAtPath<UnityEngine.Texture2D>(targetPath);
|
||||
if (externalObject != null)
|
||||
{
|
||||
addRemap(externalObject);
|
||||
}
|
||||
}
|
||||
|
||||
if (onCompleted != null)
|
||||
{
|
||||
onCompleted(extractor.Textures.Keys);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 556e0ca7f0824e44b9000d04e0e9914c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,89 +0,0 @@
|
|||
#if false
|
||||
using System;
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public class gltfAssetPostprocessor : AssetPostprocessor
|
||||
{
|
||||
static void OnPostprocessAllAssets(string[] importedAssets,
|
||||
string[] deletedAssets,
|
||||
string[] movedAssets,
|
||||
string[] movedFromAssetPaths)
|
||||
{
|
||||
foreach (string path in importedAssets)
|
||||
{
|
||||
if (UnityPath.FromUnityPath(path).IsStreamingAsset)
|
||||
{
|
||||
Debug.LogFormat("Skip StreamingAssets: {0}", path);
|
||||
continue;
|
||||
}
|
||||
|
||||
var ext = Path.GetExtension(path).ToLower();
|
||||
switch (ext)
|
||||
{
|
||||
case ".gltf":
|
||||
case ".glb":
|
||||
{
|
||||
var gltfPath = UnityPath.FromUnityPath(path);
|
||||
var prefabPath = gltfPath.Parent.Child(gltfPath.FileNameWithoutExtension + ".prefab");
|
||||
ImportAsset(UnityPath.FromUnityPath(path).FullPath, ext, prefabPath);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void ImportAsset(string src, string ext, UnityPath prefabPath)
|
||||
{
|
||||
if (!prefabPath.IsUnderAssetsFolder)
|
||||
{
|
||||
Debug.LogWarningFormat("out of asset path: {0}", prefabPath);
|
||||
return;
|
||||
}
|
||||
|
||||
var parser = new GltfParser();
|
||||
parser.ParsePath(src);
|
||||
var context = new ImporterContext(parser);
|
||||
|
||||
// Extract textures to assets folder
|
||||
context.ExtractImages(prefabPath);
|
||||
|
||||
ImportDelayed(src, prefabPath, context);
|
||||
}
|
||||
|
||||
static void ImportDelayed(string src, UnityPath prefabPath, ImporterContext context)
|
||||
{
|
||||
EditorApplication.delayCall += () =>
|
||||
{
|
||||
//
|
||||
// After textures imported(To ensure TextureImporter be accessible).
|
||||
//
|
||||
try
|
||||
{
|
||||
context.Load();
|
||||
context.SaveAsAsset(prefabPath);
|
||||
context.EditorDestroyRoot();
|
||||
}
|
||||
catch (UniGLTFNotSupportedException ex)
|
||||
{
|
||||
Debug.LogWarningFormat("{0}: {1}",
|
||||
src,
|
||||
ex.Message
|
||||
);
|
||||
context.EditorDestroyRootAndAssets();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogErrorFormat("import error: {0}", src);
|
||||
Debug.LogErrorFormat("{0}", ex);
|
||||
context.EditorDestroyRootAndAssets();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -229,13 +229,20 @@ namespace UniGLTF
|
|||
for (int i = 0; i < GLTF.textures.Count; ++i)
|
||||
{
|
||||
var gltfTexture = GLTF.textures[i];
|
||||
if (string.IsNullOrEmpty(gltfTexture.name))
|
||||
var gltfImage = GLTF.images[gltfTexture.source];
|
||||
if (!string.IsNullOrEmpty(gltfImage.uri))
|
||||
{
|
||||
// use image name
|
||||
gltfTexture.name = GLTF.images[gltfTexture.source].name;
|
||||
// from image uri
|
||||
gltfTexture.name = Path.GetFileNameWithoutExtension(gltfImage.uri);
|
||||
}
|
||||
if (string.IsNullOrEmpty(gltfTexture.name))
|
||||
{
|
||||
// use image name
|
||||
gltfTexture.name = gltfImage.name;
|
||||
}
|
||||
if (string.IsNullOrEmpty(gltfTexture.name))
|
||||
{
|
||||
// no name
|
||||
var newName = $"texture_{i}";
|
||||
if (!used.Add(newName))
|
||||
{
|
||||
|
|
@ -250,15 +257,17 @@ namespace UniGLTF
|
|||
else
|
||||
{
|
||||
var lower = gltfTexture.name.ToLower();
|
||||
if (used.Contains(lower))
|
||||
if (!used.Add(lower))
|
||||
{
|
||||
// rename
|
||||
var uname = lower + "_" + Guid.NewGuid().ToString("N");
|
||||
Debug.LogWarning($"same name: {lower} => {uname}");
|
||||
gltfTexture.name = uname;
|
||||
lower = uname;
|
||||
if (!used.Add(uname))
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
}
|
||||
used.Add(lower);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -325,62 +334,6 @@ namespace UniGLTF
|
|||
}
|
||||
}
|
||||
|
||||
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)
|
||||
|
|
@ -425,7 +378,7 @@ namespace UniGLTF
|
|||
var m = GLTF.materials[i];
|
||||
foreach (var x in EnumerateTextures(m))
|
||||
{
|
||||
if (used.Add(x.Name))
|
||||
if (used.Add(x.ConvertedName))
|
||||
{
|
||||
yield return x;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -103,17 +103,6 @@ namespace UniGLTF
|
|||
throw new UniGLTFNotSupportedException("draco is not supported");
|
||||
}
|
||||
|
||||
// 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_awaitCaller, m_textureFactory.GetTextureAsync);
|
||||
|
|
@ -201,8 +190,9 @@ namespace UniGLTF
|
|||
}
|
||||
#endregion
|
||||
|
||||
#region Imported
|
||||
#region Imported
|
||||
public GameObject Root;
|
||||
bool m_ownRoot = true;
|
||||
public List<Transform> Nodes = new List<Transform>();
|
||||
|
||||
public List<MeshWithMaterials> Meshes = new List<MeshWithMaterials>();
|
||||
|
|
@ -216,6 +206,14 @@ namespace UniGLTF
|
|||
}
|
||||
}
|
||||
}
|
||||
void RemoveMesh(Mesh mesh)
|
||||
{
|
||||
var index = Meshes.FindIndex(x => x.Mesh == mesh);
|
||||
if (index >= 0)
|
||||
{
|
||||
Meshes.RemoveAt(index);
|
||||
}
|
||||
}
|
||||
|
||||
public void EnableUpdateWhenOffscreen()
|
||||
{
|
||||
|
|
@ -236,20 +234,39 @@ namespace UniGLTF
|
|||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Importに使った一時オブジェクトを破棄する
|
||||
///
|
||||
/// 変換のあるテクスチャで、変換前のもの
|
||||
/// normal, occlusion, metallicRoughness
|
||||
/// ImporterContextが所有する UnityEngine.Object を破棄する
|
||||
/// </summary>
|
||||
public virtual void Dispose()
|
||||
{
|
||||
foreach (var x in m_textureFactory.Textures)
|
||||
Action<UnityEngine.Object> destroy = UnityResourceDestroyer.DestroyResource();
|
||||
|
||||
foreach (var x in AnimationClips)
|
||||
{
|
||||
if (!x.IsUsed)
|
||||
{
|
||||
// Destroy temporary texture object
|
||||
UnityEngine.Object.Destroy(x.Texture);
|
||||
}
|
||||
#if VRM_DEVELOP
|
||||
Debug.Log($"Destroy {x}");
|
||||
#endif
|
||||
destroy(x);
|
||||
}
|
||||
AnimationClips.Clear();
|
||||
|
||||
foreach (var x in Meshes)
|
||||
{
|
||||
#if VRM_DEVELOP
|
||||
Debug.Log($"Destroy {x}");
|
||||
#endif
|
||||
destroy(x.Mesh);
|
||||
}
|
||||
Meshes.Clear();
|
||||
|
||||
m_materialFactory.Dispose();
|
||||
m_textureFactory.Dispose();
|
||||
|
||||
if (m_ownRoot && Root != null)
|
||||
{
|
||||
#if VRM_DEVELOP
|
||||
Debug.Log($"Destroy {Root}");
|
||||
#endif
|
||||
destroy(Root);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -257,33 +274,64 @@ namespace UniGLTF
|
|||
/// Root ヒエラルキーで使っているリソース
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual IEnumerable<UnityEngine.Object> ModelOwnResources()
|
||||
public virtual void TransferOwnership(TakeOwnershipFunc take)
|
||||
{
|
||||
var list = new List<UnityEngine.Object>();
|
||||
foreach (var mesh in Meshes)
|
||||
{
|
||||
yield return mesh.Mesh;
|
||||
if (take(mesh.Mesh))
|
||||
{
|
||||
list.Add(mesh.Mesh);
|
||||
}
|
||||
}
|
||||
foreach (var material in m_materialFactory.Materials)
|
||||
foreach (var x in list)
|
||||
{
|
||||
yield return material.Asset;
|
||||
}
|
||||
foreach (var texture in m_textureFactory.Textures)
|
||||
{
|
||||
yield return texture.Texture;
|
||||
RemoveMesh(x as Mesh);
|
||||
}
|
||||
|
||||
TextureFactory.TransferOwnership(take);
|
||||
MaterialFactory.TransferOwnership(take);
|
||||
|
||||
list.Clear();
|
||||
foreach (var animation in AnimationClips)
|
||||
{
|
||||
yield return animation;
|
||||
if (take(animation))
|
||||
{
|
||||
list.Add(animation);
|
||||
}
|
||||
}
|
||||
foreach (var x in list)
|
||||
{
|
||||
AnimationClips.Remove(x as AnimationClip);
|
||||
}
|
||||
|
||||
if (m_ownRoot && Root != null)
|
||||
{
|
||||
if (take(Root))
|
||||
{
|
||||
// 所有権(Dispose権)
|
||||
m_ownRoot = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RootにUnityResourceDestroyerをアタッチして、
|
||||
/// RootをUnityEngine.Object.Destroyしたときに、
|
||||
/// 関連するUnityEngine.Objectを破棄するようにする。
|
||||
/// Mesh, Material, Texture, AnimationClip, GameObject の所有者が
|
||||
/// ImporterContext から UnityResourceDestroyer に移動する。
|
||||
/// ImporterContext.Dispose の対象から外れる。
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public UnityResourceDestroyer DisposeOnGameObjectDestroyed()
|
||||
{
|
||||
var destroyer = Root.AddComponent<UnityResourceDestroyer>();
|
||||
foreach (var x in ModelOwnResources())
|
||||
TransferOwnership(o =>
|
||||
{
|
||||
destroyer.Resources.Add(x);
|
||||
}
|
||||
destroyer.Resources.Add(o);
|
||||
return true;
|
||||
});
|
||||
return destroyer;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,10 +16,21 @@ namespace UniGLTF
|
|||
{
|
||||
throw new Exception();
|
||||
}
|
||||
if (task.IsFaulted)
|
||||
{
|
||||
if (task.Exception is AggregateException ae && ae.InnerExceptions.Count == 1)
|
||||
{
|
||||
throw ae.InnerException;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw task.Exception;
|
||||
}
|
||||
}
|
||||
|
||||
#if VRM_DEVELOP
|
||||
Debug.Log(meassureTime.GetSpeedLog());
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,6 +64,8 @@ namespace UniGLTF
|
|||
public readonly Material Asset;
|
||||
public readonly bool UseExternal;
|
||||
|
||||
public bool IsSubAsset => !UseExternal;
|
||||
|
||||
public MaterialLoadInfo(Material asset, bool useExternal)
|
||||
{
|
||||
Asset = asset;
|
||||
|
|
@ -73,19 +75,52 @@ namespace UniGLTF
|
|||
|
||||
List<MaterialLoadInfo> m_materials = new List<MaterialLoadInfo>();
|
||||
public IReadOnlyList<MaterialLoadInfo> Materials => m_materials;
|
||||
public void Dispose()
|
||||
void Remove(Material material)
|
||||
{
|
||||
foreach (var x in ObjectsForSubAsset())
|
||||
var index = m_materials.FindIndex(x => x.Asset == material);
|
||||
if (index >= 0)
|
||||
{
|
||||
UnityEngine.Object.DestroyImmediate(x, true);
|
||||
m_materials.RemoveAt(index);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<UnityEngine.Object> ObjectsForSubAsset()
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var x in m_materials)
|
||||
{
|
||||
yield return x.Asset;
|
||||
if (!x.UseExternal)
|
||||
{
|
||||
// 外部の '.asset' からロードしていない
|
||||
#if VRM_DEVELOP
|
||||
Debug.Log($"Destroy {x.Asset}");
|
||||
#endif
|
||||
UnityEngine.Object.DestroyImmediate(x.Asset, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 所有権(Dispose権)を移譲する
|
||||
/// </summary>
|
||||
/// <param name="take"></param>
|
||||
public void TransferOwnership(TakeOwnershipFunc take)
|
||||
{
|
||||
var list = new List<Material>();
|
||||
foreach (var x in m_materials)
|
||||
{
|
||||
if (!x.UseExternal)
|
||||
{
|
||||
// 外部の '.asset' からロードしていない
|
||||
if (take(x.Asset))
|
||||
{
|
||||
list.Add(x.Asset);
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (var x in list)
|
||||
{
|
||||
Remove(x);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -200,22 +235,5 @@ namespace UniGLTF
|
|||
var task = DefaultCreateMaterialAsync(default(ImmediateCaller), 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,13 +71,13 @@ namespace UniGLTF
|
|||
{
|
||||
getTexture = (_x, _y, _z) => Task.FromResult<Texture2D>(null);
|
||||
}
|
||||
var src = gltf.materials[i];
|
||||
|
||||
var material = MaterialFactory.CreateMaterial(i, src, ShaderName);
|
||||
|
||||
// PBR material
|
||||
if (src != null)
|
||||
var material = default(Material);
|
||||
if (i >= 0 && i < gltf.materials.Count)
|
||||
{
|
||||
var src = gltf.materials[i];
|
||||
material = MaterialFactory.CreateMaterial(i, src, ShaderName);
|
||||
if (src.pbrMetallicRoughness != null)
|
||||
{
|
||||
if (src.pbrMetallicRoughness.baseColorFactor != null && src.pbrMetallicRoughness.baseColorFactor.Length == 4)
|
||||
|
|
@ -214,6 +214,10 @@ namespace UniGLTF
|
|||
|
||||
material.SetFloat("_Mode", (float)blendMode);
|
||||
}
|
||||
else
|
||||
{
|
||||
material = MaterialFactory.CreateMaterial(i, null, ShaderName);
|
||||
}
|
||||
|
||||
return material;
|
||||
}
|
||||
|
|
|
|||
13
Assets/UniGLTF/Runtime/UniGLTF/IO/TakeOwnershipFunc.cs
Normal file
13
Assets/UniGLTF/Runtime/UniGLTF/IO/TakeOwnershipFunc.cs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
namespace UniGLTF
|
||||
{
|
||||
/// <summary>
|
||||
/// 所有権を移動する関数。
|
||||
///
|
||||
/// * 所有権が移動する。return true => ImporterContext.Dispose の対象から外れる
|
||||
/// * 所有権が移動しない。return false => Importer.Context.Dispose でDestroyされる
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="o">対象のオブジェクト</param>
|
||||
/// <returns>所有権が移動したらtrue</returns>
|
||||
public delegate bool TakeOwnershipFunc(UnityEngine.Object o);
|
||||
}
|
||||
11
Assets/UniGLTF/Runtime/UniGLTF/IO/TakeOwnershipFunc.cs.meta
Normal file
11
Assets/UniGLTF/Runtime/UniGLTF/IO/TakeOwnershipFunc.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ab2b998b9235dc94a90ccaf2e40a50a6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -154,7 +154,7 @@ namespace UniGLTF
|
|||
);
|
||||
}
|
||||
|
||||
public virtual int ExportTexture(glTF gltf, int bufferIndex, Texture texture, glTFTextureTypes textureType)
|
||||
public int ExportTexture(glTF gltf, int bufferIndex, Texture texture, glTFTextureTypes textureType)
|
||||
{
|
||||
var bytesWithMime = GetBytesWithMime(texture, textureType); ;
|
||||
|
||||
|
|
@ -166,7 +166,7 @@ namespace UniGLTF
|
|||
var imageIndex = gltf.images.Count;
|
||||
gltf.images.Add(new glTFImage
|
||||
{
|
||||
name = texture.name,
|
||||
name = GetTextureParam.RemoveSuffix(texture.name),
|
||||
bufferView = viewIndex,
|
||||
mimeType = bytesWithMime.mine,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -5,10 +5,50 @@ namespace UniGLTF
|
|||
public struct GetTextureParam
|
||||
{
|
||||
public const string NORMAL_PROP = "_BumpMap";
|
||||
public const string NORMAL_SUFFIX = ".normal";
|
||||
public const string METALLIC_GLOSS_PROP = "_MetallicGlossMap";
|
||||
public const string METALLIC_GLOSS_SUFFIX = ".metallicRoughness";
|
||||
public const string OCCLUSION_PROP = "_OcclusionMap";
|
||||
public const string OCCLUSION_SUFFIX = ".occlusion";
|
||||
|
||||
public static string RemoveSuffix(string src)
|
||||
{
|
||||
if (src.EndsWith(NORMAL_SUFFIX))
|
||||
{
|
||||
return src.Substring(0, src.Length - NORMAL_SUFFIX.Length);
|
||||
}
|
||||
else if (src.EndsWith(METALLIC_GLOSS_SUFFIX))
|
||||
{
|
||||
return src.Substring(0, src.Length - METALLIC_GLOSS_SUFFIX.Length);
|
||||
}
|
||||
else if (src.EndsWith(OCCLUSION_SUFFIX))
|
||||
{
|
||||
return src.Substring(0, src.Length - OCCLUSION_SUFFIX.Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
return src;
|
||||
}
|
||||
}
|
||||
|
||||
readonly string m_name;
|
||||
|
||||
public string GltflName => m_name;
|
||||
|
||||
public string ConvertedName
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (TextureType)
|
||||
{
|
||||
case METALLIC_GLOSS_PROP: return $"{m_name}{METALLIC_GLOSS_SUFFIX}";
|
||||
case OCCLUSION_PROP: return $"{m_name}{OCCLUSION_SUFFIX}";
|
||||
case NORMAL_PROP: return $"{m_name}{NORMAL_SUFFIX}";
|
||||
default: return m_name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public readonly string Name;
|
||||
public readonly string TextureType;
|
||||
public readonly float MetallicFactor;
|
||||
public readonly ushort? Index0;
|
||||
|
|
@ -18,13 +58,18 @@ namespace UniGLTF
|
|||
public readonly ushort? Index4;
|
||||
public readonly ushort? Index5;
|
||||
|
||||
/// <summary>
|
||||
/// この2種類は変換済みをExtract
|
||||
/// </summary>
|
||||
public bool ExtractConverted => TextureType == OCCLUSION_PROP || TextureType == METALLIC_GLOSS_PROP;
|
||||
|
||||
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;
|
||||
m_name = name;
|
||||
|
||||
TextureType = textureType;
|
||||
MetallicFactor = metallicFactor;
|
||||
|
|
@ -69,13 +114,13 @@ namespace UniGLTF
|
|||
public static GetTextureParam CreateMetallic(glTF gltf, int textureIndex, float metallicFactor)
|
||||
{
|
||||
var name = gltf.textures[textureIndex].name;
|
||||
return new GetTextureParam(name + ".metallicRoughness", METALLIC_GLOSS_PROP, metallicFactor, textureIndex, default, default, default, default, default);
|
||||
return new GetTextureParam(name, 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);
|
||||
return new GetTextureParam(name, OCCLUSION_PROP, default, textureIndex, default, default, default, default, default);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ namespace UniGLTF
|
|||
public bool IsUsed => Flags.HasFlag(TextureLoadFlags.Used);
|
||||
public bool IsExternal => Flags.HasFlag(TextureLoadFlags.External);
|
||||
|
||||
public bool IsSubAsset => IsUsed && !IsExternal;
|
||||
|
||||
public TextureLoadInfo(Texture2D texture, bool used, bool isExternal)
|
||||
{
|
||||
Texture = texture;
|
||||
|
|
@ -49,10 +51,15 @@ namespace UniGLTF
|
|||
{
|
||||
if (param.Index0.HasValue && m_externalMap != null)
|
||||
{
|
||||
if (m_externalMap.TryGetValue(param.Name, out external))
|
||||
var cacheName = param.ConvertedName;
|
||||
if (param.TextureType == GetTextureParam.NORMAL_PROP)
|
||||
{
|
||||
// Debug.Log($"use external: {param.Name}");
|
||||
m_textureCache.Add(param.Name, new TextureLoadInfo(external, used, true));
|
||||
cacheName = param.GltflName;
|
||||
}
|
||||
|
||||
if (m_externalMap.TryGetValue(cacheName, out external))
|
||||
{
|
||||
m_textureCache.Add(cacheName, new TextureLoadInfo(external, used, true));
|
||||
return external;
|
||||
}
|
||||
}
|
||||
|
|
@ -77,17 +84,42 @@ namespace UniGLTF
|
|||
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var x in ObjectsForSubAsset())
|
||||
{
|
||||
UnityEngine.Object.DestroyImmediate(x, true);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<UnityEngine.Object> ObjectsForSubAsset()
|
||||
{
|
||||
Action<UnityEngine.Object> destroy = UnityResourceDestroyer.DestroyResource();
|
||||
foreach (var kv in m_textureCache)
|
||||
{
|
||||
yield return kv.Value.Texture;
|
||||
if (!kv.Value.IsExternal)
|
||||
{
|
||||
#if VRM_DEVELOP
|
||||
Debug.Log($"Destroy {kv.Value.Texture}");
|
||||
#endif
|
||||
destroy(kv.Value.Texture);
|
||||
}
|
||||
}
|
||||
m_textureCache.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 所有権(Dispose権)を移譲する
|
||||
/// </summary>
|
||||
/// <param name="take"></param>
|
||||
public void TransferOwnership(TakeOwnershipFunc take)
|
||||
{
|
||||
var keys = new List<string>();
|
||||
foreach (var x in m_textureCache)
|
||||
{
|
||||
if (x.Value.IsUsed && !x.Value.IsExternal)
|
||||
{
|
||||
// マテリアルから参照されていて
|
||||
// 外部のAssetからロードしていない。
|
||||
if (take(x.Value.Texture))
|
||||
{
|
||||
keys.Add(x.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (var x in keys)
|
||||
{
|
||||
m_textureCache.Remove(x);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -118,7 +150,7 @@ namespace UniGLTF
|
|||
/// <returns></returns>
|
||||
public async Task<Texture2D> GetTextureAsync(IAwaitCaller awaitCaller, glTF gltf, GetTextureParam param)
|
||||
{
|
||||
if (m_textureCache.TryGetValue(param.Name, out TextureLoadInfo cacheInfo))
|
||||
if (m_textureCache.TryGetValue(param.ConvertedName, out TextureLoadInfo cacheInfo))
|
||||
{
|
||||
return cacheInfo.Texture;
|
||||
}
|
||||
|
|
@ -131,26 +163,12 @@ namespace UniGLTF
|
|||
{
|
||||
case GetTextureParam.NORMAL_PROP:
|
||||
{
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
var baseTexture = await GetOrCreateBaseTexture(awaitCaller, 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 info = await LoadTextureAsync(awaitCaller, 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
|
||||
return info.Texture;
|
||||
}
|
||||
var baseTexture = await GetOrCreateBaseTexture(awaitCaller, gltf, param.Index0.Value, false);
|
||||
var converted = new NormalConverter().GetImportTexture(baseTexture.Texture);
|
||||
converted.name = param.ConvertedName;
|
||||
var info = new TextureLoadInfo(converted, true, false);
|
||||
m_textureCache.Add(converted.name, info);
|
||||
return info.Texture;
|
||||
}
|
||||
|
||||
case GetTextureParam.METALLIC_GLOSS_PROP:
|
||||
|
|
@ -158,9 +176,9 @@ namespace UniGLTF
|
|||
// Bake roughnessFactor values into a texture.
|
||||
var baseTexture = await GetOrCreateBaseTexture(awaitCaller, gltf, param.Index0.Value, false);
|
||||
var converted = new MetallicRoughnessConverter(param.MetallicFactor).GetImportTexture(baseTexture.Texture);
|
||||
converted.name = param.Name;
|
||||
converted.name = param.ConvertedName;
|
||||
var info = new TextureLoadInfo(converted, true, false);
|
||||
m_textureCache.Add(param.Name, info);
|
||||
m_textureCache.Add(converted.name, info);
|
||||
return info.Texture;
|
||||
}
|
||||
|
||||
|
|
@ -168,9 +186,9 @@ namespace UniGLTF
|
|||
{
|
||||
var baseTexture = await GetOrCreateBaseTexture(awaitCaller, gltf, param.Index0.Value, false);
|
||||
var converted = new OcclusionConverter().GetImportTexture(baseTexture.Texture);
|
||||
converted.name = param.Name;
|
||||
converted.name = param.ConvertedName;
|
||||
var info = new TextureLoadInfo(converted, true, false);
|
||||
m_textureCache.Add(param.Name, info);
|
||||
m_textureCache.Add(converted.name, info);
|
||||
return info.Texture;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
|
|
@ -9,7 +10,7 @@ namespace UniGLTF
|
|||
/// </summary>
|
||||
public class UnityResourceDestroyer : MonoBehaviour
|
||||
{
|
||||
List<UnityEngine.Object> m_resources = new List<Object>();
|
||||
List<UnityEngine.Object> m_resources = new List<UnityEngine.Object>();
|
||||
public IList<UnityEngine.Object> Resources => m_resources;
|
||||
|
||||
void OnDestroy()
|
||||
|
|
@ -23,5 +24,16 @@ namespace UniGLTF
|
|||
Destroy(x);
|
||||
}
|
||||
}
|
||||
|
||||
public static Action<UnityEngine.Object> DestroyResource()
|
||||
{
|
||||
Action<UnityEngine.Object> des = (UnityEngine.Object o) => UnityEngine.Object.Destroy(o);
|
||||
Action<UnityEngine.Object> desi = (UnityEngine.Object o) => UnityEngine.Object.DestroyImmediate(o);
|
||||
Action<UnityEngine.Object> func = Application.isPlaying
|
||||
? des
|
||||
: desi
|
||||
;
|
||||
return func;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ca87b3d02ce67634a9ebcfe8cca70ece
|
||||
guid: 93b3af59a4d8b704a883260f2fd40c44
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
using System;
|
||||
|
||||
|
||||
namespace UniJSON
|
||||
{
|
||||
public struct ActionDisposer : IDisposable
|
||||
{
|
||||
Action m_action;
|
||||
|
||||
public ActionDisposer(Action action)
|
||||
{
|
||||
m_action = action;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
m_action();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -98,44 +98,31 @@ namespace UniGLTF
|
|||
public void UniGLTFSimpleSceneTest()
|
||||
{
|
||||
var go = CreateSimpleScene();
|
||||
ImporterContext context = default;
|
||||
|
||||
try
|
||||
// export
|
||||
var gltf = new glTF();
|
||||
|
||||
string json = null;
|
||||
using (var exporter = new gltfExporter(gltf))
|
||||
{
|
||||
// export
|
||||
var gltf = new glTF();
|
||||
exporter.Prepare(go);
|
||||
exporter.Export(MeshExportSettings.Default);
|
||||
|
||||
string json = null;
|
||||
using (var exporter = new gltfExporter(gltf))
|
||||
{
|
||||
exporter.Prepare(go);
|
||||
exporter.Export(MeshExportSettings.Default);
|
||||
// remove empty buffer
|
||||
gltf.buffers.Clear();
|
||||
|
||||
// remove empty buffer
|
||||
gltf.buffers.Clear();
|
||||
|
||||
json = gltf.ToJson();
|
||||
}
|
||||
|
||||
// parse
|
||||
var parser = new GltfParser();
|
||||
parser.ParseJson(json, new SimpleStorage(new ArraySegment<byte>()));
|
||||
|
||||
// import
|
||||
context = new ImporterContext(parser);
|
||||
context.Load();
|
||||
|
||||
AssertAreEqual(go.transform, context.Root.transform);
|
||||
json = gltf.ToJson();
|
||||
}
|
||||
finally
|
||||
|
||||
// parse
|
||||
var parser = new GltfParser();
|
||||
parser.ParseJson(json, new SimpleStorage(new ArraySegment<byte>()));
|
||||
|
||||
// import
|
||||
using (var context = new ImporterContext(parser))
|
||||
{
|
||||
//Debug.LogFormat("Destroy, {0}", go.name);
|
||||
GameObject.DestroyImmediate(go);
|
||||
if (context != null)
|
||||
{
|
||||
var editor = new EditorImporterContext(context);
|
||||
editor.EditorDestroyRootAndAssets();
|
||||
}
|
||||
context.Load();
|
||||
AssertAreEqual(go.transform, context.Root.transform);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -568,19 +555,22 @@ namespace UniGLTF
|
|||
{
|
||||
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();
|
||||
|
||||
var importedRed = context.Root.transform.GetChild(0);
|
||||
var importedRedMaterial = importedRed.GetComponent<Renderer>().sharedMaterial;
|
||||
Assert.AreEqual("red", importedRedMaterial.name);
|
||||
Assert.AreEqual(Color.red, importedRedMaterial.color);
|
||||
using (var context = new ImporterContext(parser))
|
||||
{
|
||||
//Debug.LogFormat("{0}", context.Json);
|
||||
context.Load();
|
||||
|
||||
var importedBlue = context.Root.transform.GetChild(1);
|
||||
var importedBlueMaterial = importedBlue.GetComponent<Renderer>().sharedMaterial;
|
||||
Assert.AreEqual("blue", importedBlueMaterial.name);
|
||||
Assert.AreEqual(Color.blue, importedBlueMaterial.color);
|
||||
var importedRed = context.Root.transform.GetChild(0);
|
||||
var importedRedMaterial = importedRed.GetComponent<Renderer>().sharedMaterial;
|
||||
Assert.AreEqual("red", importedRedMaterial.name);
|
||||
Assert.AreEqual(Color.red, importedRedMaterial.color);
|
||||
|
||||
var importedBlue = context.Root.transform.GetChild(1);
|
||||
var importedBlueMaterial = importedBlue.GetComponent<Renderer>().sharedMaterial;
|
||||
Assert.AreEqual("blue", importedBlueMaterial.name);
|
||||
Assert.AreEqual(Color.blue, importedBlueMaterial.color);
|
||||
}
|
||||
}
|
||||
|
||||
// import new version
|
||||
|
|
@ -588,18 +578,20 @@ namespace UniGLTF
|
|||
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();
|
||||
using (var context = new ImporterContext(parser))
|
||||
{
|
||||
context.Load();
|
||||
|
||||
var importedRed = context.Root.transform.GetChild(0);
|
||||
var importedRedMaterial = importedRed.GetComponent<Renderer>().sharedMaterial;
|
||||
Assert.AreEqual("red", importedRedMaterial.name);
|
||||
Assert.AreEqual(Color.red, importedRedMaterial.color);
|
||||
var importedRed = context.Root.transform.GetChild(0);
|
||||
var importedRedMaterial = importedRed.GetComponent<Renderer>().sharedMaterial;
|
||||
Assert.AreEqual("red", importedRedMaterial.name);
|
||||
Assert.AreEqual(Color.red, importedRedMaterial.color);
|
||||
|
||||
var importedBlue = context.Root.transform.GetChild(1);
|
||||
var importedBlueMaterial = importedBlue.GetComponent<Renderer>().sharedMaterial;
|
||||
Assert.AreEqual("blue", importedBlueMaterial.name);
|
||||
Assert.AreEqual(Color.blue, importedBlueMaterial.color);
|
||||
var importedBlue = context.Root.transform.GetChild(1);
|
||||
var importedBlueMaterial = importedBlue.GetComponent<Renderer>().sharedMaterial;
|
||||
Assert.AreEqual("blue", importedBlueMaterial.name);
|
||||
Assert.AreEqual(Color.blue, importedBlueMaterial.color);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
|
|
|
|||
|
|
@ -45,13 +45,12 @@ namespace VRM.Samples
|
|||
var parser = new GltfParser();
|
||||
parser.ParseGlb(File.ReadAllBytes(path));
|
||||
|
||||
var context = new VRMImporterContext(parser);
|
||||
context.Load();
|
||||
context.ShowMeshes();
|
||||
context.EnableUpdateWhenOffscreen();
|
||||
|
||||
using (new ActionDisposer(() => { GameObject.DestroyImmediate(context.Root); }))
|
||||
using (var context = new VRMImporterContext(parser))
|
||||
{
|
||||
context.Load();
|
||||
context.ShowMeshes();
|
||||
context.EnableUpdateWhenOffscreen();
|
||||
|
||||
var importedJson = JsonParser.Parse(context.Json);
|
||||
importedJson.SetValue("/extensions/VRM/exporterVersion", VRMVersion.VRM_VERSION, (f, x) => f.Value(x));
|
||||
importedJson.SetValue("/asset/generator", UniGLTF.UniGLTFVersion.UNIGLTF_VERSION, (f, x) => f.Value(x));
|
||||
|
|
@ -118,16 +117,18 @@ namespace VRM.Samples
|
|||
var path = AliciaPath;
|
||||
var parser = new GltfParser();
|
||||
parser.ParseGlb(File.ReadAllBytes(path));
|
||||
var context = new VRMImporterContext(parser);
|
||||
context.Load();
|
||||
context.ShowMeshes();
|
||||
context.EnableUpdateWhenOffscreen();
|
||||
|
||||
foreach (var mesh in context.Meshes)
|
||||
using (var context = new VRMImporterContext(parser))
|
||||
{
|
||||
var src = mesh.Mesh;
|
||||
var dst = src.Copy(true);
|
||||
MeshTests.MeshEquals(src, dst);
|
||||
context.Load();
|
||||
context.ShowMeshes();
|
||||
context.EnableUpdateWhenOffscreen();
|
||||
foreach (var mesh in context.Meshes)
|
||||
{
|
||||
var src = mesh.Mesh;
|
||||
var dst = src.Copy(true);
|
||||
MeshTests.MeshEquals(src, dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -138,28 +139,31 @@ namespace VRM.Samples
|
|||
var path = AliciaPath;
|
||||
var parser = new GltfParser();
|
||||
parser.ParseGlb(File.ReadAllBytes(path));
|
||||
var context = new VRMImporterContext(parser);
|
||||
var oldJson = context.GLTF.ToJson().ParseAsJson().ToString(" ");
|
||||
|
||||
// 生成シリアライザでJSON化する
|
||||
var f = new JsonFormatter();
|
||||
GltfSerializer.Serialize(f, context.GLTF);
|
||||
var parsed = f.ToString().ParseAsJson();
|
||||
var newJson = parsed.ToString(" ");
|
||||
using (var context = new VRMImporterContext(parser))
|
||||
{
|
||||
var oldJson = context.GLTF.ToJson().ParseAsJson().ToString(" ");
|
||||
|
||||
// File.WriteAllText("old.json", oldJson);
|
||||
// File.WriteAllText("new.json", newJson);
|
||||
// 生成シリアライザでJSON化する
|
||||
var f = new JsonFormatter();
|
||||
GltfSerializer.Serialize(f, context.GLTF);
|
||||
var parsed = f.ToString().ParseAsJson();
|
||||
var newJson = parsed.ToString(" ");
|
||||
|
||||
// 比較
|
||||
Assert.AreEqual(oldJson.ParseAsJson().ToString(), newJson.ParseAsJson().ToString());
|
||||
// File.WriteAllText("old.json", oldJson);
|
||||
// File.WriteAllText("new.json", newJson);
|
||||
|
||||
// 生成デシリアライザでロードする
|
||||
var ff = new JsonFormatter();
|
||||
var des = GltfDeserializer.Deserialize(parsed);
|
||||
ff.Clear();
|
||||
GltfSerializer.Serialize(ff, des);
|
||||
var desJson = ff.ToString().ParseAsJson().ToString(" ");
|
||||
Assert.AreEqual(oldJson.ParseAsJson().ToString(), desJson.ParseAsJson().ToString());
|
||||
// 比較
|
||||
Assert.AreEqual(oldJson.ParseAsJson().ToString(), newJson.ParseAsJson().ToString());
|
||||
|
||||
// 生成デシリアライザでロードする
|
||||
var ff = new JsonFormatter();
|
||||
var des = GltfDeserializer.Deserialize(parsed);
|
||||
ff.Clear();
|
||||
GltfSerializer.Serialize(ff, des);
|
||||
var desJson = ff.ToString().ParseAsJson().ToString(" ");
|
||||
Assert.AreEqual(oldJson.ParseAsJson().ToString(), desJson.ParseAsJson().ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,8 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2f563e7bcfaebb74dbf9748df1f4824c
|
||||
timeCreated: 1520832729
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -50,16 +50,18 @@ namespace VRM.Samples
|
|||
var parser = new GltfParser();
|
||||
parser.ParseGlb(bytes);
|
||||
|
||||
var context = new VRMImporterContext(parser);
|
||||
using (var context = new VRMImporterContext(parser))
|
||||
{
|
||||
|
||||
// metaを取得(todo: thumbnailテクスチャのロード)
|
||||
var meta = await context.ReadMetaAsync();
|
||||
Debug.LogFormat("meta: title:{0}", meta.Title);
|
||||
// metaを取得(todo: thumbnailテクスチャのロード)
|
||||
var meta = await context.ReadMetaAsync();
|
||||
Debug.LogFormat("meta: title:{0}", meta.Title);
|
||||
|
||||
// ParseしたJSONをシーンオブジェクトに変換していく
|
||||
await context.LoadAsync();
|
||||
// ParseしたJSONをシーンオブジェクトに変換していく
|
||||
await context.LoadAsync();
|
||||
|
||||
OnLoaded(context);
|
||||
OnLoaded(context);
|
||||
}
|
||||
}
|
||||
|
||||
void OnLoaded(VRMImporterContext context)
|
||||
|
|
|
|||
|
|
@ -90,23 +90,24 @@ namespace VRM.Samples
|
|||
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)
|
||||
using (var context = new VRMImporterContext(parser))
|
||||
{
|
||||
await context.LoadAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Load();
|
||||
}
|
||||
// metaを取得(todo: thumbnailテクスチャのロード)
|
||||
var meta = await context.ReadMetaAsync();
|
||||
Debug.LogFormat("meta: title:{0}", meta.Title);
|
||||
|
||||
OnLoaded(context);
|
||||
// ParseしたJSONをシーンオブジェクトに変換していく
|
||||
if (m_loadAsync)
|
||||
{
|
||||
await context.LoadAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Load();
|
||||
}
|
||||
|
||||
OnLoaded(context);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -167,10 +168,12 @@ namespace VRM.Samples
|
|||
void OnLoaded(VRMImporterContext context)
|
||||
{
|
||||
var root = context.Root;
|
||||
|
||||
root.transform.SetParent(transform, false);
|
||||
|
||||
//メッシュを表示します
|
||||
context.ShowMeshes();
|
||||
context.DisposeOnGameObjectDestroyed();
|
||||
|
||||
// add motion
|
||||
var humanPoseTransfer = root.AddComponent<UniHumanoid.HumanPoseTransfer>();
|
||||
|
|
|
|||
|
|
@ -1,188 +0,0 @@
|
|||
#pragma warning disable 0414
|
||||
using System;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
#if (NET_4_6 && UNITY_2017_1_OR_NEWER)
|
||||
using System.Threading.Tasks;
|
||||
#endif
|
||||
|
||||
|
||||
namespace VRM.Samples
|
||||
{
|
||||
public class VRMRuntimeLoaderNet4 : MonoBehaviour
|
||||
{
|
||||
[SerializeField, Header("GUI")]
|
||||
CanvasManager m_canvas;
|
||||
|
||||
[SerializeField]
|
||||
LookTarget m_faceCamera;
|
||||
|
||||
[SerializeField, Header("loader")]
|
||||
UniHumanoid.HumanPoseTransfer m_source;
|
||||
|
||||
[SerializeField]
|
||||
UniHumanoid.HumanPoseTransfer m_target;
|
||||
|
||||
[SerializeField, Header("runtime")]
|
||||
VRMFirstPerson m_firstPerson;
|
||||
|
||||
#if (NET_4_6 && UNITY_2017_1_OR_NEWER && !UNITY_WEBGL)
|
||||
VRMBlendShapeProxy m_blendShape;
|
||||
|
||||
void SetupTarget()
|
||||
{
|
||||
if (m_target != null)
|
||||
{
|
||||
m_target.Source = m_source;
|
||||
m_target.SourceType = UniHumanoid.HumanPoseTransfer.HumanPoseTransferSourceType.HumanPoseTransfer;
|
||||
|
||||
m_blendShape = m_target.GetComponent<VRMBlendShapeProxy>();
|
||||
|
||||
m_firstPerson = m_target.GetComponent<VRMFirstPerson>();
|
||||
|
||||
var animator = m_target.GetComponent<Animator>();
|
||||
if (animator != null)
|
||||
{
|
||||
m_firstPerson.Setup();
|
||||
|
||||
if (m_faceCamera != null)
|
||||
{
|
||||
m_faceCamera.Target = animator.GetBoneTransform(HumanBodyBones.Head);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
SetupTarget();
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
if (m_canvas == null)
|
||||
{
|
||||
Debug.LogWarning("no canvas");
|
||||
return;
|
||||
}
|
||||
|
||||
m_canvas.LoadVRMButton.onClick.AddListener(LoadVRMClicked);
|
||||
m_canvas.LoadBVHButton.onClick.AddListener(LoadBVHClicked);
|
||||
}
|
||||
|
||||
// Byte列を得る
|
||||
async static Task<Byte[]> ReadBytesAsync(string path)
|
||||
{
|
||||
return File.ReadAllBytes(path);
|
||||
}
|
||||
|
||||
async static Task<VRMImporterContext> LoadAsync(Byte[] bytes)
|
||||
{
|
||||
var context = new VRMImporterContext();
|
||||
|
||||
// GLB形式でJSONを取得しParseします
|
||||
context.ParseGlb(bytes);
|
||||
|
||||
// ParseしたJSONをシーンオブジェクトに変換していく
|
||||
await context.LoadAsyncTask();
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Taskで非同期にロードする例
|
||||
/// </summary>
|
||||
async void LoadVRMClicked()
|
||||
{
|
||||
#if UNITY_STANDALONE_WIN
|
||||
var path = FileDialogForWindows.FileDialog("open VRM", ".vrm");
|
||||
#elif UNITY_EDITOR
|
||||
var path = UnityEditor.EditorUtility.OpenFilePanel("Open VRM", "", "vrm");
|
||||
#else
|
||||
var path = Application.dataPath + "/default.vrm";
|
||||
#endif
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var context = new VRMImporterContext();
|
||||
|
||||
var bytes = await ReadBytesAsync(path);
|
||||
|
||||
// GLB形式でJSONを取得しParseします
|
||||
context.ParseGlb(bytes);
|
||||
|
||||
// metaを取得(todo: thumbnailテクスチャのロード)
|
||||
var meta = context.ReadMeta();
|
||||
Debug.LogFormat("meta: title:{0}", meta.Title);
|
||||
|
||||
// ParseしたJSONをシーンオブジェクトに変換していく
|
||||
var now = Time.time;
|
||||
await context.LoadAsyncTask();
|
||||
|
||||
var delta = Time.time - now;
|
||||
Debug.LogFormat("LoadVrmAsync {0:0.0} seconds", delta);
|
||||
OnLoaded(context);
|
||||
|
||||
}
|
||||
|
||||
void LoadBVHClicked()
|
||||
{
|
||||
#if UNITY_STANDALONE_WIN
|
||||
var path = FileDialogForWindows.FileDialog("open BVH", ".bvh");
|
||||
if (!string.IsNullOrEmpty(path))
|
||||
{
|
||||
LoadBvh(path);
|
||||
}
|
||||
#elif UNITY_EDITOR
|
||||
var path = UnityEditor.EditorUtility.OpenFilePanel("Open BVH", "", "bvh");
|
||||
if (!string.IsNullOrEmpty(path))
|
||||
{
|
||||
LoadBvh(path);
|
||||
}
|
||||
#else
|
||||
LoadBvh(Application.dataPath + "/default.bvh");
|
||||
#endif
|
||||
}
|
||||
|
||||
void OnLoaded(VRMImporterContext context)
|
||||
{
|
||||
var root = context.Root;
|
||||
root.transform.SetParent(transform, false);
|
||||
|
||||
//メッシュを表示します
|
||||
context.ShowMeshes();
|
||||
|
||||
// add motion
|
||||
var humanPoseTransfer = root.AddComponent<UniHumanoid.HumanPoseTransfer>();
|
||||
if (m_target != null)
|
||||
{
|
||||
GameObject.Destroy(m_target.gameObject);
|
||||
}
|
||||
m_target = humanPoseTransfer;
|
||||
SetupTarget();
|
||||
}
|
||||
|
||||
void LoadBvh(string path)
|
||||
{
|
||||
Debug.LogFormat("ImportBvh: {0}", path);
|
||||
|
||||
var context = new UniHumanoid.BvhImporterContext();
|
||||
|
||||
context.Parse(path);
|
||||
|
||||
context.Load();
|
||||
|
||||
if (m_source != null)
|
||||
{
|
||||
GameObject.Destroy(m_source.gameObject);
|
||||
}
|
||||
m_source = context.Root.GetComponent<UniHumanoid.HumanPoseTransfer>();
|
||||
|
||||
SetupTarget();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 649886f2803ade846a93be89f73e35c7
|
||||
timeCreated: 1517899576
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -314,15 +314,15 @@ namespace VRM.Samples
|
|||
var parser = new GltfParser();
|
||||
parser.ParseGlb(file);
|
||||
|
||||
var context = new VRMImporterContext(parser);
|
||||
await m_texts.UpdateMetaAsync(context);
|
||||
await context.LoadAsync();
|
||||
|
||||
context.DisposeOnGameObjectDestroyed();
|
||||
context.ShowMeshes();
|
||||
context.EnableUpdateWhenOffscreen();
|
||||
context.ShowMeshes();
|
||||
SetModel(context.Root);
|
||||
using (var context = new VRMImporterContext(parser))
|
||||
{
|
||||
await m_texts.UpdateMetaAsync(context);
|
||||
await context.LoadAsync();
|
||||
context.EnableUpdateWhenOffscreen();
|
||||
context.ShowMeshes();
|
||||
context.DisposeOnGameObjectDestroyed();
|
||||
SetModel(context.Root);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -334,10 +334,9 @@ namespace VRM.Samples
|
|||
|
||||
var context = new UniGLTF.ImporterContext(parser);
|
||||
context.Load();
|
||||
context.DisposeOnGameObjectDestroyed();
|
||||
context.ShowMeshes();
|
||||
context.EnableUpdateWhenOffscreen();
|
||||
context.ShowMeshes();
|
||||
context.DisposeOnGameObjectDestroyed();
|
||||
SetModel(context.Root);
|
||||
break;
|
||||
}
|
||||
|
|
@ -350,10 +349,9 @@ namespace VRM.Samples
|
|||
|
||||
var context = new UniGLTF.ImporterContext(parser);
|
||||
context.Load();
|
||||
context.DisposeOnGameObjectDestroyed();
|
||||
context.ShowMeshes();
|
||||
context.EnableUpdateWhenOffscreen();
|
||||
context.ShowMeshes();
|
||||
context.DisposeOnGameObjectDestroyed();
|
||||
SetModel(context.Root);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,42 +1,26 @@
|
|||
using System.Collections;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UniGLTF;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace VRM
|
||||
{
|
||||
public class VRMEditorImporterContext : EditorImporterContext
|
||||
public class VRMEditorImporterContext
|
||||
{
|
||||
VRMImporterContext m_context;
|
||||
UnityPath m_prefabPath;
|
||||
List<UnityPath> m_paths = new List<UnityPath>();
|
||||
|
||||
public VRMEditorImporterContext(VRMImporterContext context) : base(context)
|
||||
|
||||
public VRMEditorImporterContext(VRMImporterContext context, UnityPath prefabPath)
|
||||
{
|
||||
m_context = context;
|
||||
m_prefabPath = prefabPath;
|
||||
}
|
||||
|
||||
public override IEnumerable<UnityEngine.Object> ObjectsForSubAsset()
|
||||
{
|
||||
foreach (var x in base.ObjectsForSubAsset())
|
||||
{
|
||||
yield return x;
|
||||
}
|
||||
|
||||
yield return m_context.AvatarDescription;
|
||||
yield return m_context.HumanoidAvatar;
|
||||
|
||||
if (m_context.BlendShapeAvatar != null && m_context.BlendShapeAvatar.Clips != null)
|
||||
{
|
||||
foreach (var x in m_context.BlendShapeAvatar.Clips)
|
||||
{
|
||||
yield return x;
|
||||
}
|
||||
}
|
||||
yield return m_context.BlendShapeAvatar;
|
||||
|
||||
yield return m_context.Meta;
|
||||
}
|
||||
|
||||
public override bool AvoidOverwriteAndLoad(UnityPath assetPath, UnityEngine.Object o)
|
||||
public bool AvoidOverwriteAndLoad(UnityPath assetPath, UnityEngine.Object o)
|
||||
{
|
||||
if (o is BlendShapeAvatar)
|
||||
{
|
||||
|
|
@ -52,10 +36,36 @@ namespace VRM
|
|||
return true;
|
||||
}
|
||||
|
||||
return base.AvoidOverwriteAndLoad(assetPath, o);
|
||||
if (o is Material)
|
||||
{
|
||||
var loaded = assetPath.LoadAsset<Material>();
|
||||
if (loaded == null)
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
// replace component reference
|
||||
foreach (var mesh in m_context.Meshes)
|
||||
{
|
||||
foreach (var r in mesh.Renderers)
|
||||
{
|
||||
for (int i = 0; i < r.sharedMaterials.Length; ++i)
|
||||
{
|
||||
if (r.sharedMaterials.Contains(o))
|
||||
{
|
||||
r.sharedMaterials = r.sharedMaterials.Select(x => x == o ? loaded : x).ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override UnityPath GetAssetPath(UnityPath prefabPath, UnityEngine.Object o, bool meshAsSubAsset)
|
||||
public UnityPath GetAssetPath(UnityPath prefabPath, UnityEngine.Object o)
|
||||
{
|
||||
if (o is BlendShapeAvatar
|
||||
|| o is BlendShapeClip)
|
||||
|
|
@ -82,9 +92,141 @@ namespace VRM
|
|||
var assetPath = dir.Child(o.name.EscapeFilePath() + ".asset");
|
||||
return assetPath;
|
||||
}
|
||||
else if (o is Material)
|
||||
{
|
||||
var materialDir = prefabPath.GetAssetFolder(".Materials");
|
||||
var materialPath = materialDir.Child(o.name.EscapeFilePath() + ".asset");
|
||||
return materialPath;
|
||||
}
|
||||
// texture is already extracted
|
||||
// else if (o is Texture2D)
|
||||
// {
|
||||
// var textureDir = prefabPath.GetAssetFolder(".Textures");
|
||||
// var texturePath = textureDir.Child(o.name.EscapeFilePath() + ".asset");
|
||||
// return texturePath;
|
||||
// }
|
||||
else if (o is Mesh)
|
||||
{
|
||||
var meshDir = prefabPath.GetAssetFolder(".Meshes");
|
||||
var meshPath = meshDir.Child(o.name.EscapeFilePath() + ".asset");
|
||||
return meshPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
return base.GetAssetPath(prefabPath, o, meshAsSubAsset);
|
||||
return default(UnityPath);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extract images from glb or gltf out of Assets folder.
|
||||
/// </summary>
|
||||
/// <param name="assetPath"></param>
|
||||
public void ConvertAndExtractImages(UnityPath assetPath, Action<IEnumerable<string>> onTextureReloaded)
|
||||
{
|
||||
//
|
||||
// convert images(metallic roughness, occlusion map)
|
||||
//
|
||||
var task = m_context.MaterialFactory.LoadMaterialsAsync(default(ImmediateCaller), m_context.TextureFactory.GetTextureAsync);
|
||||
if (!task.IsCompleted)
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
if (task.IsFaulted)
|
||||
{
|
||||
if (task.Exception is AggregateException ae && ae.InnerExceptions.Count == 1)
|
||||
{
|
||||
throw ae.InnerException;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw task.Exception;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// extract converted textures
|
||||
//
|
||||
var subAssets = m_context.TextureFactory.Textures
|
||||
.Where(x => x.IsUsed)
|
||||
.Select(x => x.Texture)
|
||||
.ToArray();
|
||||
var prefabParentDir = assetPath.Parent;
|
||||
var folder = assetPath.GetAssetFolder(".Textures");
|
||||
TextureExtractor.ExtractTextures(assetPath.Value, subAssets, _ => { }, onTextureReloaded);
|
||||
}
|
||||
|
||||
bool SaveAsAsset(UnityEngine.Object o)
|
||||
{
|
||||
if (o is GameObject)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(AssetDatabase.GetAssetPath(o)))
|
||||
{
|
||||
// already exists. not dispose
|
||||
#if VRM_DEVELOP
|
||||
Debug.Log($"Loaded. skip: {o}");
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
var assetPath = GetAssetPath(m_prefabPath, o);
|
||||
if (assetPath.IsNull)
|
||||
{
|
||||
// not dispose
|
||||
return true;
|
||||
}
|
||||
|
||||
// if (assetPath.IsFileExists)
|
||||
// {
|
||||
// if (AvoidOverwriteAndLoad(assetPath, o))
|
||||
// {
|
||||
// #if VRM_DEVELOP
|
||||
// Debug.Log($"AvoidOverwriteAndLoad: {assetPath}");
|
||||
// #endif
|
||||
// // 上書きせずに既存のアセットからロードして置き換えた
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
|
||||
// アセットとして書き込む
|
||||
assetPath.Parent.EnsureFolder();
|
||||
assetPath.CreateAsset(o);
|
||||
m_paths.Add(assetPath);
|
||||
|
||||
// 所有権が移動
|
||||
return true;
|
||||
}
|
||||
|
||||
public void SaveAsAsset()
|
||||
{
|
||||
m_context.ShowMeshes();
|
||||
|
||||
//
|
||||
// save sub assets
|
||||
//
|
||||
m_paths.Clear();
|
||||
m_paths.Add(m_prefabPath);
|
||||
m_context.TransferOwnership(SaveAsAsset);
|
||||
|
||||
// Create or update Main Asset
|
||||
if (m_prefabPath.IsFileExists)
|
||||
{
|
||||
Debug.LogFormat("replace prefab: {0}", m_prefabPath);
|
||||
var prefab = m_prefabPath.LoadAsset<GameObject>();
|
||||
PrefabUtility.SaveAsPrefabAssetAndConnect(m_context.Root, m_prefabPath.Value, InteractionMode.AutomatedAction);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogFormat("create prefab: {0}", m_prefabPath);
|
||||
PrefabUtility.SaveAsPrefabAssetAndConnect(m_context.Root, m_prefabPath.Value, InteractionMode.AutomatedAction);
|
||||
}
|
||||
|
||||
foreach (var x in m_paths)
|
||||
{
|
||||
x.ImportAsset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@
|
|||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UniGLTF;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace VRM
|
||||
{
|
||||
|
|
@ -22,11 +23,15 @@ namespace VRM
|
|||
// load into scene
|
||||
var parser = new GltfParser();
|
||||
parser.ParsePath(path);
|
||||
var context = new VRMImporterContext(parser);
|
||||
context.Load();
|
||||
context.ShowMeshes();
|
||||
context.EnableUpdateWhenOffscreen();
|
||||
Selection.activeGameObject = context.Root;
|
||||
|
||||
using (var context = new VRMImporterContext(parser))
|
||||
{
|
||||
context.Load();
|
||||
context.EnableUpdateWhenOffscreen();
|
||||
context.ShowMeshes();
|
||||
context.DisposeOnGameObjectDestroyed();
|
||||
Selection.activeGameObject = context.Root;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -52,19 +57,25 @@ namespace VRM
|
|||
var prefabPath = UnityPath.FromUnityPath(assetPath);
|
||||
var parser = new GltfParser();
|
||||
parser.ParseGlb(File.ReadAllBytes(path));
|
||||
var context = new VRMImporterContext(parser);
|
||||
var editor = new VRMEditorImporterContext(context);
|
||||
editor.ExtractImages(prefabPath);
|
||||
|
||||
EditorApplication.delayCall += () =>
|
||||
Action<IEnumerable<string>> onCompleted = _ =>
|
||||
{
|
||||
//
|
||||
// after textures imported
|
||||
//
|
||||
context.Load();
|
||||
editor.SaveAsAsset(prefabPath);
|
||||
editor.Dispose();
|
||||
using (var context = new VRMImporterContext(parser))
|
||||
{
|
||||
var editor = new VRMEditorImporterContext(context, prefabPath);
|
||||
context.Load();
|
||||
editor.SaveAsAsset();
|
||||
}
|
||||
};
|
||||
|
||||
using (var context = new VRMImporterContext(parser))
|
||||
{
|
||||
var editor = new VRMEditorImporterContext(context, prefabPath);
|
||||
editor.ConvertAndExtractImages(UnityPath.FromFullpath(path), onCompleted);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UniGLTF;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
|
@ -37,41 +38,31 @@ namespace VRM
|
|||
}
|
||||
|
||||
var parser = new GltfParser();
|
||||
try
|
||||
{
|
||||
parser.ParseGlb(File.ReadAllBytes(path.FullPath));
|
||||
}
|
||||
catch (KeyNotFoundException)
|
||||
{
|
||||
// invalid VRM-0.X.
|
||||
// maybe VRM-1.0.do nothing
|
||||
return;
|
||||
}
|
||||
parser.ParseGlb(File.ReadAllBytes(path.FullPath));
|
||||
|
||||
var prefabPath = path.Parent.Child(path.FileNameWithoutExtension + ".prefab");
|
||||
|
||||
// save texture assets !
|
||||
LoadTextureAsyncFunc textureLoader = async (caller, textureIndex, used) =>
|
||||
Action<IEnumerable<string>> onCompleted = texturePaths =>
|
||||
{
|
||||
var gltfTexture = parser.GLTF.textures[textureIndex];
|
||||
var gltfImage = parser.GLTF.images[gltfTexture.source];
|
||||
var assetPath = prefabPath.Parent.Child(gltfImage.uri);
|
||||
var texture = await UniGLTF.AssetTextureLoader.LoadTaskAsync(assetPath, parser.GLTF, textureIndex);
|
||||
return new TextureLoadInfo(texture, used, false);
|
||||
var map = texturePaths.Select(x =>
|
||||
{
|
||||
var texture = AssetDatabase.LoadAssetAtPath(x, typeof(Texture2D));
|
||||
return (texture.name, texture);
|
||||
}).ToArray();
|
||||
using (var context = new VRMImporterContext(parser, null, map))
|
||||
{
|
||||
var editor = new VRMEditorImporterContext(context, prefabPath);
|
||||
context.Load();
|
||||
editor.SaveAsAsset();
|
||||
}
|
||||
};
|
||||
var context = new VRMImporterContext(parser, textureLoader);
|
||||
var editor = new VRMEditorImporterContext(context);
|
||||
editor.ExtractImages(prefabPath);
|
||||
|
||||
EditorApplication.delayCall += () =>
|
||||
// extract texture images
|
||||
using (var context = new VRMImporterContext(parser))
|
||||
{
|
||||
//
|
||||
// after textures imported
|
||||
//
|
||||
context.Load();
|
||||
editor.SaveAsAsset(prefabPath);
|
||||
editor.Dispose();
|
||||
};
|
||||
var editor = new VRMEditorImporterContext(context, prefabPath);
|
||||
editor.ConvertAndExtractImages(path, onCompleted);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ VRM extension is for 3d humanoid avatars (and models) in VR applications.
|
|||
public glTF_VRM_SecondaryAnimation secondaryAnimation = new glTF_VRM_SecondaryAnimation();
|
||||
public List<glTF_VRM_Material> materialProperties = new List<glTF_VRM_Material>();
|
||||
|
||||
public static bool TryDeserilize(glTFExtension extension, out glTF_VRM_extensions vrm)
|
||||
public static bool TryDeserialize(glTFExtension extension, out glTF_VRM_extensions vrm)
|
||||
{
|
||||
if (extension is glTFExtensionImport import)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -8,16 +8,16 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace VRM
|
||||
{
|
||||
|
||||
|
||||
public class VRMImporterContext : ImporterContext
|
||||
{
|
||||
public VRM.glTF_VRM_extensions VRM { get; private set; }
|
||||
|
||||
public VRMImporterContext(GltfParser parser, UniGLTF.LoadTextureAsyncFunc asyncTextureLoader = null) : base(parser, asyncTextureLoader)
|
||||
public VRMImporterContext(GltfParser parser,
|
||||
UniGLTF.LoadTextureAsyncFunc asyncTextureLoader = null,
|
||||
IEnumerable<(string, UnityEngine.Object)> externalObjectMap = null) : base(parser, asyncTextureLoader, externalObjectMap)
|
||||
{
|
||||
// parse VRM part
|
||||
if (glTF_VRM_extensions.TryDeserilize(GLTF.extensions, out glTF_VRM_extensions vrm))
|
||||
if (glTF_VRM_extensions.TryDeserialize(GLTF.extensions, out glTF_VRM_extensions vrm))
|
||||
{
|
||||
VRM = vrm;
|
||||
// override material importer
|
||||
|
|
@ -290,7 +290,10 @@ namespace VRM
|
|||
meta.ContactInformation = gltfMeta.contactInformation;
|
||||
meta.Reference = gltfMeta.reference;
|
||||
meta.Title = gltfMeta.title;
|
||||
meta.Thumbnail = await TextureFactory.GetTextureAsync(awaitCaller, GLTF, GetTextureParam.Create(GLTF, gltfMeta.texture));
|
||||
if (gltfMeta.texture >= 0)
|
||||
{
|
||||
meta.Thumbnail = await TextureFactory.GetTextureAsync(awaitCaller, GLTF, GetTextureParam.Create(GLTF, gltfMeta.texture));
|
||||
}
|
||||
meta.AllowedUser = gltfMeta.allowedUser;
|
||||
meta.ViolentUssage = gltfMeta.violentUssage;
|
||||
meta.SexualUssage = gltfMeta.sexualUssage;
|
||||
|
|
@ -303,22 +306,44 @@ namespace VRM
|
|||
return meta;
|
||||
}
|
||||
|
||||
public override IEnumerable<UnityEngine.Object> ModelOwnResources()
|
||||
public override void TransferOwnership(TakeOwnershipFunc take)
|
||||
{
|
||||
foreach (var x in base.ModelOwnResources())
|
||||
// VRM 固有のリソース(ScriptableObject)
|
||||
if (take(HumanoidAvatar))
|
||||
{
|
||||
yield return x;
|
||||
HumanoidAvatar = null;
|
||||
}
|
||||
|
||||
// VRM 固有のリソース(ScriptableObject)
|
||||
yield return HumanoidAvatar;
|
||||
yield return AvatarDescription;
|
||||
yield return Meta;
|
||||
if (take(Meta))
|
||||
{
|
||||
Meta = null;
|
||||
}
|
||||
|
||||
if (take(AvatarDescription))
|
||||
{
|
||||
AvatarDescription = null;
|
||||
}
|
||||
|
||||
var list = new List<BlendShapeClip>();
|
||||
foreach (var x in BlendShapeAvatar.Clips)
|
||||
{
|
||||
yield return x;
|
||||
if (take(x))
|
||||
{
|
||||
list.Add(x);
|
||||
}
|
||||
}
|
||||
yield return BlendShapeAvatar;
|
||||
foreach (var x in list)
|
||||
{
|
||||
BlendShapeAvatar.Clips.Remove(x);
|
||||
}
|
||||
|
||||
if (take(BlendShapeAvatar))
|
||||
{
|
||||
BlendShapeAvatar = null;
|
||||
}
|
||||
|
||||
// GLTF のリソース
|
||||
base.TransferOwnership(take);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,9 @@ namespace VRM
|
|||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarningFormat("unknown shader {0}.", shaderName);
|
||||
// #if VRM_DEVELOP
|
||||
// Debug.LogWarningFormat("unknown shader {0}.", shaderName);
|
||||
// #endif
|
||||
}
|
||||
return await MaterialFactory.DefaultCreateMaterialAsync(awaitCaller, gltf, m_index, getTexture);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user