ForgeVision Engineer Blog

フォージビジョン エンジニア ブログ

360°画像をSkyboxに表示するときに継ぎ目を無くす方法

こんにちは!VR事業部の石井です。

今回はUnityでSkyboxに360°画像(全天球画像)を貼ったときに継ぎ目を無くす方法をご紹介します。

バージョン情報など

各種バージョン情報は以下の通りです。

  • Unity 2022.3.16f1

継ぎ目とは?

このように灰色の線が上下の極点に伸びています。
これが継ぎ目です。

以下の手順で継ぎ目を再現できます。

  1. 360°画像をインポートする
  2. マテリアルを作成し、シェーダーを Skybox/panoramic にする
  3. マテリアルのテクスチャに360°画像を適用する
  4. Unity上部のメニューからWindow>Rendering>Lightingを選択し、Lightingウィンドウを開く
  5. LightingウィンドウのEnvironmentで3で作成したマテリアルをSkybox Materialに割り当てる
  6. SceneビューまたはGameビューでX軸マイナスの方向を向く(マテリアルのRotationが0の場合)

原因

ミップマップが原因である可能性が高いです。 docs.unity3d.com

ミップマップの縮小した画像は色を平均化しているため、端の色がぼやけることがあります。
それが継ぎ目となって現れるようです。

解消手順

Skyboxではミップマップのメリットを享受することはないので、ミップマップを削除します。

画像をUnityに事前にインポートする場合

事前にインポートする場合は簡単に解決できます。

  1. Projectウィンドウで360°画像を選択する
  2. Inspectorウィンドウで Generate Mipmaps をオフにする
  3. Applyボタンを押す

これで継ぎ目がなくなります。

画像をランタイムでロードする場合

以下のC#スクリプト(PanoramaImageLoad.cs)でStreaming Assetsから読み込む場合を例に示します。

using System;
using System.Collections;
using System.IO;
using UnityEngine;
using UnityEngine.Networking;
 
public class PanoramaImageLoad : MonoBehaviour
{
    /// <summary>
    /// Skyboxマテリアル
    /// </summary>
    [SerializeField] private Material _material;

    /// <summary>
    /// 360°画像のファイル名
    /// </summary>
    [SerializeField] private string _panoramaImageName;
 
    private void Start()
    {
        StartCoroutine(DownloadTextureFromStreamingAssets(texture => _material.mainTexture = texture));
    }
 
    /// <summary>
    /// StreamingAssetsからテクスチャをダウンロードする
    /// </summary>
    /// <param name="callback">コールバック</param>
    /// <returns></returns>
    private IEnumerator DownloadTextureFromStreamingAssets(Action<Texture> callback)
    {
        var url = Path.Combine(Application.streamingAssetsPath, _panoramaImageName);
 
        using var www = UnityWebRequestTexture.GetTexture(url);
        yield return www.SendWebRequest();
        if (www.result == UnityWebRequest.Result.ConnectionError || www.result == UnityWebRequest.Result.ProtocolError)
        {
            Debug.LogError(www.error);
            yield break;
        }
 
        var downloadedTexture = ((DownloadHandlerTexture) www.downloadHandler).texture;
        if (downloadedTexture == null)
        {
            Debug.LogError(www.downloadHandler.error);
            yield break;
        }
 
        // Texture2Dコンストラクタの第4引数(mipChain)がfalseだと継ぎ目が消える
        var newTexture = new Texture2D(downloadedTexture.width, downloadedTexture.height, TextureFormat.RGB24, false);
        newTexture.SetPixels(downloadedTexture.GetPixels());
        newTexture.Apply();
 
        callback(newTexture);
    }
}
  1. AssetsフォルダにStreamingAssetsフォルダを作成する
  2. StreamingAssetsフォルダに360°画像を保存する
  3. Hierarchyウィンドウで空のオブジェクトを作成する
  4. 空のオブジェクトにPanoramaImageLoad.csをアタッチする
  5. Skyboxマテリアルと360°画像名(ここでは360PanoramaImage.png)を入力する
  6. 実行する

ここで大事なのは以下のテクスチャの作成です。

        // Texture2Dコンストラクタの第4引数(mipChain)がfalseだと継ぎ目が消える
        var newTexture = new Texture2D(downloadedTexture.width, downloadedTexture.height, TextureFormat.RGB24, false);
        newTexture.SetPixels(downloadedTexture.GetPixels());
        newTexture.Apply();

Texture2Dコンストラクタの第4引数(mipChain)がfalseだと、ミップマップなしのテクスチャを生成できます。 docs.unity3d.com

まとめ

空間に継ぎ目があると没入感を阻害する要因になります。
ミップマップは便利な機能ですが不要なときは使わないほうが良いでしょう。
上記で例示したように手間がかからずに継ぎ目は消せるので、ぜひお試しください!

おまけ

この記事で使用した360°画像は筆者が神津島の山で撮影した画像です。
神津島は山登り、釣り、海水浴、温泉、クラフトビールと楽しい要素満載なので、是非足を運んでみてください!