mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-09-10 21:09:08 -05:00
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
@@ -14,12 +15,37 @@ namespace UniGLTF
|
||||
throw new FileNotFoundException(path);
|
||||
}
|
||||
|
||||
Debug.LogFormat("{0}", path);
|
||||
if (awaitCaller == null)
|
||||
{
|
||||
Debug.LogWarning("GltfUtility.LoadAsync: awaitCaller argument is null. ImmediateCaller is used as the default fallback. When playing, we recommend RuntimeOnlyAwaitCaller.");
|
||||
awaitCaller = new ImmediateCaller();
|
||||
}
|
||||
|
||||
using (GltfData data = new AutoGltfFileParser(path).Parse())
|
||||
using (var loader = new UniGLTF.ImporterContext(data, materialGenerator: materialGenerator))
|
||||
{
|
||||
return await loader.LoadAsync(awaitCaller);
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<RuntimeGltfInstance> LoadBytesAsync(string path, byte[] bytes, IAwaitCaller awaitCaller = null, IMaterialDescriptorGenerator materialGenerator = null)
|
||||
{
|
||||
if (bytes == null)
|
||||
{
|
||||
throw new ArgumentNullException("bytes");
|
||||
}
|
||||
|
||||
if (awaitCaller == null)
|
||||
{
|
||||
Debug.LogWarning("GltfUtility.LoadAsync: awaitCaller argument is null. ImmediateCaller is used as the default fallback. When playing, we recommend RuntimeOnlyAwaitCaller.");
|
||||
awaitCaller = new ImmediateCaller();
|
||||
}
|
||||
|
||||
using (GltfData data = new GlbBinaryParser(bytes, path).Parse())
|
||||
using (var loader = new UniGLTF.ImporterContext(data, materialGenerator: materialGenerator))
|
||||
{
|
||||
return await loader.LoadAsync(awaitCaller);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,5 +60,57 @@ namespace VRM
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static async Task<RuntimeGltfInstance> LoadBytesAsync(string path,
|
||||
byte[] bytes,
|
||||
IAwaitCaller awaitCaller = null,
|
||||
MaterialGeneratorCallback materialGeneratorCallback = null,
|
||||
MetaCallback metaCallback = null,
|
||||
bool loadAnimation = false
|
||||
)
|
||||
{
|
||||
if (bytes == null)
|
||||
{
|
||||
throw new ArgumentNullException("bytes");
|
||||
}
|
||||
|
||||
if (awaitCaller == null)
|
||||
{
|
||||
Debug.LogWarning("VrmUtility.LoadAsync: awaitCaller argument is null. ImmediateCaller is used as the default fallback. When playing, we recommend RuntimeOnlyAwaitCaller.");
|
||||
awaitCaller = new ImmediateCaller();
|
||||
}
|
||||
|
||||
using (GltfData data = new GlbBinaryParser(bytes, path).Parse())
|
||||
{
|
||||
try
|
||||
{
|
||||
var vrm = new VRMData(data);
|
||||
IMaterialDescriptorGenerator materialGen = default;
|
||||
if (materialGeneratorCallback != null)
|
||||
{
|
||||
materialGen = materialGeneratorCallback(vrm.VrmExtension);
|
||||
}
|
||||
using (var loader = new VRMImporterContext(vrm, materialGenerator: materialGen, loadAnimation: loadAnimation))
|
||||
{
|
||||
if (metaCallback != null)
|
||||
{
|
||||
var meta = await loader.ReadMetaAsync(awaitCaller, true);
|
||||
metaCallback(meta);
|
||||
}
|
||||
return await loader.LoadAsync(awaitCaller);
|
||||
}
|
||||
}
|
||||
catch (NotVrm0Exception)
|
||||
{
|
||||
// retry
|
||||
Debug.LogWarning("file extension is vrm. but not vrm ?");
|
||||
using (var loader = new UniGLTF.ImporterContext(data))
|
||||
{
|
||||
return await loader.LoadAsync(awaitCaller);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace VRMShaders
|
||||
{
|
||||
/// <summary>
|
||||
/// Runtime (Build 後と、Editor Playing) での非同期ロードを実現する AwaitCaller.
|
||||
/// WebGL など Thread が無いもの向け
|
||||
/// </summary>
|
||||
public sealed class RuntimeOnlyNoThreadAwaitCaller : IAwaitCaller
|
||||
{
|
||||
private readonly NextFrameTaskScheduler _scheduler;
|
||||
|
||||
public RuntimeOnlyNoThreadAwaitCaller()
|
||||
{
|
||||
_scheduler = new NextFrameTaskScheduler();
|
||||
}
|
||||
|
||||
public Task NextFrame()
|
||||
{
|
||||
var tcs = new TaskCompletionSource<object>();
|
||||
_scheduler.Enqueue(() => tcs.SetResult(default));
|
||||
return tcs.Task;
|
||||
}
|
||||
|
||||
public Task Run(Action action)
|
||||
{
|
||||
try
|
||||
{
|
||||
action();
|
||||
return Task.FromResult<object>(null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Task.FromException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public Task<T> Run<T>(Func<T> action)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Task.FromResult(action());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Task.FromException<T>(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6d3630f9fecf62f4a8137907b0f7beb2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/VRM_Samples/SimpleViewer/Plugins.meta
Normal file
8
Assets/VRM_Samples/SimpleViewer/Plugins.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ccb1849bc34bcd740ba2e17462125200
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
21
Assets/VRM_Samples/SimpleViewer/Plugins/OpenFile.jslib
Normal file
21
Assets/VRM_Samples/SimpleViewer/Plugins/OpenFile.jslib
Normal file
@@ -0,0 +1,21 @@
|
||||
mergeInto(LibraryManager.library, {
|
||||
WebGLFileDialog: function () {
|
||||
const file_input_id = "file-input";
|
||||
var file_input = document.getElementById(file_input_id);
|
||||
if (!file_input) {
|
||||
file_input = document.createElement('input');
|
||||
file_input.setAttribute('type', 'file');
|
||||
file_input.setAttribute('id', file_input_id);
|
||||
// file_input.setAttribute('accept', '.vrm')
|
||||
file_input.style.visibility = 'hidden';
|
||||
file_input.onclick = function (event) {
|
||||
event.target.value = null;
|
||||
};
|
||||
file_input.onchange = function (event) {
|
||||
SendMessage('Canvas', 'FileSelected', URL.createObjectURL(event.target.files[0]));
|
||||
}
|
||||
document.body.appendChild(file_input);
|
||||
}
|
||||
file_input.click();
|
||||
},
|
||||
});
|
||||
32
Assets/VRM_Samples/SimpleViewer/Plugins/OpenFile.jslib.meta
Normal file
32
Assets/VRM_Samples/SimpleViewer/Plugins/OpenFile.jslib.meta
Normal file
@@ -0,0 +1,32 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2e8941ad33d65584f8ef2f8b829a05e7
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
WebGL: WebGL
|
||||
second:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
using UniGLTF;
|
||||
using UniHumanoid;
|
||||
@@ -11,10 +13,13 @@ using VRMShaders;
|
||||
|
||||
namespace VRM.SimpleViewer
|
||||
{
|
||||
|
||||
|
||||
public class ViewerUI : MonoBehaviour
|
||||
{
|
||||
#if UNITY_WEBGL
|
||||
[DllImport("__Internal")]
|
||||
private static extern void WebGLFileDialog();
|
||||
#endif
|
||||
|
||||
#region UI
|
||||
[SerializeField]
|
||||
Text m_version = default;
|
||||
@@ -353,10 +358,29 @@ namespace VRM.SimpleViewer
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator LoadTexture(string url)
|
||||
{
|
||||
var www = new WWW(url);
|
||||
yield return www;
|
||||
LoadModelAsync("tmp.vrm", www.bytes);
|
||||
}
|
||||
|
||||
public void FileSelected(string url)
|
||||
{
|
||||
Debug.Log($"FileSelected: {url}");
|
||||
StartCoroutine(LoadTexture(url));
|
||||
}
|
||||
|
||||
void OnOpenClicked()
|
||||
{
|
||||
#if UNITY_STANDALONE_WIN
|
||||
var path = FileDialogForWindows.FileDialog("open VRM", "vrm", "glb", "bvh", "gltf", "zip");
|
||||
#elif UNITY_WEBGL
|
||||
{
|
||||
WebGLFileDialog();
|
||||
return;
|
||||
}
|
||||
var path = "";
|
||||
#elif UNITY_EDITOR
|
||||
var path = UnityEditor.EditorUtility.OpenFilePanel("Open VRM", "", "vrm");
|
||||
#else
|
||||
@@ -370,8 +394,11 @@ namespace VRM.SimpleViewer
|
||||
LoadModelAsync(path);
|
||||
}
|
||||
|
||||
async void LoadModelAsync(string path)
|
||||
async void LoadModelAsync(string path, byte[] bytes = null)
|
||||
{
|
||||
var size = bytes != null ? bytes.Length : 0;
|
||||
Debug.Log($"LoadModelAsync: {path}: {size}bytes");
|
||||
|
||||
var ext = Path.GetExtension(path).ToLower();
|
||||
switch (ext)
|
||||
{
|
||||
@@ -379,7 +406,7 @@ namespace VRM.SimpleViewer
|
||||
case ".glb":
|
||||
case ".zip":
|
||||
{
|
||||
var instance = await GltfUtility.LoadAsync(path,
|
||||
var instance = await GltfUtility.LoadBytesAsync(path, bytes,
|
||||
GetIAwaitCaller(m_useAsync.isOn),
|
||||
GetGltfMaterialGenerator(m_useUrpMaterial.isOn));
|
||||
break;
|
||||
@@ -389,7 +416,7 @@ namespace VRM.SimpleViewer
|
||||
{
|
||||
VrmUtility.MaterialGeneratorCallback materialCallback = (VRM.glTF_VRM_extensions vrm) => GetVrmMaterialGenerator(m_useUrpMaterial.isOn, vrm);
|
||||
VrmUtility.MetaCallback metaCallback = m_texts.UpdateMeta;
|
||||
var instance = await VrmUtility.LoadAsync(path, GetIAwaitCaller(m_useAsync.isOn), materialCallback, metaCallback, loadAnimation: m_loadAnimation.isOn);
|
||||
var instance = await VrmUtility.LoadBytesAsync(path, bytes, GetIAwaitCaller(m_useAsync.isOn), materialCallback, metaCallback, loadAnimation: m_loadAnimation.isOn);
|
||||
SetModel(instance);
|
||||
break;
|
||||
}
|
||||
@@ -433,7 +460,11 @@ namespace VRM.SimpleViewer
|
||||
{
|
||||
if (useAsync)
|
||||
{
|
||||
#if UNITY_WEBGL
|
||||
return new RuntimeOnlyNoThreadAwaitCaller();
|
||||
#else
|
||||
return new RuntimeOnlyAwaitCaller();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user