We've generated a cubemap using the editor script sample found in the Camera.RenderToCubemap documentation. We'd like to edit the faces by hand but can't find a way to access the individual face textures that make up the Cubemap texture. Is it possible to do so? If so, how?
In case somebody needs this, here is how to extract all the faces in png format, in the asset folder. Copy this script in an "editor" folder in a project "asset" folder
import System.IO;
class SaveCubeMapToPngWizard extends ScriptableWizard {
var cubemap : Cubemap;
function OnWizardUpdate () {
helpString = "Select cubemap to save to individual png";
isValid = (cubemap != null);
}
function OnWizardCreate ()
{
var width = cubemap.width;
var height = cubemap.height;
Debug.Log(Application.dataPath + "/" +cubemap.name +"_PositiveX.png");
var tex = new Texture2D (width, height, TextureFormat.RGB24, false);
// Read screen contents into the texture
tex.SetPixels(cubemap.GetPixels(CubemapFace.PositiveX));
// Encode texture into PNG
var bytes = tex.EncodeToPNG();
File.WriteAllBytes(Application.dataPath + "/" + cubemap.name +"_PositiveX.png", bytes);
tex.SetPixels(cubemap.GetPixels(CubemapFace.NegativeX));
bytes = tex.EncodeToPNG();
File.WriteAllBytes(Application.dataPath + "/" + cubemap.name +"_NegativeX.png", bytes);
tex.SetPixels(cubemap.GetPixels(CubemapFace.PositiveY));
bytes = tex.EncodeToPNG();
File.WriteAllBytes(Application.dataPath + "/" + cubemap.name +"_PositiveY.png", bytes);
tex.SetPixels(cubemap.GetPixels(CubemapFace.NegativeY));
bytes = tex.EncodeToPNG();
File.WriteAllBytes(Application.dataPath + "/" + cubemap.name +"_NegativeY.png", bytes);
tex.SetPixels(cubemap.GetPixels(CubemapFace.PositiveZ));
bytes = tex.EncodeToPNG();
File.WriteAllBytes(Application.dataPath + "/" + cubemap.name +"_PositiveZ.png", bytes);
tex.SetPixels(cubemap.GetPixels(CubemapFace.NegativeZ));
bytes = tex.EncodeToPNG();
File.WriteAllBytes(Application.dataPath + "/" + cubemap.name +"_NegativeZ.png", bytes);
DestroyImmediate(tex);
}
@MenuItem("GameObject/Save CubeMap To Png ")
static function SaveCubeMapToPng ()
{
ScriptableWizard.DisplayWizard(
"Save CubeMap To Png", SaveCubeMapToPngWizard , "Save");
}
}
take a look at cubemap class and it's setpixels method here you can get pixels with these methods and set them on a Texture2D or do any other thing that you want with it.
Finally got this working. The above code didn’t work for me. Appears the problem is with the first line “import http://System.IO;”. I’m not much of a coder, but this had to be wrong since any “//” automatically comments out anything that follows it. Anyway, here’s the full script that worked for me. Hope it helps someone.
import System;
import System.IO;
class SaveCubeMapToPngWizard extends ScriptableWizard {
var cubemap : Cubemap;
function OnWizardUpdate () {
helpString = "Select cubemap to save to individual png";
isValid = (cubemap != null);
}
function OnWizardCreate ()
{
var width = cubemap.width;
var height = cubemap.height;
Debug.Log(Application.dataPath + "/" +cubemap.name +"_PositiveX.png");
var tex = new Texture2D (width, height, TextureFormat.RGB24, false);
// Read screen contents into the texture
tex.SetPixels(cubemap.GetPixels(CubemapFace.PositiveX));
// Encode texture into PNG
var bytes = tex.EncodeToPNG();
File.WriteAllBytes(Application.dataPath + "/" + cubemap.name +"_PositiveX.png", bytes);
tex.SetPixels(cubemap.GetPixels(CubemapFace.NegativeX));
bytes = tex.EncodeToPNG();
File.WriteAllBytes(Application.dataPath + "/" + cubemap.name +"_NegativeX.png", bytes);
tex.SetPixels(cubemap.GetPixels(CubemapFace.PositiveY));
bytes = tex.EncodeToPNG();
File.WriteAllBytes(Application.dataPath + "/" + cubemap.name +"_PositiveY.png", bytes);
tex.SetPixels(cubemap.GetPixels(CubemapFace.NegativeY));
bytes = tex.EncodeToPNG();
File.WriteAllBytes(Application.dataPath + "/" + cubemap.name +"_NegativeY.png", bytes);
tex.SetPixels(cubemap.GetPixels(CubemapFace.PositiveZ));
bytes = tex.EncodeToPNG();
File.WriteAllBytes(Application.dataPath + "/" + cubemap.name +"_PositiveZ.png", bytes);
tex.SetPixels(cubemap.GetPixels(CubemapFace.NegativeZ));
bytes = tex.EncodeToPNG();
File.WriteAllBytes(Application.dataPath + "/" + cubemap.name +"_NegativeZ.png", bytes);
DestroyImmediate(tex);
}
@MenuItem("GameObject/Save CubeMap To Png ")
static function SaveCubeMapToPng ()
{
ScriptableWizard.DisplayWizard(
"Save CubeMap To Png", SaveCubeMapToPngWizard , "Save");
}
}
Many thanks for the script !
But some noobs (including me) have problems with this “not so good” documentation.
I try to complete the docu:
- Greate a Javascript with the name “SaveCubeMapToPngWizard” in a Editor folder in Assets (how described above).
- Copy the script, but including the first lines “import…”, “class SaveCube…” and the brace at the end of the script (in the green area).
- The first line should be: “import System.IO;” and NOT “import http://System.IO;”
I hope it helps someone !
Regards - MS
On #3, MS-3D meant to say: “import System.IO;” and NOT “import http://System.IO;”
To be clear, the first line should be:
import System.IO
If you build a Win32 build you can PIX the project and then steal the cubemap textures this way.
I just did this, as we lost our original textures.
If anyone’s interested, here’s a C# version of this code. Also, I don’t know if anyone is also having this issue but all of the output textures were rotated 180 degrees. I got a piece of code thanks to Jessy on the unity forum that resolves this issue and flips the images correctly.
using UnityEngine;
using UnityEditor;
using System;
using System.Linq;
using System.IO;
using System.Collections;
public class SaveCubemapToPNG : ScriptableWizard
{
#region private members
public Cubemap m_cubemap = null;
#endregion
#region wizard methods.
[MenuItem( "Save CubeMap To Png" )]
static void SaveCubeMapToPng()
{
ScriptableWizard.DisplayWizard<SaveCubemapToPNG>( "Save CubeMap To Png", "Save" );
}
public void OnWizardUpdate()
{
helpString = "Select cubemap to save to individual .png";
if( Selection.activeObject is Cubemap && m_cubemap == null )
m_cubemap = Selection.activeObject as Cubemap;
isValid = ( m_cubemap != null );
}
public void OnWizardCreate()
{
Debug.Log( "Exporting to ... " + Application.dataPath + "/" + m_cubemap.name + "_????.png" );
int width = m_cubemap.width;
int height = m_cubemap.height;
Texture2D tex = new Texture2D( width, height, TextureFormat.RGB24, false );
byte[] bytes = null;
// Iterate through 6 faces.
for( int i = 0; i < 6; ++i )
{
// Encode texture into PNG.
tex.SetPixels( m_cubemap.GetPixels( (CubemapFace)i ) );
// Flip pixels on both axis (they are rotated for some reason).
FlipPixels( tex, true, true );
// Save as PNG.
File.WriteAllBytes( Application.dataPath + "/" + m_cubemap.name + "_" + ( (CubemapFace)i ).ToString() + ".png", tex.EncodeToPNG() );
}
DestroyImmediate(tex);
}
public static void FlipPixels( Texture2D texture, bool flipX, bool flipY )
{
Color32[] originalPixels = texture.GetPixels32();
var flippedPixels = Enumerable.Range( 0, texture.width * texture.height ).Select( index =>
{
int x = index % texture.width;
int y = index / texture.width;
if( flipX )
x = texture.width - 1 - x;
if( flipY )
y = texture.height - 1 - y;
return originalPixels[y * texture.width + x];
}
);
texture.SetPixels32( flippedPixels.ToArray() );
texture.Apply();
}
#endregion
}