TECHブログ


360度全天球パノラマのWebGLコンテンツをUnityで作る

はじめに

コロナ禍で展示会などのイベント開催ができない代わりに、オンラインでの開催も増えています。そうした際に、Webブラウザ上に全天球パノラマを表示して360度見渡すバーチャル体験ができるコンテンツを多く目にします。今回は、Webブラウザで表示できるコンテンツをUnityを使った制作を紹介します。

開発環境

  • Unity2019.4.x
  • Visual Studio 2019

事前準備

  • 動作確認用にApache等でローカル環境にWebサーバを立てておく
  • UnityはWebGL用にビルドできる設定にしておく
  • 360度パノラマ用の画像を準備しておく

Unityでの実装

パノラマ天球画像の表示

UnityではSkybox用のシェーダーを使用すれば簡単にパノラマ画像の表示ができます。
今回は、https://hdrihaven.comから画像をダウンロードして使用しました。

Skybox/Panoramicシェーダーを割り当てたマテリアルのテクスチャとして画像を使用します。
単純にパノラマ画像を表示するだけであれば、Skyboxのテクスチャとして画像をアサインすれば表示できますが、今回はパノラマ上にHotspotとオブジェクトを配置していくので、全天球モデルのGameObjectを作成して使用します。
また、パノラマを切り替えて遷移する仕組みにしたいので、パノラマ画像の数だけ用意しました。
全天球モデルは、https://catlikecoding.com/unity/tutorials/octahedron-sphereのoctahedron-sphere-meshesを使用しました。

カメラのマウス操作

球体の中心にカメラを配置することで、全天球パノラマの内部に入ることができます。

Webブラウザ上で360度自由に見渡せるようにするために、以下のScriptを適用させます。マウス操作でカメラの回転とズームイン/アウトができるようになります。

public class ControlCamera : MonoBehaviour
{
    public float mouseSensitivity = 1f;
    private float miniX = -360f;
    private float maxX = 360f;
    private float miniY = -90f;
    private float maxY = 90f;
    private float rotX = 0f;
    private float rotY = 0f;

    private Quaternion originalRot;
    private float scroll = 0f;
    public float scrollSpeed = 1f;

    private float minFov = 20f;
    private float maxFov = 100f;
    private float originFov;

    void Start()
	{       
        originalRot = Camera.main.transform.localRotation;
        originFov = Camera.main.fieldOfView;
    }

    void Update()
    {
        if (Input.GetMouseButton(0))
        {
            rotX -= Input.GetAxis("Mouse X") * mouseSensitivity;
            rotY -= Input.GetAxis("Mouse Y") * mouseSensitivity;
            rotX = ClampAngle(rotX, minimumX, maximumX);
            rotY = ClampAngle(rotY, minimumY, maximumY);
            Quaternion xQuaternion = Quaternion.AngleAxis(rotX, Vector3.up);
            Quaternion yQuaternion = Quaternion.AngleAxis(rotY, Vector3.left);
            Camera.main.transform.localRotation = originalrot * xQuaternion * yQuaternion;
        }        

        scroll = Input.GetAxis("Mouse ScrollWheel");
        Camera.main.fieldOfView -= scroll * scrollSpeed;
        if (Camera.main.fieldOfView < minFov)
        {
            Camera.main.fieldOfView = minFov;
        }
        else if (Camera.main.fieldOfView > maxFov)
        {
            Camera.main.fieldOfView = maxFov;
        }
    }

    // カメラ操作補正
    public static float ClampAngle(float angle, float min, float max)
    {
        if (angle < -360f)
            angle += 360f;
        if (angle > 360f)
            angle -= 360f;
        return Mathf.Clamp(angle, min, max);
    }
}

Hotspotの配置

Hotspotとはパノラマ上で特別な情報を持った場所のことで、特定箇所の説明を表示させたり、ボタンのようにクリックすることでインタラクティブ性を持たせたりします。
通常WebGLで全天球上にHotspotを配置する場合は緯度軽度の座標系で考える必要があるので結構ややこしくて面倒な作業になります。今回はUnityのモデルとして天球を作成しているので、天球モデルのMeshの表面上を沿うようにXYZ座標で調整すれば、簡単に位置合わせができます。
ボタンだけでなく、画像や動画または3Dモデルを配置することでより多くの情報を持ったコンテンツにすることができます。3Dモデルの影を落としてパノラマに馴染ませたりといった編集もUnityで制作したので簡単に実現できました。

メディアの表示

パノラマ内に、ポスターや掲示板などの画像を表示させる物や、映像を表示するモニターがあれば、そこにぴったりと重なるようにHotspotを設けることで目的に合わせたコンテンツを表示することができます。今回は、パノラマ内の額縁とスクリーンに合わせて表示されるように配置しました。また、対象のパノラマに移動するごとに複数素材の中からランダムで選択して表示させています。
差し替え素材として使用した動画はNHKクリエイティブ・ライブラリーを、画像はメトロポリタン美術館のものを使用しました。

デモ

以上の内容で作成したWebGLコンテンツになります。
表示ブラウザはGoogle Chrome推奨です。

  • マウスのドラッグ操作:カメラの回転
  • ホイール操作:ズームイン/アウト

まとめ

Unityでビルドすると、WebGLコンテンツがパッケージされたBuildフォルダと、それを表示するためのindex.htmlファイルが作成さるので、htmlファイルを置き換えれば自分のWebページにコンテンツを表示できます。また設定次第では、Webページ上のJavaScriptからUnityのScriptを呼び出してWebページのメニューとUnityのコンテンツを連動させたりと、Webページ内のコンテンツとして応用した作り方もできます。
コンテンツをリッチなものにするほど、PC性能によって表示ができないなどの問題も未だありますが、Unityを利用すればより面白いものが作れそうです。