見出し画像

UnityのWebGLビルドで、ブラウザで動くVRMビューワーを作る

初めましての方は初めまして!
HIKKY開発チームに努めるフロントエンドエンジニアのメカニック24歳、現役美少女アイドル。です。

本記事では、VR法人HIKKYが主催するVket系イベントで使われている、Unity WebGLビルドで制作されたアプリケーションの紹介と、それらに使われている基礎的な技術を紹介したいと思います。

Vketで活用されるUnity WebGLビルド

まず最初に、Unity WebGLについて凄く簡単に説明すると、Unityで作ったアプリケーションをそのままWebブラウザ上で実行可能にするものです。
Webブラウザというプラットフォームの制限があるため、Unityの全ての機能が使える訳ではありませんが、Unityで作ったアプリケーションをそのままWebブラウザに持ってこれるのは魅力的です。
HIKKYが主催する、〇〇Vket系イベント(ComV,MusV,GamV)で使われている入稿ツールは、全てこのUnity WebGLで作られています。
Unityで制作されているので、実際にイベント会場に配置された際と同様の動作を、Webブラウザで手軽に確認できるのがこれらのツールの強みです。

入稿物のルックを確認をしつつ、入稿を進められる

Unity WebGLでVRMビューワーを作る

Unity WebGLの技術的側面を紹介するにあたって、本記事ではブラウザで動作するVRMビューワーの作り方を紹介したいと思います。

準備

まずはUnity WebGLビルドがインストールされたプロジェクトにVRM1.0のunitypackageをインポートします。
本記事では、執筆時点での最新版(v0.109.0)を前提に解説していきます。

pluginの作成

UnityとWebページで相互にやり取りするアプリケーションを作る際にはpluginを使う方法が一般的です。
Unityのassets直下にpluginsフォルダを作成し、そこにjavascriptで書かれた.jslibファイルを配置することでUnityのスクリプトからjavascriptのコードを実行できます。
今回は、実行時にinput要素を作成するCreateInput関数と、Unityのボタンがクリックされたときにinput要素がクリックされたかのように動作させるClickInput関数を用意しました。

// plugins/InputPlugin.jslib
  var InputPlugin = {
    CreateInput: function() {
      var name = 'WebGLVRM'
      // input要素を作成
      var fileInput = document.createElement('input');
      fileInput.setAttribute('type', 'file');
      fileInput.setAttribute('accept', '.vrm');
      fileInput.setAttribute('id', name);
      fileInput.onclick = function (event) {
        this.value = null;
      };
      // ファイルが選択されたらblobをUnity側のFileSelectedに渡す
      fileInput.onchange = function (event) {
        SendMessage('WebGLVRM', 'FileSelected', URL.createObjectURL(event.target.files[0]));
      }
      document.body.appendChild(fileInput);
    },
    ClickInput: function() {
      var name = 'WebGLVRM'
      document.getElementById(name).click();
    }
  };
  mergeInto(LibraryManager.library, InputPlugin);

上記のコードをコピー&ペーストして使い際には、コメントアウトした行を削除して使ってください。

Unityのスクリプトの作成

VRMの読み込み等をおこなうスクリプトを作成します。
スクリプトをアタッチするオブジェクトの名前は、必ずpluginのSendMessageで1つ目の引数に渡した名前(今回は”WebGLTest”)と同じにしてください。名前が違うとSendMessageを受け取ることが出来ません。

// scripts/WebGLVRMOpenFile.cs
using System.Collections;
using System.Runtime.InteropServices;
using UnityEngine;
using UniVRM10;
using VRMShaders;

public class WebGLVRMOpenFile : MonoBehaviour
{
    // pluginから関数を読み込む
    [DllImport("__Internal")]
    private static extern void CreateInput();
    [DllImport("__Internal")]
    private static extern void ClickInput();

    // inputタグを生成する
    void Start()
    {
        CreateInput();
    }

    // ボタンをクリックしたときの処理
    public void UploadButtonClick()
    {
        ClickInput();
    }

    // inputタグに変更があったときに呼び出される
    // urlにはinputで選択したファイルのblobが渡される
    public void FileSelected(string url)
    {
        Debug.Log(url);
        StartCoroutine(LoadFile(url));
    }

    // blobからバイト配列を読み込んで、VRMをロードする
    private IEnumerator LoadFile(string url)
    {
        yield return new WaitForSeconds(0.1f);
        WWW www = new WWW(url);
        yield return www;

        byte[] fileContent = www.bytes;

        Vrm10.LoadBytesAsync(fileContent,true,new ControlRigGenerationOption(),true, new RuntimeOnlyNoThreadAwaitCaller());
    }
}

アプリケーションのビルド

Unity上で動作の確認が出来たら、アプリケーションをビルドします。
もし、ビルド後のアプリケーションを実行した際に「Unable to parse Build/HTML5.framework.js.gz!」というエラーが表示された場合、Player Settingsを開きPublishing SettingsにあるDecompression Fallbackという項目にチェックを入れてください。

動作確認

ビルドしたファイルを適当なWebサーバーにアップロードし、動作を確認します。

動いた!

Unity WebGLで出力したアプリケーションは、Webサーバーに配置しないと動作しないのですが、毎回動作確認のためにWebサーバーを構築するのは非常に手間がかかります。
そういう時は、こちらのChromeアドオンを使うと便利です。

まとめ

参考に、本記事の執筆にあたって製作したUnityプロジェクトのgithubを置いておきます。
上記のスクリプトに加えて簡易的なカメラ操作などを加えてあります。

最後に

ここまでの記事を見て「簡単だな……」と思った、そこのあなた!
VR法人HIKKYではあなたのような優秀なエンジニアを常に募集しています。
HIKKY開発チームはフルリモートで勤務可能かつ、実名を晒す必要もありません。
興味がある方は下記ページからお気軽にご応募ください!