Unityの基本機能だけを使ってSceneのキューブマップ(全天球画像)を作る

  • 24
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

今までは無料のアセットを使ってやっていたのですが、

Camera.RenderToCubemap
機能:カメラからキューブマップにレンダリングします。

こんな便利な機能があったなんて知らなかった!
そして使ってみて超便利だったので共有します。

キューブマップにしたいシーンを作成

キューブマップを作るのに「まずキューブマップを用意します」では本末転倒になってしまうので、Sphereに全天球画像を貼り付けたりして作成します。
スクリーンショット 2016-04-10 20.39.04.png

ダミーのキューブマップ用テクスチャを用意

適当なテクスチャをプロジェクトにドロップします。
このテクスチャは後でキューブマップを作る際に上書きされてしまうので、消えてもいいものを使ってください。
* 追記:cubemapは、後でセーブされたものに差し替える必要があります。

ダミーのキューブマップ用テクスチャの設定を変更

ダミーのキューブマップ用テクスチャを選択し、Inspectorから設定を変更します。

  • Texture Type を Cubemap に変更

CubeMapマテリアルを用意

Create > Material でマテリアルを作成し、Shader > Skybox > 6Sided を選択、テクスチャにダミーのキューブマップテクスチャを指定します。

エディタースクリプトを用意

Editorフォルダを作成し、その中にこちらのUnityサンプルスクリプトを作成します。

  • 追記:サンプルのままだと保存されないので、こちらを参考にスクリプトを修正しました(天地逆に出力されていたのを修正)。
// // http://docs.unity3d.com/ja/current/ScriptReference/Camera.RenderToCubemap.html
// http://stackoverflow.com/questions/34458622/unity-save-cubemap-to-one-circle-image
using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Linq;
using System.IO;

public class RenderCubemapWizard : ScriptableWizard {

    public Camera camera;
    public Cubemap cubemap;

    void OnWizardUpdate () {
        string helpString = "Select transform to render from and cubemap to render into";
        bool isValid = (camera != null) && (cubemap != null);
    }

    void OnWizardCreate () {
        if (camera == null) {
            camera = Camera.main;
        }
        // render into cubemap      
        camera.RenderToCubemap( cubemap );
        cubemap.Apply ();
        ConvertToPng ();
    }

    [MenuItem("GameObject/Render into Cubemap")]
    static void RenderCubemap () {
        ScriptableWizard.DisplayWizard<RenderCubemapWizard>(
            "Render cubemap", "Render!");
    }

    void ConvertToPng()
    {
        Debug.Log(Application.dataPath + "/" +cubemap.name +"_PositiveX.png");
        var tex = new Texture2D (cubemap.width, cubemap.height, TextureFormat.RGB24, false);
        var bytes = getPlanePixels(tex,CubemapFace.PositiveX);      
        File.WriteAllBytes(Application.dataPath + "/"  + cubemap.name +"_PositiveX.png", bytes);       

        bytes = getPlanePixels(tex,CubemapFace.NegativeX);     
        File.WriteAllBytes(Application.dataPath + "/"  + cubemap.name +"_NegativeX.png", bytes);       

        bytes = getPlanePixels(tex,CubemapFace.PositiveY);     
        File.WriteAllBytes(Application.dataPath + "/"  + cubemap.name +"_PositiveY.png", bytes);       

        bytes = getPlanePixels(tex,CubemapFace.NegativeY);     
        File.WriteAllBytes(Application.dataPath + "/"  + cubemap.name +"_NegativeY.png", bytes);       

        bytes = getPlanePixels(tex,CubemapFace.PositiveZ);     
        File.WriteAllBytes(Application.dataPath + "/"  + cubemap.name +"_PositiveZ.png", bytes);       

        bytes = getPlanePixels(tex,CubemapFace.NegativeZ);     
        File.WriteAllBytes(Application.dataPath + "/"  + cubemap.name   +"_NegativeZ.png", bytes);       
        DestroyImmediate(tex);

    }

    byte[] getPlanePixels(Texture2D _tex, CubemapFace _face){
        Texture2D tmpTex = new Texture2D (cubemap.width, cubemap.height, TextureFormat.RGB24, false);
        tmpTex.SetPixels(cubemap.GetPixels(_face));
        Color[] vline;
        for (int x = 0; x < cubemap.width; ++x) {
            vline = tmpTex.GetPixels (x, 0, 1, cubemap.height);
            _tex.SetPixels (x, 0, 1, cubemap.height,vline.Reverse().ToArray());
        }
        return _tex.EncodeToPNG();     
    }

}

スクリプトを実行する

GameObjectメニューから Render into Cubemap を実行します。
スクリーンショット 2016-04-10 20.43.00.png

ダイアログウインドウが現れるので、
Render From Position にカメラを、Cubemapにダミーのキューブマップ用テクスチャを指定して実行します
スクリーンショット 2016-04-10 20.43.24.png

完成!

  • 追記:最終的に出力された6枚の画像をキューブマップのそれぞれの面に設定して完成です。
  • スクリーンショット 2016-04-11 22.51.20.png

  • Window > Lighting > Skyboxでキューブマップマテリアルを指定します。

スクリーンショット 2016-04-10 20.45.11.png

スクリーンショット 2016-04-10 20.46.39.png