diff --git a/.github/workflows/build-webgl.yml b/.github/workflows/build-webgl.yml new file mode 100644 index 000000000..527d2377a --- /dev/null +++ b/.github/workflows/build-webgl.yml @@ -0,0 +1,84 @@ +name: Create UnityPackage + +on: + workflow_dispatch: + +env: + UNITY_PROJECT_PATH: . + +defaults: + run: + shell: bash + +permissions: + contents: read + pages: write + id-token: write + +jobs: + create-unitypackage: + runs-on: [self-hosted, Windows, X64, Unity] + timeout-minutes: 60 + steps: + - id: checkout + uses: actions/checkout@v4 + with: + submodules: recursive + lfs: true + + - name: Detect Unity Version + id: detect-unity-version + run: | + PROJECT_VERSION_PATH="${{ env.UNITY_PROJECT_PATH }}/ProjectSettings/ProjectVersion.txt" + UNITY_HUB="C:\Program Files\Unity Hub\Unity Hub.exe" + + UNITY_VERSION=`cat ${PROJECT_VERSION_PATH} | sed -n -E "s/^m_EditorVersion:\s+//p" | head -n 1` + UNITY_CHANGESET=`cat ${PROJECT_VERSION_PATH} | sed -n -E "s/^m_EditorVersionWithRevision:\s+\S+\s+\((\S+)\)/\1/p" | head -n 1` + UNITY_EDITOR_EXECUTABLE=`"${UNITY_HUB}" -- --headless editors --installed | \ + sed -n -E "s/^${UNITY_VERSION} , installed at //p" | \ + head -n 1` + + if [ -z "${UNITY_EDITOR_EXECUTABLE}" ]; then + echo "Unity ${UNITY_VERSION} is not installed." + exit 1 + + # コマンドラインからのインストールは Unity 3.7.0 時点では UAC 必須で難しい + UNITY_INSTALL_COMMAND="\"${UNITY_HUB}\" -- --headless install \ + --version ${UNITY_VERSION} \ + --changeset ${UNITY_CHANGESET} \ + --module windows-il2cpp \ + --childModules" + fi + + echo "${UNITY_EDITOR_EXECUTABLE} is installed." + echo "unity-editor-executable=${UNITY_EDITOR_EXECUTABLE}" >> "${GITHUB_OUTPUT}" + + - name: Buidl WebGL + id: build-webgl + run: | + # build to Build/SimpleViewer + "${{ steps.detect-unity-version.outputs.unity-editor-executable }}" \ + -batchmode \ + -silent-crashes \ + -projectPath "${{ env.UNITY_PROJECT_PATH }}" \ + -executeMethod "VRM.BuildClass.BuildWebGL_SimpleViewer" \ + -logFile create-webgl.log + echo "Success to create BuildWebGL." + + - name: Upload artifact + uses: actions/upload-pages-artifact@v2 + with: + path: Build + + # Deployment job + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + needs: build + runs-on: ubuntu-latest + name: Deploy + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v2 diff --git a/.vscode/settings.json b/.vscode/settings.json index 622fb688b..2bd897499 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -56,5 +56,8 @@ "Scriptable", "UNIVRM" ], - "dotnet.defaultSolution": "UniVRM.sln" + "dotnet.defaultSolution": "UniVRM.sln", + "files.associations": { + "*.jslib": "javascript", + } } \ No newline at end of file diff --git a/Assets/VRM/Editor/BuildClass.cs b/Assets/VRM/Editor/BuildClass.cs index f1ed4a9c9..410de15a4 100644 --- a/Assets/VRM/Editor/BuildClass.cs +++ b/Assets/VRM/Editor/BuildClass.cs @@ -1,4 +1,5 @@ using UnityEditor; +using UnityEngine.Rendering; namespace VRM { @@ -15,7 +16,7 @@ namespace VRM var report = BuildPipeline.BuildPlayer( scenes, - "./Build/DummyBuild.exe", + "./Build/DummyBuild/DummyBuild.exe", BuildTarget.StandaloneWindows, BuildOptions.Development ); @@ -25,5 +26,45 @@ namespace VRM throw new System.Exception(report.summary.ToString()); } } + + public static void BuildWebGL_SimpleViewer() + { + var scenes = new string[]{ + "./Assets/VRM_Samples/SimpleViewer/SimpleViewer.unity", + }; + + var report = BuildPipeline.BuildPlayer(new BuildPlayerOptions + { + scenes = scenes, + locationPathName = "Build/SimpleViewer", + target = BuildTarget.WebGL, + } + ); + + if (report.summary.result != UnityEditor.Build.Reporting.BuildResult.Succeeded) + { + throw new System.Exception(report.summary.ToString()); + } + } + + public static void BuildWebGL_VRM10Viewer() + { + var scenes = new string[]{ + "./Assets/VRM10_Samples/VRM10Viewer/VRM10Viewer.unity", + }; + + var report = BuildPipeline.BuildPlayer(new BuildPlayerOptions + { + scenes = scenes, + locationPathName = "Build/VRM10Viewer", + target = BuildTarget.WebGL, + } + ); + + if (report.summary.result != UnityEditor.Build.Reporting.BuildResult.Succeeded) + { + throw new System.Exception(report.summary.ToString()); + } + } } } diff --git a/Assets/VRM/Editor/VrmTopMenu.cs b/Assets/VRM/Editor/VrmTopMenu.cs index f1e910074..7c8caa901 100644 --- a/Assets/VRM/Editor/VrmTopMenu.cs +++ b/Assets/VRM/Editor/VrmTopMenu.cs @@ -55,7 +55,13 @@ namespace VRM [MenuItem(DevelopmentMenuPrefix + "/Build dummy for CI", false, 93)] private static void BuildDummyForCi() => BuildClass.Build(); - [MenuItem(DevelopmentMenuPrefix + "/Create UnityPackage", false, 94)] + [MenuItem(DevelopmentMenuPrefix + "/Build 0x WebGL for CI", false, 94)] + private static void BuildWebGLForCi0x() => BuildClass.BuildWebGL_SimpleViewer(); + + [MenuItem(DevelopmentMenuPrefix + "/Build 10 WebGL for CI", false, 95)] + private static void BuildWebGLForCi10() => BuildClass.BuildWebGL_VRM10Viewer(); + + [MenuItem(DevelopmentMenuPrefix + "/Create UnityPackage", false, 99)] private static void CreateUnityPackage() => VRMExportUnityPackage.CreateUnityPackageWithoutBuild(); #endif } diff --git a/Assets/VRM/Samples~/SimpleViewer/FileDialog/FileUtil.cs b/Assets/VRM/Samples~/SimpleViewer/FileDialog/FileUtil.cs index b7c73f2c8..49455fc6c 100644 --- a/Assets/VRM/Samples~/SimpleViewer/FileDialog/FileUtil.cs +++ b/Assets/VRM/Samples~/SimpleViewer/FileDialog/FileUtil.cs @@ -7,9 +7,9 @@ namespace VRM.SimpleViewer #if UNITY_STANDALONE_WIN return FileDialogForWindows.FileDialog(title, extensions); #elif UNITY_WEBGL - // Open WebGLFileDialog - // see: Assets\VRM_Samples\SimpleViewer\Plugins\OpenFile.jslib - WebGLUtil.WebGLFileDialog(); + // Open WebGL_VRM0X_SimpleViewer_FileDialog + // see: Assets/UniGLTF/Runtime/Utils/Plugins/OpenFile.jslib + WebGLUtil.WebGL_VRM0X_SimpleViewer_FileDialog("Canvas", "FileSelected"); // Control flow does not return here. return empty string with dummy return ""; #elif UNITY_EDITOR diff --git a/Assets/VRM/Samples~/SimpleViewer/FileDialog/WebGLUtil.cs b/Assets/VRM/Samples~/SimpleViewer/FileDialog/WebGLUtil.cs index 1d94e2de8..06dea7b71 100644 --- a/Assets/VRM/Samples~/SimpleViewer/FileDialog/WebGLUtil.cs +++ b/Assets/VRM/Samples~/SimpleViewer/FileDialog/WebGLUtil.cs @@ -6,7 +6,7 @@ namespace VRM.SimpleViewer public static class WebGLUtil { [DllImport("__Internal")] - public static extern void WebGLFileDialog(); + public static extern void WebGL_VRM0X_SimpleViewer_FileDialog(string target, string message); } } -#endif \ No newline at end of file +#endif diff --git a/Assets/VRM/Samples~/SimpleViewer/Plugins.meta b/Assets/VRM/Samples~/SimpleViewer/Plugins.meta index fdecce026..7c4d5035c 100644 --- a/Assets/VRM/Samples~/SimpleViewer/Plugins.meta +++ b/Assets/VRM/Samples~/SimpleViewer/Plugins.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: ccb1849bc34bcd740ba2e17462125200 +guid: 453de3a4f46d44d4087a1fca730e04d5 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/VRM/Samples~/SimpleViewer/Plugins/WebGL_VRM0X_SimpleViewer.jslib b/Assets/VRM/Samples~/SimpleViewer/Plugins/WebGL_VRM0X_SimpleViewer.jslib new file mode 100644 index 000000000..11c9321aa --- /dev/null +++ b/Assets/VRM/Samples~/SimpleViewer/Plugins/WebGL_VRM0X_SimpleViewer.jslib @@ -0,0 +1,23 @@ +mergeInto(LibraryManager.library, { + WebGL_VRM0X_SimpleViewer_FileDialog: function (_target, _message) { + const target = UTF8ToString(_target); + const message = UTF8ToString(_message); + 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.style.visibility = 'hidden'; + file_input.onclick = function (event) { + event.target.value = null; + }; + file_input.onchange = function (event) { + console.log('SendMessage', target, message); + SendMessage(target, message, URL.createObjectURL(event.target.files[0])); + } + document.body.appendChild(file_input); + } + file_input.click(); + }, +}); diff --git a/Assets/VRM/Samples~/SimpleViewer/Plugins/WebGL_VRM0X_SimpleViewer.jslib.meta b/Assets/VRM/Samples~/SimpleViewer/Plugins/WebGL_VRM0X_SimpleViewer.jslib.meta new file mode 100644 index 000000000..d1ccd5cd3 --- /dev/null +++ b/Assets/VRM/Samples~/SimpleViewer/Plugins/WebGL_VRM0X_SimpleViewer.jslib.meta @@ -0,0 +1,32 @@ +fileFormatVersion: 2 +guid: ef25d97dc58954a4ca17b4173225e58f +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: diff --git a/Assets/VRM/Samples~/SimpleViewer/ViewerUI.cs b/Assets/VRM/Samples~/SimpleViewer/ViewerUI.cs index 3a4988c90..575f44556 100644 --- a/Assets/VRM/Samples~/SimpleViewer/ViewerUI.cs +++ b/Assets/VRM/Samples~/SimpleViewer/ViewerUI.cs @@ -4,7 +4,6 @@ using System.IO; using System.Linq; using System.Threading.Tasks; using UniGLTF; -using UniGLTF.SpringBoneJobs; using UniHumanoid; using Unity.Collections; using UnityEngine; @@ -294,8 +293,7 @@ namespace VRM.SimpleViewer private void Start() { - m_version.text = string.Format("VRMViewer {0}.{1}", - PackageVersion.MAJOR, PackageVersion.MINOR); + m_version.text = string.Format("SimpleViewer {0}", PackageVersion.VERSION); m_open.onClick.AddListener(OnOpenClicked); m_reset.onClick.AddListener(() => m_loaded?.ResetSpringbone()); @@ -359,9 +357,9 @@ namespace VRM.SimpleViewer IEnumerator LoadCoroutine(string url) { - var www = new UnityEngine.Networking.UnityWebRequest(url); + var www = new WWW(url); yield return www; - var task = LoadBytesAsync("WebGL.vrm", www.downloadHandler.data); + var task = LoadBytesAsync("WebGL.vrm", www.bytes); } /// diff --git a/Assets/VRM10/Runtime/IO/Vrm10.cs b/Assets/VRM10/Runtime/IO/Vrm10.cs index a797df092..1008602fa 100644 --- a/Assets/VRM10/Runtime/IO/Vrm10.cs +++ b/Assets/VRM10/Runtime/IO/Vrm10.cs @@ -99,7 +99,8 @@ namespace UniVRM10 IMaterialDescriptorGenerator materialGenerator = null, VrmMetaInformationCallback vrmMetaInformationCallback = null, CancellationToken ct = default, - ImporterContextSettings importerContextSettings = null) + ImporterContextSettings importerContextSettings = null, + IVrm10SpringBoneRuntime springboneRuntime = null) { awaitCaller ??= Application.isPlaying ? new RuntimeOnlyAwaitCaller() @@ -116,7 +117,8 @@ namespace UniVRM10 materialGenerator, vrmMetaInformationCallback, ct, - importerContextSettings); + importerContextSettings, + springboneRuntime); } /// diff --git a/Assets/VRM10/Samples~/VRM10Viewer/FaceCameraTarget.asset b/Assets/VRM10/Samples~/VRM10Viewer/FaceCameraTarget.asset index c1311d8e0..dc5b55f8e 100644 --- a/Assets/VRM10/Samples~/VRM10Viewer/FaceCameraTarget.asset +++ b/Assets/VRM10/Samples~/VRM10Viewer/FaceCameraTarget.asset @@ -26,6 +26,7 @@ CustomRenderTexture: m_UseDynamicScale: 0 m_BindMS: 0 m_EnableCompatibleFormat: 1 + m_EnableRandomWrite: 0 m_TextureSettings: serializedVersion: 2 m_FilterMode: 1 diff --git a/Assets/VRM10/Samples~/VRM10Viewer/Plugins.meta b/Assets/VRM10/Samples~/VRM10Viewer/Plugins.meta new file mode 100644 index 000000000..7e020264f --- /dev/null +++ b/Assets/VRM10/Samples~/VRM10Viewer/Plugins.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a75c9f76297d99041bdf9ca2458d12bb +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VRM/Samples~/SimpleViewer/Plugins/OpenFile.jslib b/Assets/VRM10/Samples~/VRM10Viewer/Plugins/WebGL_VRM10_VRM10Viewer.jslib similarity index 67% rename from Assets/VRM/Samples~/SimpleViewer/Plugins/OpenFile.jslib rename to Assets/VRM10/Samples~/VRM10Viewer/Plugins/WebGL_VRM10_VRM10Viewer.jslib index 48ba0ce57..1a0cb627b 100644 --- a/Assets/VRM/Samples~/SimpleViewer/Plugins/OpenFile.jslib +++ b/Assets/VRM10/Samples~/VRM10Viewer/Plugins/WebGL_VRM10_VRM10Viewer.jslib @@ -1,21 +1,23 @@ mergeInto(LibraryManager.library, { - WebGLFileDialog: function () { + WebGL_VRM10_VRM10Viewer_FileDialog: function (_target, _message) { + const target = UTF8ToString(_target); + const message = UTF8ToString(_message); 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])); + console.log('SendMessage', target, message); + SendMessage(target, message, URL.createObjectURL(event.target.files[0])); } document.body.appendChild(file_input); } file_input.click(); }, -}); \ No newline at end of file +}); diff --git a/Assets/VRM/Samples~/SimpleViewer/Plugins/OpenFile.jslib.meta b/Assets/VRM10/Samples~/VRM10Viewer/Plugins/WebGL_VRM10_VRM10Viewer.jslib.meta similarity index 100% rename from Assets/VRM/Samples~/SimpleViewer/Plugins/OpenFile.jslib.meta rename to Assets/VRM10/Samples~/VRM10Viewer/Plugins/WebGL_VRM10_VRM10Viewer.jslib.meta diff --git a/Assets/VRM10/Samples~/VRM10Viewer/VRM10ViewerUI.cs b/Assets/VRM10/Samples~/VRM10Viewer/VRM10ViewerUI.cs index 5dbc28055..cd788bb7a 100644 --- a/Assets/VRM10/Samples~/VRM10Viewer/VRM10ViewerUI.cs +++ b/Assets/VRM10/Samples~/VRM10Viewer/VRM10ViewerUI.cs @@ -1,8 +1,11 @@ using System; +using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Runtime.InteropServices; using System.Threading; +using System.Threading.Tasks; using UniGLTF; using UniGLTF.SpringBoneJobs.Blittables; using UnityEngine; @@ -474,8 +477,7 @@ namespace UniVRM10.VRM10Viewer m_autoBlink = gameObject.AddComponent(); m_autoLipsync = gameObject.AddComponent(); - m_version.text = string.Format("VRMViewer {0}.{1}", - VRM10SpecVersion.MAJOR, VRM10SpecVersion.MINOR); + m_version.text = string.Format("VRM10ViewerUI {0}", PackageVersion.VERSION); m_openModel.onClick.AddListener(OnOpenModelClicked); m_openMotion.onClick.AddListener(OnOpenMotionClicked); @@ -491,7 +493,7 @@ namespace UniVRM10.VRM10Viewer if (ArgumentChecker.TryGetFirstLoadable(out var cmd)) { - LoadModel(cmd); + var _ = LoadModel(cmd); } m_texts.Start(); @@ -502,7 +504,6 @@ namespace UniVRM10.VRM10Viewer _cancellationTokenSource?.Dispose(); } - private void Update() { if (Input.GetKeyDown(KeyCode.Tab)) @@ -639,15 +640,29 @@ namespace UniVRM10.VRM10Viewer } } - void OnOpenModelClicked() + [DllImport("__Internal")] + public static extern void WebGL_VRM10_VRM10Viewer_FileDialog(string target, string message); + + string FileDialog() { #if UNITY_STANDALONE_WIN - var path = VRM10FileDialogForWindows.FileDialog("open VRM", "vrm"); + return VRM10FileDialogForWindows.FileDialog("open VRM", "vrm"); +#elif UNITY_WEBGL + // Open WebGL_VRM10_VRM10Viewer_FileDialog + // see: Assets/UniGLTF/Runtime/Utils/Plugins/OpenFile.jslib + WebGL_VRM10_VRM10Viewer_FileDialog("Canvas", "FileSelected"); + // Control flow does not return here. return empty string with dummy + return null; #elif UNITY_EDITOR - var path = UnityEditor.EditorUtility.OpenFilePanel("Open VRM", "", "vrm"); + return UnityEditor.EditorUtility.OpenFilePanel("Open VRM", "", "vrm"); #else - var path = Application.dataPath + "/default.vrm"; + return Application.dataPath + "/default.vrm"; #endif + } + + void OnOpenModelClicked() + { + var path = FileDialog(); if (string.IsNullOrEmpty(path)) { return; @@ -660,7 +675,24 @@ namespace UniVRM10.VRM10Viewer return; } - LoadModel(path); + _ = LoadModel(path); + } + + /// + /// for WebGL + /// call from OpenFile.jslib + /// + public void FileSelected(string url) + { + Debug.Log($"FileSelected: {url}"); + StartCoroutine(LoadCoroutine(url)); + } + + IEnumerator LoadCoroutine(string url) + { + var www = new WWW(url); + yield return www; + var _ = LoadModel("WebGL.vrm", www.bytes); } async void OnOpenMotionClicked() @@ -760,7 +792,29 @@ namespace UniVRM10.VRM10Viewer } } - async void LoadModel(string path) + IAwaitCaller GetIAwaitCaller() + { + if (m_useAsync) + { +#if UNITY_WEBGL + return new RuntimeOnlyNoThreadAwaitCaller(); +#else + return new RuntimeOnlyAwaitCaller(); +#endif + } + else + { + return new ImmediateCaller(); + } + } + + async Task LoadModel(string path) + { + var bytes = await File.ReadAllBytesAsync(path); + await LoadModel(path, bytes); + } + + async Task LoadModel(string path, byte[] bytes) { // cleanup m_loaded?.Dispose(); @@ -772,10 +826,10 @@ namespace UniVRM10.VRM10Viewer try { Debug.LogFormat("{0}", path); - var vrm10Instance = await Vrm10.LoadPathAsync(path, + var vrm10Instance = await Vrm10.LoadBytesAsync(bytes, canLoadVrm0X: true, showMeshes: false, - awaitCaller: m_useAsync.enabled ? new RuntimeOnlyAwaitCaller() : new ImmediateCaller(), + awaitCaller: GetIAwaitCaller(), vrmMetaInformationCallback: m_texts.UpdateMeta, ct: cancellationToken, springboneRuntime: m_useSpringboneSingelton.isOn ? new Vrm10FastSpringboneRuntime() : new Vrm10FastSpringboneRuntimeStandalone()); diff --git a/Assets/VRM10_Samples/VRM10Viewer/FaceCameraTarget.asset b/Assets/VRM10_Samples/VRM10Viewer/FaceCameraTarget.asset index c1311d8e0..dc5b55f8e 100644 --- a/Assets/VRM10_Samples/VRM10Viewer/FaceCameraTarget.asset +++ b/Assets/VRM10_Samples/VRM10Viewer/FaceCameraTarget.asset @@ -26,6 +26,7 @@ CustomRenderTexture: m_UseDynamicScale: 0 m_BindMS: 0 m_EnableCompatibleFormat: 1 + m_EnableRandomWrite: 0 m_TextureSettings: serializedVersion: 2 m_FilterMode: 1 diff --git a/Assets/VRM10_Samples/VRM10Viewer/Plugins.meta b/Assets/VRM10_Samples/VRM10Viewer/Plugins.meta new file mode 100644 index 000000000..7e020264f --- /dev/null +++ b/Assets/VRM10_Samples/VRM10Viewer/Plugins.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a75c9f76297d99041bdf9ca2458d12bb +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VRM_Samples/SimpleViewer/Plugins/OpenFile.jslib b/Assets/VRM10_Samples/VRM10Viewer/Plugins/WebGL_VRM10_VRM10Viewer.jslib similarity index 67% rename from Assets/VRM_Samples/SimpleViewer/Plugins/OpenFile.jslib rename to Assets/VRM10_Samples/VRM10Viewer/Plugins/WebGL_VRM10_VRM10Viewer.jslib index 48ba0ce57..1a0cb627b 100644 --- a/Assets/VRM_Samples/SimpleViewer/Plugins/OpenFile.jslib +++ b/Assets/VRM10_Samples/VRM10Viewer/Plugins/WebGL_VRM10_VRM10Viewer.jslib @@ -1,21 +1,23 @@ mergeInto(LibraryManager.library, { - WebGLFileDialog: function () { + WebGL_VRM10_VRM10Viewer_FileDialog: function (_target, _message) { + const target = UTF8ToString(_target); + const message = UTF8ToString(_message); 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])); + console.log('SendMessage', target, message); + SendMessage(target, message, URL.createObjectURL(event.target.files[0])); } document.body.appendChild(file_input); } file_input.click(); }, -}); \ No newline at end of file +}); diff --git a/Assets/VRM_Samples/SimpleViewer/Plugins/OpenFile.jslib.meta b/Assets/VRM10_Samples/VRM10Viewer/Plugins/WebGL_VRM10_VRM10Viewer.jslib.meta similarity index 100% rename from Assets/VRM_Samples/SimpleViewer/Plugins/OpenFile.jslib.meta rename to Assets/VRM10_Samples/VRM10Viewer/Plugins/WebGL_VRM10_VRM10Viewer.jslib.meta diff --git a/Assets/VRM10_Samples/VRM10Viewer/VRM10ViewerUI.cs b/Assets/VRM10_Samples/VRM10Viewer/VRM10ViewerUI.cs index 5dbc28055..cd788bb7a 100644 --- a/Assets/VRM10_Samples/VRM10Viewer/VRM10ViewerUI.cs +++ b/Assets/VRM10_Samples/VRM10Viewer/VRM10ViewerUI.cs @@ -1,8 +1,11 @@ using System; +using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Runtime.InteropServices; using System.Threading; +using System.Threading.Tasks; using UniGLTF; using UniGLTF.SpringBoneJobs.Blittables; using UnityEngine; @@ -474,8 +477,7 @@ namespace UniVRM10.VRM10Viewer m_autoBlink = gameObject.AddComponent(); m_autoLipsync = gameObject.AddComponent(); - m_version.text = string.Format("VRMViewer {0}.{1}", - VRM10SpecVersion.MAJOR, VRM10SpecVersion.MINOR); + m_version.text = string.Format("VRM10ViewerUI {0}", PackageVersion.VERSION); m_openModel.onClick.AddListener(OnOpenModelClicked); m_openMotion.onClick.AddListener(OnOpenMotionClicked); @@ -491,7 +493,7 @@ namespace UniVRM10.VRM10Viewer if (ArgumentChecker.TryGetFirstLoadable(out var cmd)) { - LoadModel(cmd); + var _ = LoadModel(cmd); } m_texts.Start(); @@ -502,7 +504,6 @@ namespace UniVRM10.VRM10Viewer _cancellationTokenSource?.Dispose(); } - private void Update() { if (Input.GetKeyDown(KeyCode.Tab)) @@ -639,15 +640,29 @@ namespace UniVRM10.VRM10Viewer } } - void OnOpenModelClicked() + [DllImport("__Internal")] + public static extern void WebGL_VRM10_VRM10Viewer_FileDialog(string target, string message); + + string FileDialog() { #if UNITY_STANDALONE_WIN - var path = VRM10FileDialogForWindows.FileDialog("open VRM", "vrm"); + return VRM10FileDialogForWindows.FileDialog("open VRM", "vrm"); +#elif UNITY_WEBGL + // Open WebGL_VRM10_VRM10Viewer_FileDialog + // see: Assets/UniGLTF/Runtime/Utils/Plugins/OpenFile.jslib + WebGL_VRM10_VRM10Viewer_FileDialog("Canvas", "FileSelected"); + // Control flow does not return here. return empty string with dummy + return null; #elif UNITY_EDITOR - var path = UnityEditor.EditorUtility.OpenFilePanel("Open VRM", "", "vrm"); + return UnityEditor.EditorUtility.OpenFilePanel("Open VRM", "", "vrm"); #else - var path = Application.dataPath + "/default.vrm"; + return Application.dataPath + "/default.vrm"; #endif + } + + void OnOpenModelClicked() + { + var path = FileDialog(); if (string.IsNullOrEmpty(path)) { return; @@ -660,7 +675,24 @@ namespace UniVRM10.VRM10Viewer return; } - LoadModel(path); + _ = LoadModel(path); + } + + /// + /// for WebGL + /// call from OpenFile.jslib + /// + public void FileSelected(string url) + { + Debug.Log($"FileSelected: {url}"); + StartCoroutine(LoadCoroutine(url)); + } + + IEnumerator LoadCoroutine(string url) + { + var www = new WWW(url); + yield return www; + var _ = LoadModel("WebGL.vrm", www.bytes); } async void OnOpenMotionClicked() @@ -760,7 +792,29 @@ namespace UniVRM10.VRM10Viewer } } - async void LoadModel(string path) + IAwaitCaller GetIAwaitCaller() + { + if (m_useAsync) + { +#if UNITY_WEBGL + return new RuntimeOnlyNoThreadAwaitCaller(); +#else + return new RuntimeOnlyAwaitCaller(); +#endif + } + else + { + return new ImmediateCaller(); + } + } + + async Task LoadModel(string path) + { + var bytes = await File.ReadAllBytesAsync(path); + await LoadModel(path, bytes); + } + + async Task LoadModel(string path, byte[] bytes) { // cleanup m_loaded?.Dispose(); @@ -772,10 +826,10 @@ namespace UniVRM10.VRM10Viewer try { Debug.LogFormat("{0}", path); - var vrm10Instance = await Vrm10.LoadPathAsync(path, + var vrm10Instance = await Vrm10.LoadBytesAsync(bytes, canLoadVrm0X: true, showMeshes: false, - awaitCaller: m_useAsync.enabled ? new RuntimeOnlyAwaitCaller() : new ImmediateCaller(), + awaitCaller: GetIAwaitCaller(), vrmMetaInformationCallback: m_texts.UpdateMeta, ct: cancellationToken, springboneRuntime: m_useSpringboneSingelton.isOn ? new Vrm10FastSpringboneRuntime() : new Vrm10FastSpringboneRuntimeStandalone()); diff --git a/Assets/VRM_Samples/SimpleViewer/FileDialog/FileUtil.cs b/Assets/VRM_Samples/SimpleViewer/FileDialog/FileUtil.cs index b7c73f2c8..49455fc6c 100644 --- a/Assets/VRM_Samples/SimpleViewer/FileDialog/FileUtil.cs +++ b/Assets/VRM_Samples/SimpleViewer/FileDialog/FileUtil.cs @@ -7,9 +7,9 @@ namespace VRM.SimpleViewer #if UNITY_STANDALONE_WIN return FileDialogForWindows.FileDialog(title, extensions); #elif UNITY_WEBGL - // Open WebGLFileDialog - // see: Assets\VRM_Samples\SimpleViewer\Plugins\OpenFile.jslib - WebGLUtil.WebGLFileDialog(); + // Open WebGL_VRM0X_SimpleViewer_FileDialog + // see: Assets/UniGLTF/Runtime/Utils/Plugins/OpenFile.jslib + WebGLUtil.WebGL_VRM0X_SimpleViewer_FileDialog("Canvas", "FileSelected"); // Control flow does not return here. return empty string with dummy return ""; #elif UNITY_EDITOR diff --git a/Assets/VRM_Samples/SimpleViewer/FileDialog/WebGLUtil.cs b/Assets/VRM_Samples/SimpleViewer/FileDialog/WebGLUtil.cs index 1d94e2de8..06dea7b71 100644 --- a/Assets/VRM_Samples/SimpleViewer/FileDialog/WebGLUtil.cs +++ b/Assets/VRM_Samples/SimpleViewer/FileDialog/WebGLUtil.cs @@ -6,7 +6,7 @@ namespace VRM.SimpleViewer public static class WebGLUtil { [DllImport("__Internal")] - public static extern void WebGLFileDialog(); + public static extern void WebGL_VRM0X_SimpleViewer_FileDialog(string target, string message); } } -#endif \ No newline at end of file +#endif diff --git a/Assets/VRM_Samples/SimpleViewer/Plugins.meta b/Assets/VRM_Samples/SimpleViewer/Plugins.meta index fdecce026..7c4d5035c 100644 --- a/Assets/VRM_Samples/SimpleViewer/Plugins.meta +++ b/Assets/VRM_Samples/SimpleViewer/Plugins.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: ccb1849bc34bcd740ba2e17462125200 +guid: 453de3a4f46d44d4087a1fca730e04d5 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/VRM_Samples/SimpleViewer/Plugins/WebGL_VRM0X_SimpleViewer.jslib b/Assets/VRM_Samples/SimpleViewer/Plugins/WebGL_VRM0X_SimpleViewer.jslib new file mode 100644 index 000000000..11c9321aa --- /dev/null +++ b/Assets/VRM_Samples/SimpleViewer/Plugins/WebGL_VRM0X_SimpleViewer.jslib @@ -0,0 +1,23 @@ +mergeInto(LibraryManager.library, { + WebGL_VRM0X_SimpleViewer_FileDialog: function (_target, _message) { + const target = UTF8ToString(_target); + const message = UTF8ToString(_message); + 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.style.visibility = 'hidden'; + file_input.onclick = function (event) { + event.target.value = null; + }; + file_input.onchange = function (event) { + console.log('SendMessage', target, message); + SendMessage(target, message, URL.createObjectURL(event.target.files[0])); + } + document.body.appendChild(file_input); + } + file_input.click(); + }, +}); diff --git a/Assets/VRM_Samples/SimpleViewer/Plugins/WebGL_VRM0X_SimpleViewer.jslib.meta b/Assets/VRM_Samples/SimpleViewer/Plugins/WebGL_VRM0X_SimpleViewer.jslib.meta new file mode 100644 index 000000000..d1ccd5cd3 --- /dev/null +++ b/Assets/VRM_Samples/SimpleViewer/Plugins/WebGL_VRM0X_SimpleViewer.jslib.meta @@ -0,0 +1,32 @@ +fileFormatVersion: 2 +guid: ef25d97dc58954a4ca17b4173225e58f +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: diff --git a/Assets/VRM_Samples/SimpleViewer/ViewerUI.cs b/Assets/VRM_Samples/SimpleViewer/ViewerUI.cs index 3a4988c90..575f44556 100644 --- a/Assets/VRM_Samples/SimpleViewer/ViewerUI.cs +++ b/Assets/VRM_Samples/SimpleViewer/ViewerUI.cs @@ -4,7 +4,6 @@ using System.IO; using System.Linq; using System.Threading.Tasks; using UniGLTF; -using UniGLTF.SpringBoneJobs; using UniHumanoid; using Unity.Collections; using UnityEngine; @@ -294,8 +293,7 @@ namespace VRM.SimpleViewer private void Start() { - m_version.text = string.Format("VRMViewer {0}.{1}", - PackageVersion.MAJOR, PackageVersion.MINOR); + m_version.text = string.Format("SimpleViewer {0}", PackageVersion.VERSION); m_open.onClick.AddListener(OnOpenClicked); m_reset.onClick.AddListener(() => m_loaded?.ResetSpringbone()); @@ -359,9 +357,9 @@ namespace VRM.SimpleViewer IEnumerator LoadCoroutine(string url) { - var www = new UnityEngine.Networking.UnityWebRequest(url); + var www = new WWW(url); yield return www; - var task = LoadBytesAsync("WebGL.vrm", www.downloadHandler.data); + var task = LoadBytesAsync("WebGL.vrm", www.bytes); } /// diff --git a/ProjectSettings/EditorBuildSettings.asset b/ProjectSettings/EditorBuildSettings.asset index 6dc24f7df..62587d23f 100644 --- a/ProjectSettings/EditorBuildSettings.asset +++ b/ProjectSettings/EditorBuildSettings.asset @@ -4,4 +4,11 @@ EditorBuildSettings: m_ObjectHideFlags: 0 serializedVersion: 2 - m_Scenes: [] + m_Scenes: + - enabled: 0 + path: Assets/VRM_Samples/SimpleViewer/SimpleViewer.unity + guid: 5d0b0ec0bd1cdee4fbd25b64a6d059df + - enabled: 1 + path: Assets/VRM10_Samples/VRM10Viewer/VRM10Viewer.unity + guid: c91fa5ff7b6696646a8b16d9bf88a5c2 + m_configObjects: {} diff --git a/ProjectSettings/ProjectSettings.asset b/ProjectSettings/ProjectSettings.asset index dca42bdd7..4574a21f1 100644 --- a/ProjectSettings/ProjectSettings.asset +++ b/ProjectSettings/ProjectSettings.asset @@ -602,7 +602,7 @@ PlayerSettings: webGLTemplate: APPLICATION:Default webGLAnalyzeBuildSize: 0 webGLUseEmbeddedResources: 0 - webGLCompressionFormat: 1 + webGLCompressionFormat: 2 webGLWasmArithmeticExceptions: 0 webGLLinkerTarget: 1 webGLThreadsSupport: 0 @@ -628,7 +628,7 @@ PlayerSettings: Stadia: UNITY_POST_PROCESSING_STACK_V2 Standalone: VRM_DEVELOP;UNITY_POST_PROCESSING_STACK_V2 VisionOS: UNITY_POST_PROCESSING_STACK_V2 - WebGL: UNITY_POST_PROCESSING_STACK_V2 + WebGL: UNITY_POST_PROCESSING_STACK_V2;VRM_DEVELOP Windows Store Apps: UNITY_POST_PROCESSING_STACK_V2 XboxOne: UNITY_POST_PROCESSING_STACK_V2 tvOS: UNITY_POST_PROCESSING_STACK_V2