Skip to content

Instantly share code, notes, and snippets.

@RemyUnity
Created April 9, 2020 09:03
Show Gist options
  • Star 16 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save RemyUnity/856f85bfe3ec7a8d845406415b426f87 to your computer and use it in GitHub Desktop.
Save RemyUnity/856f85bfe3ec7a8d845406415b426f87 to your computer and use it in GitHub Desktop.
Unity utility to convert 6 texture to a single cubemap texture
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.Linq;
using System.IO;
public class CubemapTextureBuilder : EditorWindow
{
[MenuItem("Tools/Cubemap Builder")]
public static void OpenWindow()
{
GetWindow<CubemapTextureBuilder>();
}
Texture2D[] textures = new Texture2D[6];
string[] labels = new string[] {
"Right", "Left",
"Top", "Bottom",
"Front", "Back"
};
TextureFormat[] HDRFormats = new TextureFormat[] {
TextureFormat.ASTC_HDR_10x10 ,
TextureFormat.ASTC_HDR_12x12 ,
TextureFormat.ASTC_HDR_4x4 ,
TextureFormat.ASTC_HDR_5x5 ,
TextureFormat.ASTC_HDR_6x6 ,
TextureFormat.ASTC_HDR_8x8 ,
TextureFormat.BC6H ,
TextureFormat.RGBAFloat ,
TextureFormat.RGBAHalf
};
Vector2Int[] placementRects = new Vector2Int[]
{
new Vector2Int(2, 1),
new Vector2Int(0, 1),
new Vector2Int(1, 2),
new Vector2Int(1, 0),
new Vector2Int(1, 1),
new Vector2Int(3, 1),
};
private void OnGUI()
{
for (int i=0; i<6; i++)
{
textures[i] = EditorGUILayout.ObjectField(labels[i], textures[i], typeof(Texture2D), false) as Texture2D;
}
if (GUILayout.Button("Build Cubemap"))
{
// Missing Texture
if (textures.Any( t => t == null ) )
{
EditorUtility.DisplayDialog("Cubemap Builder Error", "One or more texture is missing.", "Ok");
return;
}
// Get size
var size = textures[0].width;
// Not all of the same size or square
if ( textures.Any( t => (t.width!=size) || (t.height!=size) ) )
{
EditorUtility.DisplayDialog("Cubemap Builder Error", "All the textures need to be the same size and square.", "Ok");
return;
}
var isHDR = HDRFormats.Any(f => f == textures[0].format);
var texturePaths = textures.Select(t => AssetDatabase.GetAssetPath(t)).ToArray();
// Should be ok, ask for the file path.
var path = EditorUtility.SaveFilePanel("Save Cubemap", Path.GetDirectoryName(texturePaths[0]), "Cubemap", isHDR ? "exr" : "png");
if (string.IsNullOrEmpty(path)) return;
// Save the readable flag to restore it afterwards
var readableFlags = textures.Select(t => t.isReadable).ToArray();
// Get the importer and mark the textures as readable
var importers = texturePaths.Select(p => TextureImporter.GetAtPath(p) as TextureImporter).ToArray();
foreach (var importer in importers)
{
importer.isReadable = true;
}
AssetDatabase.Refresh();
foreach( var p in texturePaths)
{
AssetDatabase.ImportAsset(p);
}
// Build the cubemap texture
var cubeTexture = new Texture2D(size * 4, size * 3, isHDR ? TextureFormat.RGBAFloat : TextureFormat.RGBA32, false);
for (int i=0; i<6; i++)
{
cubeTexture.SetPixels(placementRects[i].x * size, placementRects[i].y * size, size, size, textures[i].GetPixels(0));
}
cubeTexture.Apply(false);
// Save the texture to the specified path, and destroy the temporary object
var bytes = isHDR ? cubeTexture.EncodeToEXR() : cubeTexture.EncodeToPNG();
File.WriteAllBytes(path, bytes);
DestroyImmediate(cubeTexture);
// Reset the read flags, and reimport everything
for (var i = 0; i<6; i++)
{
importers[i].isReadable = readableFlags[i];
}
path = path.Remove(0, Application.dataPath.Length-6);
AssetDatabase.ImportAsset(path);
var cubeImporter = AssetImporter.GetAtPath(path) as TextureImporter;
cubeImporter.textureShape = TextureImporterShape.TextureCube;
cubeImporter.sRGBTexture = false;
cubeImporter.generateCubemap = TextureImporterGenerateCubemap.FullCubemap;
foreach (var p in texturePaths)
{
AssetDatabase.ImportAsset(p);
}
AssetDatabase.ImportAsset(path);
AssetDatabase.Refresh();
}
}
}
@RemyUnity
Copy link
Author

RemyUnity commented Apr 9, 2020

Usage

  1. Import the script in your project
  2. Open the window in Tools/Cubemap Builder
    image
  3. Place your maps, and click Build !
    image

Limitations

  • All the source maps need to be square and have the same size (at least, in the texture importer settings).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment