unity的环境捕捉器

Author Avatar
Kanglai Qian 11月 08, 2014

一下午随手写了一个环境捕捉器,山寨了一下unreal的scene capture cube。结果后来发现unity3d pro自带了一个Camera.RenderToCubemap函数真是哈哈哈哈啊……

实现的思路很简单,在任意GameObject上挂载脚本之后,会自动生成一个摄像机对象。设置一下纹理大小和cubemap文件名之后,点Build Cubemap就会生成一个cubemap在关卡文件同级目录下。

Save Image勾上之后会同步导出6个贴图文件;Preview如果勾上,则会在Game界面显示、否则会直接弄到render texture上。

生成的cubemap文件。

如果需要特殊效果,可以在这个GameObject上贴上各种后处理脚本并预览。反正这个东西也写的很简单,就纯当练手用了……学习了一下纹理抓取、保存、inspector GUI设置等,顺便发现了纹理的y真是麻烦啊。

CubemapCaptureEditor.csview raw
using UnityEngine;
using UnityEditor;
using System.Collections;

[CustomEditor(typeof(CubemapCaptureScript))]
public class CubemapCaptureEditor : Editor {
void OnEnable() {
CubemapCaptureScript myScript = (CubemapCaptureScript)target;
myScript.Setup ();
}

void OnDisable() {
CubemapCaptureScript myScript = (CubemapCaptureScript)target;
myScript.Cleanup ();
}

public override void OnInspectorGUI()
{
DrawDefaultInspector();

CubemapCaptureScript myScript = (CubemapCaptureScript)target;
myScript.TextureSize = EditorGUILayout.IntField ("Texture Size", myScript.TextureSize);
myScript.PreviewCamera = EditorGUILayout.Toggle ("Preview", myScript.PreviewCamera);
if(GUILayout.Button("Build Cubemap"))
{
myScript.BuildCubemap();
}
}
}
CubemapCaptureScript.csview raw
using UnityEngine;
using UnityEditor;
using System.Collections;

public class CubemapCaptureScript : MonoBehaviour {
public string filename = "mycubemap";
public bool PreviewCamera {
get { return m_PreviewCamera; }
set {
if(m_PreviewCamera != value) {
m_PreviewCamera = value;
Setup();
}
}
}
private bool m_PreviewCamera = false;
public int TextureSize {
get { return m_TextureSize; }
set {
int size = Mathf.NextPowerOfTwo(value);
if(m_TextureSize != size) {
m_TextureSize = size;
Setup();
}
}
}
private int m_TextureSize = 16;
private int m_LastTextureSize = -1;
public bool m_saveImage = false;
private RenderTexture m_RenderTexture = null;

private RenderTexture BuildRenderTexture() {
RenderTexture texture = new RenderTexture( m_TextureSize, m_TextureSize, 16 );
texture.name = "__CubemapRenderTexture" + GetInstanceID();
texture.isPowerOfTwo = true;
texture.hideFlags = HideFlags.DontSave;
return texture;
}

public void Setup() {
if (m_RenderTexture != null && m_LastTextureSize != m_TextureSize) {
DestroyImmediate( m_RenderTexture );
m_RenderTexture = null;
}

if (m_RenderTexture == null) {
m_RenderTexture = new RenderTexture( m_TextureSize, m_TextureSize, 16 , RenderTextureFormat.ARGB32);
m_RenderTexture.name = "__CubemapRenderTexture" + GetInstanceID();
m_RenderTexture.isPowerOfTwo = true;
m_RenderTexture.hideFlags = HideFlags.DontSave;
m_LastTextureSize = m_TextureSize;
}

if (camera == null) {
gameObject.AddComponent<Camera>();
}
camera.targetTexture = m_PreviewCamera?null:m_RenderTexture;
}
public void Cleanup() {
if (m_RenderTexture != null) {
DestroyImmediate (m_RenderTexture);
m_RenderTexture = null;
}
m_LastTextureSize = -1;
}

public void SaveRenderTexture( RenderTexture texture, Cubemap cube, CubemapFace face, bool flipX = false, bool flipY = true ) {
RenderTexture.active = texture;
// read render target
Texture2D texture_ = new Texture2D(m_TextureSize, m_TextureSize, TextureFormat.ARGB32, false);
texture_.ReadPixels( new Rect(0, 0, m_TextureSize, m_TextureSize), 0, 0);
texture_.Apply ();
// flip
if (flipY) {
for (int x = 0; x < m_TextureSize; x++) {
for (int y1 = 0, y2 = m_TextureSize-1; y1 < y2; y1++, y2--) {
Color t1 = texture_.GetPixel (x, y1);
texture_.SetPixel (x, y1, texture_.GetPixel (x, y2));
texture_.SetPixel (x, y2, t1);
}
}
}
texture_.Apply ();
if (flipX) {
for (int x1 = 0, x2 = m_TextureSize-1; x1 < x2; x1++, x2--) {
for (int y = 0; y < m_TextureSize; y++) {
Color t1 = texture_.GetPixel (x1, y);
texture_.SetPixel (x1, y, texture_.GetPixel (x2, y));
texture_.SetPixel (x2, y, t1);
}
}
}
texture_.Apply ();
if (m_saveImage) {
byte[] bytes = texture_.EncodeToPNG();
string[] path_ = EditorApplication.currentScene.Split(char.Parse("/"));
path_[path_.Length -1] = filename+"_"+face.ToString()+".png";
System.IO.File.WriteAllBytes(string.Join("/", path_), bytes);
}
// save to cubemap
cube.SetPixels (texture_.GetPixels (), face);
cube.Apply ();
DestroyImmediate(texture_);

RenderTexture.active = null;
}

public void BuildCubemap() {
Setup ();
Cubemap cube = new Cubemap (m_TextureSize, TextureFormat.ARGB32, false);

// OnWillRenderObject
camera.ResetWorldToCameraMatrix ();
camera.targetTexture = m_RenderTexture;

Quaternion oldRotation = transform.rotation;
// get 6 directions
camera.ResetProjectionMatrix ();
camera.Render();
SaveRenderTexture (m_RenderTexture, cube, CubemapFace.PositiveZ);

transform.Rotate (Vector3.up * 90);
camera.ResetProjectionMatrix ();
camera.Render();
SaveRenderTexture (m_RenderTexture, cube, CubemapFace.PositiveX);

transform.Rotate (Vector3.up * 90);
camera.ResetProjectionMatrix ();
camera.Render();
SaveRenderTexture (m_RenderTexture, cube, CubemapFace.NegativeZ);

transform.Rotate (Vector3.up * 90);
camera.ResetProjectionMatrix ();
camera.Render();
SaveRenderTexture (m_RenderTexture, cube, CubemapFace.NegativeX);

transform.rotation = oldRotation;
transform.Rotate (Vector3.right * 90);
camera.ResetProjectionMatrix ();
camera.Render();
SaveRenderTexture (m_RenderTexture, cube, CubemapFace.NegativeY);

transform.Rotate (Vector3.right * -180);
camera.ResetProjectionMatrix ();
camera.Render();
SaveRenderTexture (m_RenderTexture, cube, CubemapFace.PositiveY);

// restore
transform.rotation = oldRotation;
camera.targetTexture = m_PreviewCamera?null:m_RenderTexture;

//save cubemap
string[] path_ = EditorApplication.currentScene.Split(char.Parse("/"));
path_[path_.Length -1] = filename+".cubemap";
AssetDatabase.CreateAsset(cube, string.Join("/",path_));
}
}

ps. unity 5.x 貌似直接提供一个反射捕捉器