UNITYのWebGLコンテンツからパノラマ画像をダウンロードする


UNITYのWebGLコンテンツで3DコンテンツをWEBブラウザで稼働させ、そのコンテンツからパノラマ画像を生成し、ローカルPCに画像を保存する方法についてです。

目的はUNITYで作成したWebGLコンテンツをWEB上で公開するにあたり、ユーザーが自由にゲーム中のシーンのパノラマ画像を取得できるインターフェースを提供することです。

記事でのUNITYバージョンは2019.1.6f1、WebGL Build Supportとします。
また、環境はWindows10、ブラウザはChromeとします。

[File:Build Settings]を開きます。
[Platform]の項目からWebGLを選択します。
右下にある[Switch Platform]をクリックし切り替えます。

これでWebGLコンテンツのビルドができるようになります。
試しに素の状態でbuildができるか試してみます。
※結構時間がかかりますが、工程を進めてbuildできないということになるとダメージ大なので試してみることをお勧めします。

[File:Build and Run]を開きます。
現在のプロジェクトのフォルダが開きますので、例えば[build]というディレクトリを作成します。

[build]のディレクトリを選択し[フォルダーの選択]をクリックするとビルドが開始します。
PCのグレードによりますが、かなり待つとChromeでWebGLコンテンツが開きます。

素の状態なのでSkyBoxとダイレクトライト、Main Cameraしかありません。
したがって上記のような画像が表示されるだけです。

[Build and Run]でWebGLビルドを行うと初回だけなぜかChromeで実行できるのですが、二回目以降ではローカルのビルド成果物をChromeで実行できません。
動作確認を行うにはWebサーバーにアップロードしてChromeで確認しています。

パノラマ画像の作成ですが、「360-screenshot-capture」という無料アセットを使わせていただきます。

https://assetstore.unity.com/packages/tools/camera/360-screenshot-capture-112864

インポートします。

空のゲームオブジェクトを作成します。

適当に分かりやすい名前に変更します。
ここではEmptyGameObjectとします。

適当なアクセス可能なフォルダに”Panorama.cs”というスクリプトファイルを生成します。
今回はAssets/Plagin/Simple360Render配下に生成します。

“Panorama.cs” を以下のように編集します。

using System.IO;
using UnityEngine;
#if UNITY_WEBGL
using System.Runtime.InteropServices;
#endif

public class Panorama : MonoBehaviour
{
#if UNITY_WEBGL
    [DllImport("__Internal")]
    private static extern void FileDownLoad(byte[] bytes, int size, string filename);
#endif

    public int imageWidth = 4096;
    public string filename = "skyonsea_panorama.png";
    private bool saveAsJPEG = false;

    // LateUpdate is called once per frame
    void LateUpdate()
    {
        if (Input.GetKeyDown(KeyCode.P))
        {
            byte[] bytes = I360Render.Capture(imageWidth, saveAsJPEG);
            if (bytes != null)
            {
#if UNITY_EDITOR
                string path = Path.Combine(Application.persistentDataPath, filename);
                File.WriteAllBytes(path, bytes);
                Debug.Log(filename + " has been saved into " + path);
#elif UNITY_WEBGL
                FileDownLoad(bytes, bytes.Length, filename);
#endif
            }
        }
    }
}

Assets/Plugins/WebGL というディレクトリを作成し、以下のコードを “FileDownload.jslib” というファイルネームで保存します。

var FileDownloadPlugin = {
    FileDownLoad: function(pImage , size, pStr) {
        var mimeType = 'data:image/png;base64';
        var filename = Pointer_stringify(pStr);
        var binary = new ArrayBuffer(size);
        var dv = new DataView(binary);

        for (var i = 0; i < size; i++)
            dv.setUint8(i, HEAPU8[pImage + i]);
        var blob = new Blob([binary], {type : mimeType});
        const a = document.createElement('a');
        a.href = window.URL.createObjectURL(blob);
        a.download = filename;
        a.style.display = 'none';
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
    }
}
mergeInto(LibraryManager.library, FileDownloadPlugin);

Panorama.csをEmpty EmptyGameObjectにアタッチします。

この状態でUnity Editorを再生すると[p]キーでパノラマキャプチャすることができます。

キャプチャされた画像の格納場所はUnity Editorの最下段にデバッグ情報として表示されます。
設定にもよりますが、以下のディレクトリにskyonsea_panorama.pngとして保存されると思います。

C:/Users/%USERNAME%/AppData/LocalLow/DefaultCompany/%PROJECTNAME%

画像は例えば以下のようなものです。

この画像はシーンのパノラマ画像です。
背後に有ったSkyBoxの太陽が見えます。
WebGLとしてビルドしたものをChromeで実行しても、同様にパノラマ画像をダウンロードすることができます。

左下をご確認ください。
ダウンロードディレクトリにパノラマ画像がダウンロードされていると思います。

さてこれでパノラマ画像をダウンロードする仕組みはできました。
後はシーンを作り上げていけば良いことになります。

以下は作例です。

この作例では以下の有料アセットを使っています。

aquas-water-river-set
massive-clouds-screen-space-volumetric-clouds

このWebGLコンテンツをクリック/マウスオーバーしてから[p]キーを押下してください。
Windows10のChromeならパノラマ画像がダウンロードできるかと思います。

如何でしょうか?
ゲーム等にパノラマ画像をダウンロードさせるインターフェースを簡単に設置できることがお分かり頂けたかと存じます。

ただし注意事項があります。
なんでもがパノラマ画像としてキャプチャされるわけではないようなのです。
WebGLとしてビルド可能であることは必須なのですが、例えWebGLとして表示できていたとしてもパノラマ画像としてキャプチャできない例に遭遇します。

例えば私はAQUASのアセットを持っていて、無料アップグレード特典で入手したAQUAS 2020も持っているわけです。
当然AQUAS 2020の方が高機能なのでAQUAS 2020を使ったWebGLコンテンツでパノラマ画像を取得したいのです。
しかしなぜかAQUAS2020のエフェクトがパノラマ画像に反映されません。
理由が分かる方、お教え頂けると助かります。

UNITYはひと時も同じ状態で留まりません。
バージョン毎の差分、アセットの対応バージョン、組み合わせなどが多すぎて上手くいかないことが多いと痛感します。

前はこれでできたから、と思って新作アセットと組み合わせようと思うと、意味不明のエラーメッセージが出力される。
やっとの思いで解決しても、最新のバージョンではまた別の問題に直面する。
その度にググり、ログを見て原因を探り、解決したり諦めたり。

最近では諦めることが多いです。
実を言うと今回の記事、Unity-Chan “Candy Rock Star”でやろうかなと思っていたのですが、 UNITY 2019のWebGLでBuildできず諦めています。

とは言え、簡単に背景を作ることとだけに着目するとそれほど大きな変化が無いので背景作成ツールとしては長いこと使い続けています。

この記事がだれかのお役に立てば幸いです。


挿絵画家になろう(その11)


「挿絵画家になろう(その11)」です。
これまでBlenderのアドオン、MB-Labの啓蒙として記事を連ねてきました。
MB-Labを使って秀逸な少女キャラクターのメッシュオブジェクトを生成し、VRoidStudioの髪をインポートして装着させ、そこそこの服を着せ、キャラクターのマテリアルも弄れるようになり、表情も変更できるようになり、同梱のポーズを組み合わせて新しいポーズも作れるようになりました。
そして服に関しても、まあそれなりに用意できるようになりました。

そろそろ背景が欲しいな、と思います。
単に背景と言っても色々です。
単色塗りつぶしやグラデーションハイライトといった2Dペイントツールでの描画でも良いし、当然ガチンコで屋内屋外の風景を描いても良いです。

ただ、我々は本来「(自称)小説家」です。
自分の小説に挿絵を付けることが目的です。
当然挿絵を書く時間は最小限に留め、その分小説執筆に時間を割きたいですよね?
そのためのいくつかのソリューションを考えました。
ただ残念ながら無料ではありません。
無料でもできなくはないですが、そこはクオリティとのトレードオフになりますね。

本記事はWindows10のChrome推奨です。
その他の環境でどうなるのかは検証していません。
以下のWEBGLコンテンツは参照できますでしょうか?

これはUNITYで作成したWEBGLコンテンツです。
正常に動作していれば、海と空の動く風景が表示されます。
海は波たち、空には雲が流れます。
このような風景が簡単に作れてしまうのです。
UNITY自体は(個人ユースであれば)無料で使えるのですが、今回は以下の有料アセットを使っています。

aquas-water-river-set
massive-clouds-screen-space-volumetric-clouds

屋外風景を考えるに、先ず超遠景としての空や大地もしくは海があり、それよりも近い遠景があり、地形を特徴付ける中近景があり、周囲環境があるわけです。
我々は人物モチーフをMB-Labの3Dキャラクターにする決心をしました。
では風景もある程度は3Dで固めていきましょう。
そのための超遠景に関して先ずは考えよう、というわけです。

上のWEBGLコンテンツをChrome上でマウスオーバーしてアクティブにし、[p]キーを押してみてください。
skyonsea_panorama.png という画像ファイルがダウンロードされれば期待動作です。
適当な画像ビューアで開くと以下のようなパノラマ画像であることが分かります。

上のWEBGLコンテンツは空と海の風景をパノラマ画像として生成するツールでもあるのです。
タイミングを選んで [p]キー を押すことにより、希望の雲の画像を得ることができるのです。

3Dキャラクターを最終的にどのプラットフォームで作品に仕上げるのかは検討すべき課題です。
ただし、今回は結論を出しません。
と言うか、空と海をUNITYで作っておきながら、今回はUNITYでどのように風景を作るのか、という話をしたい訳でもありません。
あくまでも風景画像をBlenderで表示してとりあえずは空と海がある風景の中、3Dキャラクターをレンダリングする方法に関して述べるだけです。

さて、パノラマ画像のサンプルを得ることができました。
この画像を任意のプラットフォームに持っていき、背景に使えば良いわけです。
UNITYのSkyBoxに再移植することもできますし、Daz Studio等、たいていの3Dインテグレーションツールで表示させることができます。
今回はBlenderの背景にする方法を説明したいと思います。

Blenderでの設定方法は簡単です。
先ずオブジェクトモードであることを確認してプロパティウインドウのワールド(青い円のマーク)を選択します。

「サーフェス」の項の「ノードを使用」をクリックします。

「サーフェス」の項に背景が設定されました。

「スクリーンレイアウトの選択」から「compositing」を選択します。

「ノード」を「マテリアル」、「シェーダーを取得するためのデータタイプ」を「ワールド」に切り替えます。

[shift+a]で現れる「追加」メニューから以下を追加します。
・テクスチャ:環境テクスチャ
・ベクトル:マッピング
・入力:テクスチャ座標
そして以下のように連結させます。

環境テクスチャにパノラマ画像を読み込みます。
3Dビューの「3Dビューのシェーディング」で「レンダー」を選択すると背景が描画されます。
もし青っぽくなるけれど全景が表示されないという場合は投影方式が「平行投影」となっています。
テンキーの[5]キーを押して「透視投影」に切り替えます。

後はノードの「マッピング」を調整して背景画像を調整します。
色々極端な設定にすると変化があって面白いです。

MB-Labのキャラクターの背景にしてみました。

いかがでしょうか?
パノラマ画像があれば、それを背景に設定できました。
別に普通の画像でも背景にできますが、パノラマ画像だとアングルやズームが思いのままですので自由度が高いのが良いです。

問題はどのようにしてパノラマ画像を入手するかです。
WEB上では無料素材としてパノラマ画像を公開していらっしゃる方もおられます。
気に入るものがあればそれを使うのでも良いでしょう。
気に入ったものが無いのならば自分で作成するという手もあります。
TwinMotionでも天候を決めてパノラマ画像で出力することができます。
素材を用意できるのならばTwinMotionで背景画像を作るのは良い選択かもしれません。

今回UNITYを使いましたが、正直なところ小説家になろうの諸兄姉にはお勧めしていません。
理由は満足する画像を作れるようになるまでのハードルが高いことです。
無料で希望する絵作りをするにはかなりスキルを磨く必要があります。
もしくは有料アセットを購入する必要があります。
たとえ有料アセットを購入したところで、バージョンやアセット毎の組み合わせがあり、なんかよく分からない障害にぶつかります。
UNITYってバージョンアップが激しくて古いアセットは新しいバージョンで使えなくなっていることが多いんですよね……。
あのアセットとこのアセットを組み合わせれば、と思いホクホクしていると「なんでこうなる?」ということが多々あり、解決のためにログ見たりググったり、そして夜は更けてゆく。
好きなら良いんですが、誰もがそんなマゾという訳じゃないですよね?
UNITYって本当によく分からない。

上のWEBGLコンテンツで生成した画像は小説の挿絵背景としてならば自由にお使い頂いて構いません。

今回はこれで終わりです。
UNITYでWEBGLコンテンツとしてパノラマ画像を生成・ダウンロードする方法に関しては別方面で需要があるかもしれません。
機会があれば別記事にまとめたいと思っています。
また、時間があれば[その12]を書きたいと思います。