diff --git a/Assets/VRM10/Editor/ScriptedImporter/VrmaScriptedImporter.cs b/Assets/VRM10/Editor/ScriptedImporter/VrmaScriptedImporter.cs new file mode 100644 index 000000000..da1791206 --- /dev/null +++ b/Assets/VRM10/Editor/ScriptedImporter/VrmaScriptedImporter.cs @@ -0,0 +1,63 @@ +using UniGLTF; +using UnityEngine; +using System.Linq; +using UnityEditor.AssetImporters; + + +namespace UniVRM10 +{ + [ScriptedImporter(1, "vrma")] + public class VrmaScriptedImporter : ScriptedImporter + { + /// + /// Vrm-1.0 の Asset にアイコンを付与する + /// + static Texture2D _AssetIcon = null; + static Texture2D AssetIcon + { + get + { + if (_AssetIcon == null) + { + // try package + _AssetIcon = UnityEditor.AssetDatabase.LoadAssetAtPath("Packages/com.vrmc.vrm/Icons/vrm-48x48.png"); + } + if (_AssetIcon == null) + { + // try assets + _AssetIcon = UnityEditor.AssetDatabase.LoadAssetAtPath("Assets/VRM10/Icons/vrm-48x48.png"); + } + return _AssetIcon; + } + } + + public override void OnImportAsset(AssetImportContext context) + { + // 2 回目以降の Asset Import において、 Importer の設定で Extract した UnityEngine.Object が入る + var extractedObjects = GetExternalObjectMap() + .Where(x => x.Value != null) + .ToDictionary(kv => new SubAssetKey(kv.Value.GetType(), kv.Key.name), kv => kv.Value); + + using (var data = new AutoGltfFileParser(assetPath).Parse()) + using (var loader = new VrmAnimationImporter(data, extractedObjects)) + { + var loaded = loader.Load(); + + loaded.TransferOwnership((k, o) => + { + context.AddObjectToAsset(k.Name, o); + }); + + var root = loaded.Root; + GameObject.DestroyImmediate(loaded); + + // var vrma = root.GetComponent(); + // context.AddObjectToAsset("__boxman_mesh__", vrma.BoxMan.sharedMesh); + // context.AddObjectToAsset("__boxman_mesh__material__", vrma.BoxMan.sharedMaterial); + + context.AddObjectToAsset(root.name, root, AssetIcon); + context.SetMainObject(root); + } + } + } +} \ No newline at end of file diff --git a/Assets/VRM10/Editor/ScriptedImporter/VrmaScriptedImporter.cs.meta b/Assets/VRM10/Editor/ScriptedImporter/VrmaScriptedImporter.cs.meta new file mode 100644 index 000000000..045128bee --- /dev/null +++ b/Assets/VRM10/Editor/ScriptedImporter/VrmaScriptedImporter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 19427481f19aca9429da3548d28da6f5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VRM10/Runtime/Components/VrmAnimationInstance/Vrm10AnimationInstance.cs.meta b/Assets/VRM10/Runtime/Components/VrmAnimationInstance/Vrm10AnimationInstance.cs.meta index 81ed9bff9..62c6d9dfc 100644 --- a/Assets/VRM10/Runtime/Components/VrmAnimationInstance/Vrm10AnimationInstance.cs.meta +++ b/Assets/VRM10/Runtime/Components/VrmAnimationInstance/Vrm10AnimationInstance.cs.meta @@ -5,7 +5,7 @@ MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 - icon: {instanceID: 0} + icon: {fileID: 2800000, guid: ad4861e134018c948ac79793d290f48b, type: 3} userData: assetBundleName: assetBundleVariant: diff --git a/Assets/VRM10/Runtime/IO/VrmAnimationImporter.cs b/Assets/VRM10/Runtime/IO/VrmAnimationImporter.cs index 41674c19e..3c2d5f9b2 100644 --- a/Assets/VRM10/Runtime/IO/VrmAnimationImporter.cs +++ b/Assets/VRM10/Runtime/IO/VrmAnimationImporter.cs @@ -7,12 +7,15 @@ using UniGLTF.Extensions.VRMC_vrm_animation; using UniHumanoid; using UniJSON; using UnityEngine; +using VrmLib; namespace UniVRM10 { public class VrmAnimationImporter : UniGLTF.ImporterContext { VRMC_vrm_animation m_vrma; + ExpressionInfo[] m_expressions; + Material m_defaultMaterial; public VrmAnimationImporter(GltfData data, IReadOnlyDictionary externalObjectMap = null, @@ -230,8 +233,8 @@ namespace UniVRM10 { // Expression は AnimationClip を分ける。 // glTFData から関連 Animation を取り除いて、取っておく。 - var expressions = IterateExpressions().ToArray(); - foreach (var channelIndex in expressions.Select(x => x.ChannelIndex).OrderByDescending(x => x)) + m_expressions = IterateExpressions().ToArray(); + foreach (var channelIndex in m_expressions.Select(x => x.ChannelIndex).OrderByDescending(x => x)) { var nodeIndex = Data.GLTF.animations[0].channels[channelIndex].target.node; Data.GLTF.nodes.RemoveAt(nodeIndex); @@ -243,11 +246,16 @@ namespace UniVRM10 Data.GLTF.scenes[0].nodes = Data.GLTF.scenes[0].nodes.Take(1).ToArray(); // 可視化メッシュ用マテリアル。base.LoadAsync を呼ぶ前に生成する。 - var defaultMaterial = await MaterialFactory.GetDefaultMaterialAsync(awaitCaller); + m_defaultMaterial = await MaterialFactory.GetDefaultMaterialAsync(awaitCaller); // Humanoid Animation が Gltf アニメーションとしてロードされる var instance = await base.LoadAsync(awaitCaller, measureTime); + return instance; + } + + protected override Task OnLoadHierarchy(IAwaitCaller awaitCaller, Func MeasureTime) + { // setup humanoid var humanMap = GetHumanMap(); if (humanMap.Count > 0) @@ -256,22 +264,23 @@ namespace UniVRM10 // // avatar // - var avatar = description.CreateAvatar(instance.Root.transform); + var avatar = description.CreateAvatar(Root.transform); avatar.name = "Avatar"; // AvatarDescription = description; - var animator = instance.gameObject.AddComponent(); + var animator = Root.AddComponent(); animator.avatar = avatar; } - if (expressions.Length > 0) + if (m_expressions.Length > 0) { - var animation = instance.GetComponentOrThrow(); + var animation = Root.GetComponentOrThrow(); var clip = animation.clip; + // m_expressionClip.name = "__expression__"; // Expression の float カーブを追加する // VrmAnimationInstance の "preset_xx" field に連動する var gltfAnimation = Data.GLTF.animations[0]; - foreach (var expression in expressions) + foreach (var expression in m_expressions) { var channel = expression.Channel; var sampler = gltfAnimation.samplers[channel.sampler]; @@ -284,11 +293,22 @@ namespace UniVRM10 } } - // VRMA-animation solver - var animationInstance = instance.gameObject.AddComponent(); - animationInstance.Initialize(expressions.Select(x => x.Key), defaultMaterial); + var animationInstance = Root.AddComponent(); - return instance; + animationInstance.Initialize(m_expressions.Select(x => x.Key), m_defaultMaterial); + + return Task.CompletedTask; + } + + public override void TransferOwnership(TakeResponsibilityForDestroyObjectFunc take) + { + var animationInstance = Root.GetComponent(); + take(SubAssetKey.Create(animationInstance.BoxMan.sharedMesh), animationInstance.BoxMan.sharedMesh); + + var animator = Root.GetComponent(); + take(SubAssetKey.Create(animator.avatar), animator.avatar); + + base.TransferOwnership(take); } } -} +} \ No newline at end of file