#pragma warning disable 0414 using System; using System.IO; using System.Runtime.InteropServices; using UnityEngine; namespace VRM { public class VRMRuntimeLoader : MonoBehaviour { [SerializeField] bool m_loadAsync; [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 UNITY_STANDALONE_WIN #region GetOpenFileName [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public class OpenFileName { public int structSize = 0; public IntPtr dlgOwner = IntPtr.Zero; public IntPtr instance = IntPtr.Zero; public String filter = null; public String customFilter = null; public int maxCustFilter = 0; public int filterIndex = 0; public String file = null; public int maxFile = 0; public String fileTitle = null; public int maxFileTitle = 0; public String initialDir = null; public String title = null; public int flags = 0; public short fileOffset = 0; public short fileExtension = 0; public String defExt = null; public IntPtr custData = IntPtr.Zero; public IntPtr hook = IntPtr.Zero; public String templateName = null; public IntPtr reservedPtr = IntPtr.Zero; public int reservedInt = 0; public int flagsEx = 0; } [DllImport("Comdlg32.dll", SetLastError = true, ThrowOnUnmappableChar = true, CharSet = CharSet.Auto)] public static extern bool GetOpenFileName([In, Out] OpenFileName ofn); public static bool GetOpenFileName1([In, Out] OpenFileName ofn) { return GetOpenFileName(ofn); } static string Filter(params string[] filters) { return string.Join("\0", filters) + "\0"; } public static string FileDialog(string title, string extension) { OpenFileName ofn = new OpenFileName(); ofn.structSize = Marshal.SizeOf(ofn); ofn.filter = Filter("All Files", "*.*", extension, "*" + extension); ofn.filterIndex = 2; ofn.file = new string(new char[256]); ofn.maxFile = ofn.file.Length; ofn.fileTitle = new string(new char[64]); ofn.maxFileTitle = ofn.fileTitle.Length; ofn.initialDir = UnityEngine.Application.dataPath; ofn.title = title; ofn.defExt = "PNG"; ofn.flags = 0x00080000 | 0x00001000 | 0x00000800 | 0x00000200 | 0x00000008;//OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST| OFN_ALLOWMULTISELECT|OFN_NOCHANGEDIR if (!GetOpenFileName(ofn)) { return null; //FileDialogResult("file:///" + ofn.file); } // later, possibly in some other method: return ofn.file; } #endregion #endif 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(); m_firstPerson = m_target.GetComponent(); var animator = m_target.GetComponent(); 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); } void LoadVRMClicked() { #if UNITY_STANDALONE_WIN var path = FileDialog("open VRM", ".vrm"); #else var path = Application.dataPath + "/default.vrm"; #endif if (string.IsNullOrEmpty(path)) { return; } var bytes = File.ReadAllBytes(path); // なんらかの方法でByte列を得た var context = new VRMImporterContext(path); // GLB形式でJSONを取得しParseします var dataChunk = context.ParseVrm(bytes); // metaを取得(todo: thumbnailテクスチャのロード) var meta = context.ReadMeta(); Debug.LogFormat("meta: title:{0}", meta.Title); // ParseしたJSONをシーンオブジェクトに変換していく if (m_loadAsync) { LoadAsync(context, dataChunk); } else { VRMImporter.LoadFromBytes(context, dataChunk); OnLoaded(context.Root); } } /// /// メタが不要な場合のローダー /// void LoadVRMClicked_without_meta() { #if UNITY_STANDALONE_WIN var path = FileDialog("open VRM", ".vrm"); #else var path = Application.dataPath + "/default.vrm"; #endif if (string.IsNullOrEmpty(path)) { return; } #if true var bytes = File.ReadAllBytes(path); // なんらかの方法でByte列を得た if (m_loadAsync) { // ローカルファイルシステムからロードします VRMImporter.LoadVrmAsync(bytes, OnLoaded); } else { var root=VRMImporter.LoadFromBytes(bytes); OnLoaded(root); } #else // ParseしたJSONをシーンオブジェクトに変換していく if (m_loadAsync) { // ローカルファイルシステムからロードします VRMImporter.LoadVrmAsync(path, OnLoaded); } else { var root=VRMImporter.LoadFromPath(path); OnLoaded(root); } #endif } void LoadAsync(VRMImporterContext context, ArraySegment dataChunk) { #if true var now = Time.time; VRMImporter.LoadVrmAsync(context, dataChunk, go=> { var delta = Time.time - now; Debug.LogFormat("LoadVrmAsync {0:0.0} seconds", delta); OnLoaded(go); }); #else // ローカルファイルシステムからロードします VRMImporter.LoadVrmAsync(path, OnLoaded); #endif } void LoadBVHClicked() { #if UNITY_STANDALONE_WIN var path = FileDialog("open BVH", ".bvh"); if (!string.IsNullOrEmpty(path)) { LoadBvh(path); } #else LoadBvh(Application.dataPath + "/default.bvh"); #endif } void OnLoaded(GameObject root) { root.transform.SetParent(transform, false); // add motion var humanPoseTransfer = root.AddComponent(); 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.ImporterContext { Path = path }; UniHumanoid.BvhImporter.Import(context); if (m_source != null) { GameObject.Destroy(m_source.gameObject); } m_source = context.Root.GetComponent(); SetupTarget(); } } }