Merge pull request #1756 from vrm-c/webgl_build

WebGLの動作確認
This commit is contained in:
ousttrue
2022-08-30 20:00:01 +09:00
committed by GitHub
8 changed files with 238 additions and 6 deletions

View File

@@ -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);
}
}
}
}

View File

@@ -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);
}
}
}
}
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6d3630f9fecf62f4a8137907b0f7beb2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ccb1849bc34bcd740ba2e17462125200
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View 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();
},
});

View 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:

View File

@@ -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
{