之前美術mm想做一個唯美天空盒,將某相機在球形模型中的視野渲染到cubemap上,然后賦給天空盒.她想再次編輯cubemap中某一面的貼圖,無奈無法獲得這些貼圖.機會來了!!
自己寫了個工具類,可以渲染,可以保存某一張圖片,也可以一次性全部導出這些貼圖,問題解決.
/// <summary>
/// 將某相機所看渲染到CubeMap,並選擇性的保存此CubeMap貼圖
/// </summary>
using UnityEngine;
using UnityEditor;
/// <summary>
/// CubeMap 六個面
/// </summary>
enum CubeMapFaces
{
right = 0,
left,
top,
bottom,
front,
back
}
public class RenderToCubeMapTool : EditorWindow
{
[MenuItem ("Window/CubeMapTool %m")]
static void AddWindow ()
{
//創建窗口
Rect wr = new Rect (0, 0, 100, 100);
RenderToCubeMapTool window = (RenderToCubeMapTool)EditorWindow.GetWindowWithRect (typeof(RenderToCubeMapTool), wr, false, "CubeMapTool");
window.Show ();
}
private Camera renderCamera;
private Cubemap renderCubeMap;
CubeMapFaces faces;
private CubemapFace offcialFaces;
void OnGUI ()
{
GUILayout.BeginVertical ();
GUILayout.Space (10f);
renderCamera = EditorGUILayout.ObjectField ("渲染相機", renderCamera, typeof(Camera), true) as Camera;
GUILayout.Space (10f);
renderCubeMap = EditorGUILayout.ObjectField ("CubeMap", renderCubeMap, typeof(Cubemap), false) as Cubemap;
GUILayout.Space (10f);
if (GUILayout.Button ("渲染") && CheckCamAndCubeMap ()) {
if (renderCamera.RenderToCubemap (renderCubeMap)) {
Debug.LogWarningFormat ("渲染完成!");
CheckSingleCubeMapFaces ();
} else {
Debug.LogWarningFormat ("渲染失敗!");
}
}
GUILayout.Space (10f);
GUILayout.BeginHorizontal ();
faces = (CubeMapFaces)EditorGUILayout.EnumPopup ("保存CubeMap某個面", faces);
if (GUILayout.Button ("保存") && CheckCamAndCubeMap ()) {
CheckSingleCubeMapFaces ();
SaveSingelTexture ();
}
GUILayout.EndHorizontal ();
GUILayout.Space (10f);
if (GUILayout.Button ("全部保存")) {
SaveMultiTexture ();
}
GUILayout.Space (10f);
EditorGUILayout.HelpBox ("請務必確認要渲染的CubeMap可以讀寫!\n (屬性面板中的 Readable 勾上即可)", MessageType.Warning);
GUILayout.EndVertical ();
}
bool CheckCamAndCubeMap ()
{
if (renderCamera == null || renderCubeMap == null) {
Debug.LogError ("渲染相機和CubeMap不能為空!");
return false;
} else {
return true;
}
}
#region 檢測單張保存時對應cubemap面
/// <summary>
/// Checks the cube map faces.
/// </summary>
void CheckSingleCubeMapFaces ()
{
switch (faces) {
case CubeMapFaces.right:
offcialFaces = CubemapFace.PositiveX;
break;
case CubeMapFaces.left:
offcialFaces = CubemapFace.NegativeX;
break;
case CubeMapFaces.top:
offcialFaces = CubemapFace.PositiveY;
break;
case CubeMapFaces.bottom:
offcialFaces = CubemapFace.NegativeY;
break;
case CubeMapFaces.front:
offcialFaces = CubemapFace.PositiveZ;
break;
case CubeMapFaces.back:
offcialFaces = CubemapFace.NegativeZ;
break;
}
}
#endregion
#region 檢測多張保存時對應的cubemap面
/// <summary>
/// Checks the multi cube map faces.
/// </summary>
void CheckMultiCubeMapFaces (int index)
{
switch (index) {
case (int)CubeMapFaces.right:
offcialFaces = CubemapFace.PositiveX;
break;
case (int)CubeMapFaces.left:
offcialFaces = CubemapFace.NegativeX;
break;
case (int)CubeMapFaces.top:
offcialFaces = CubemapFace.PositiveY;
break;
case (int)CubeMapFaces.bottom:
offcialFaces = CubemapFace.NegativeY;
break;
case (int)CubeMapFaces.front:
offcialFaces = CubemapFace.PositiveZ;
break;
case (int)CubeMapFaces.back:
offcialFaces = CubemapFace.NegativeZ;
break;
}
}
#endregion
#region 由cubemap 朝向反推前后左右方向
string CheckDir ()
{
string name = "TestTexture";
switch (offcialFaces) {
case CubemapFace.PositiveX:
name = "right";
break;
case CubemapFace.NegativeX:
name = "left";
break;
case CubemapFace.PositiveY:
name = "top";
break;
case CubemapFace.NegativeY:
name = "bottom";
break;
case CubemapFace.PositiveZ:
name = "front";
break;
case CubemapFace.NegativeZ:
name = "back";
break;
}
return name;
}
#endregion
#region 保存單張圖片
/// <summary>
///保存單張圖片
/// </summary>
private void SaveSingelTexture ()
{
Texture2D screenShot = new Texture2D (renderCubeMap.width,
renderCubeMap.height,
TextureFormat.ARGB32,
false);
for (int i = 0; i< renderCubeMap.width; i++) {
for (int j = 0; j < renderCubeMap.height; j++) {
screenShot.SetPixel (i, j, renderCubeMap.GetPixel (offcialFaces, renderCubeMap.width - i, renderCubeMap.height - j));
}
}
screenShot.Apply ();
byte[] bytes = screenShot.EncodeToPNG ();
string path = EditorUtility.SaveFilePanel ("圖片保存", Application.dataPath, faces.ToString (), "png");
System.IO.File.WriteAllBytes (path, bytes);
AssetDatabase.Refresh ();
}
#endregion
#region 保存多張圖片
/// <summary>
///保存單張圖片
/// </summary>
private void SaveMultiTexture ()
{
Texture2D screenShot;
string path = Application.dataPath + "/" + "CubeMapTextures/";
for (int k = 0; k< 6; k++) {
screenShot = new Texture2D (renderCubeMap.width,
renderCubeMap.height,
TextureFormat.ARGB32,
false);
CheckMultiCubeMapFaces (k);
for (int i = 0; i< renderCubeMap.width; i++) {
for (int j = 0; j < renderCubeMap.height; j++) {
screenShot.SetPixel (i, j, renderCubeMap.GetPixel (offcialFaces, renderCubeMap.width - i, renderCubeMap.height - j));
}
}
screenShot.Apply ();
byte[] bytes = screenShot.EncodeToPNG ();
if (!System.IO.Directory.Exists (path)) {
System.IO.Directory.CreateDirectory (path);
}
System.IO.File.WriteAllBytes (path + CheckDir () + ".png", bytes);
}
AssetDatabase.Refresh ();
Debug.LogWarning ("六張圖片已經保存在 " + path + " 下!");
}
#endregion
void OnInspectorUpdate ()
{
this.Repaint ();
}
void OnFocus ()
{
//Debug.Log("當窗口獲得焦點時調用一次");
}
void OnLostFocus ()
{
//Debug.Log("當窗口丟失焦點時調用一次");
Caching.CleanCache ();
}
}
注意
1 cubemap 需保持可讀寫狀態(勾選readable)
2 cubemap尺寸較大時可能需要稍稍等待下(和mm喝咖啡的時間來了 ^^)
