HugoでUnity WebGLを表示する

もう半年以上前の話になりますが、WordpressからHugoにサイトを移行した際、Unityコンテンツを移植する必要がありました。

慣れないHugoと解凍エラーで苦労したものの、無事Unityコンテンツの表示に成功、さて記事を書くぞという段階で放置してしまっていたので、今更ながらきちんと記事にして残しておこうと思います。

手順としては適切なビルド設定をした上で、Unity公式のWebGLテンプレートを流用してショートコードを作るだけの単純なものとなっております。使用したツールのバージョンは以下の通り。

  • Hugo: v0.120.4
  • Unity: 2022.3.11f1 (LTS)

ビルド設定

まずはUnityのプロジェクトを開き、ビルド設定からプラットフォームをWebGLに切り替えます。

次に「編集→プロジェクト設定→プレイヤー→解像度と表示」から「WebGLテンプレート」の項目をMinimalに変更。テンプレートを改変して使うため、内容は最低限の方が都合がいいです。

次に同ページの「公開設定」から「解凍フォールバック」を有効にします。詳細は公式リファレンスに任せますが、要は「圧縮されたコンテンツの解凍に失敗しても大丈夫なようにしとくよ」という機能です。

Unity ユーザーマニュアル Deploy WebGL application

解凍の成否はブラウザやサーバー設定に依存するようで、私の環境では「Unable to parse Build/test.framework.js.gz!」といったエラーが出て解凍できませんでした。これを有効にすることで出力されるloader.jsのサイズが僅かに大きくなりますが、解凍できない環境でもUnityを実行できるようになります。

圧縮形式はBrotliかGZipをお好みで選択して大丈夫だと思います。無圧縮はファイルサイズが膨れ上がるのでオススメしません。

設定が終わったらプロジェクトをビルドし、次の作業に移ります。

ショートコードの作成

出力したファイルの構成は以下のようになっています。

  • [ビルドの出力先]/
    • index.html
    • Build/
      • [ビルドの出力先].data.js.[圧縮形式]
      • [ビルドの出力先].framework.js.[圧縮形式]
      • [ビルドの出力先].loader.js
      • [ビルドの出力先].wasm.[圧縮形式]

ビルドの出力先が一部ファイル名に割り当てられ、圧縮設定に応じて拡張子が追加されます。

解凍フォールバックが有効なら「.unityweb」が、そうでない場合はBrotliで「.br」、GZipで「.gz」が拡張子になります。無圧縮の場合は拡張子の追加はありません。

これらの内、index.htmlがUnityコンテンツ(Buildフォルダ内)を呼び出すファイルにあたるため、これを一部抜粋してショートコードにします。

index.htmlの中身は割愛しますが、必要なのは<canvas><script>の部分です。これにパスや解像度などの、プロジェクトに依存する箇所をパラメータで制御できるようにしたものが以下になります。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
{{ $path := "Build/" }}
{{ with .Get "path"}}
    {{ $path = . }}
{{ end }}
{{ $build := .Get "build"}}
{{ $ext := ".unityweb" }}
{{ with .Get "ext" }}
    {{ $ext = . }}
{{ end }}
{{ $width := .Get "width" }}
{{ $height := .Get "height"}}
{{ $bgc := "#000000" }}
{{ with .Get "bgc" }}
    {{ $bgc = . }}
{{ end }}

<canvas id="unity-canvas" width={{ $width }} height={{ $height }} tabindex="-1" style="width: {{ $width }}px; height: {{ $height }}px; background-color: {{ $bgc }}"></canvas>
<script src="{{ $path }}{{ $build }}.loader.js"></script>
<script>
    if (/iPhone|iPad|iPod|Android/i.test(navigator.userAgent)) {
        // Mobile device style: fill the whole browser client area with the game canvas:
        var meta = document.createElement('meta');
        meta.name = 'viewport';
        meta.content = 'width=device-width, height=device-height, initial-scale=1.0, user-scalable=no, shrink-to-fit=yes';
        document.getElementsByTagName('head')[0].appendChild(meta);

        var canvas = document.querySelector("#unity-canvas");
        canvas.style.width = "100%";
        canvas.style.height = "100%";
        canvas.style.position = "fixed";

        document.body.style.textAlign = "left";
    }
    createUnityInstance(document.querySelector("#unity-canvas"), {
        dataUrl: "{{ $path }}{{ $build }}.data{{ $ext }}",
        frameworkUrl: "{{ $path }}{{ $build }}.framework.js{{ $ext }}",
        codeUrl: "{{ $path }}{{ $build }}.wasm{{ $ext }}",
        streamingAssetsUrl: "StreamingAssets",
        companyName: "{{ .Site.Title }}",
        productName: "{{ .Get "name" }}",
        productVersion: "{{ .Get "version" }}",
        // matchWebGLToCanvasSize: false, // Uncomment this to separately control WebGL canvas render size and DOM element size.
        // devicePixelRatio: 1, // Uncomment this to override low DPI rendering on high DPI displays.
      });
</script>

冒頭でショートコードのパラメータを受け取り、<canvas><script>の一部に反映させています。使用できるパラメータは以下の通りです。

  • build
    • ビルド時に指定した出力先フォルダです。ファイル名の一部になるため必須です。
  • path(省略可)
    • 使用するフォルダ名。初期値は「Build/」です。
    • ルート相対パスでの呼び出しや、Buildフォルダの名前を変更している場合に指定が必要です。
  • ext(省略可)
    • 圧縮形式の拡張子。解凍フォールバックを使う前提で.unitywebを初期値にしています。
    • このコードでは無圧縮を指定することが出来ませんが、そもそも使わない想定なので妥協しました。
  • name
    • プロジェクトの名前。
  • version
    • プロジェクトのバージョン。
  • width, height
    • コンテンツの横幅と縦幅。canvasとcssの両方で使われます。
  • bcg(省略可)
    • 背景色。コンテンツが読み込まれるまでこの色が表示されます。
    • 初期値は無難に黒を指定しています。

上記のコードをHugoサイト内の「layouts/shortcodes/」に配置します。ファイル名がそのままショートコードになりますので、他と競合しない範囲でご自由にどうぞ。ここではシンプルに「unity.html」とした体で進めます。

同一ディレクトリでの実行

次に、実行したいコンテンツ(Buildフォルダ)をHugoサイトの任意のディレクトリに配置します。(index.htmlは不要です)

この時、ショートコードを実行するindex.mdとBuildフォルダが異なるディレクトリにある場合は次項を参照してください。

あとはindex.mdの任意の箇所に、作成したショートコードを記述することでUnityコンテンツを呼び出すことが出来ます。

{{< unity build="ビルド時の出力先フォルダ名" width="" height="" name="プロジェクト名" version="" >}}

各パラメータを記述し、必要に応じてext=".gz"bgc="#ffffff"といった設定を追加してください。

異なるディレクトリでの実行

もしindex.mdとBuildフォルダが異なるディレクトリに存在する場合は、ショートコードの「path」パラメータにBuildフォルダのディレクトリを指定する必要があります。

例えば、Buildフォルダを「/static/test/」に配置している場合は以下のように記述します。

{{< unity path="/test/Build/" build="" width="" height="" name="" version="" >}}

ルート相対パスで指定することによりindex.mdの場所に依存せず実行できます。他にも「同一フォルダにindex.mdとBuildフォルダがあるが、そのindex.mdの中身を他のページからも表示している」といった場合でもpathの指定が必要になるかと思います。

まとめ

以上、HugoでUnity WebGLを実行するための手順でした。重要なのは以下の2点です。

  • Unityコンテンツの解凍に失敗する場合、「解凍フォールバック」を有効にする
  • ビルド時の出力名、Buildフォルダのパス、拡張子の指定を適切に行う

これらに見落としがあると実行時にエラーが出るため、動作しない場合は上記を確認してみると改善するかもしれません。

余談ですが、私が移行しようと思っていたプロジェクトの一つは、最新バージョンで開くとモデルの座標軸が変わったのかモーションが大変恐ろしいことになっていました。さてどうしたものか…