序:開始決定寫東西,內容不限,關于工作內容的,關于自己業(yè)余研究的,關于生活的...因為只有寫下來,思路才會更清晰,印象才會更深刻,更可以Share。ps:我是個女碼農(nóng),現(xiàn)在從事Unity游戲、應用的開發(fā)。不要試圖問一個女生為什么選擇這個職業(yè),做了就是做了,并且要做好。
Ok,well這次簡短點,我最近碰到一個關于Unity截屏的問題。用過的人很快會想到兩種截屏的方式:
Application.CaptureScreenshot(string file name),這會截取當前屏幕保存為png格式,存放在Application.dataPath(PC/Mac),Application.persistantDataPath(移動設備)。如果需要獲取圖片用作顯示,或保存在系統(tǒng)照片集下,就需要通過www的方式讀取后再做處理,不是很方便。
Texture2D.ReadPixels(Rect source, int destX, int destY, bool recaculateMipmaps=true), 這會讀取指定區(qū)域內的屏幕像素至一張texture中,用于UI顯示、保存等。相比方法一更方便直觀。我們大多數(shù)都是采用該方法。
但是,最近碰到的問題是,在一些低端性能差點的Android設備上,用以上兩種方式截出來的圖是黑色(像素值全是0),用了coroutine方式WaitEndOfFrame,試圖修改Texture2D的format、size,放在Monobehavior.OnPostRender()中...試過想到的各種方法均無效,也沒有報warning、error。就想到嘗試用第三種方式來實現(xiàn):RenderTexture。
通過將Camera的內容渲染到一張RT中,然后用Texture2D.ReadPixels()方法從當前的RT中讀取,結果可行!代碼如下:
public static Texture2D CaptureCamera(Rect rect, params Camera[] cameras)
{
RenderTexture rt = new RenderTexture ((int)Screen.width, (int)Screen.height, 24);
//臨時設置相關相機的targetTexture為rt, 并手動渲染相關相機
for (int i=0; i<cameras.Length; i++)
{
if(cameras[i] != null)
{
cameras[i].targetTexture=rt;
cameras[i].Render();
}
}
//激活這個rt, 并從中中讀取像素。
RenderTexture.active = rt;
Texture2D screenShot = new Texture2D((int)rect.width, (int)rect.height, TextureFormat.RGB24, false);
screenShot.ReadPixels(rect, 0, 0); //注:這個時候,它是從RenderTexture.active中讀取像素
screenShot.Apply();
//重置相關參數(shù),以使用camera繼續(xù)在屏幕上顯示
for(int i=0; i<cameras.Length; i++)
{
if(cameras[i] !=null)
cameras[i].targetTexture = null;
}
RenderTexture.active = null;
GameObject.Destroy(rt);
return screenShot;
}
分析原因,有如下推斷:Android渲染采用了雙緩沖,而前兩種方式是從繪制到當前屏幕的framebuffer中讀數(shù)據(jù),當設備運行慢時,在Unity調用接口所讀到的數(shù)據(jù)是從正在寫入的framebuffer里面的,還沒有swap送入屏幕顯示,所以讀到的像素值為0。采用RenderTexture方式將Camera繪制內容寫入texture中,從該texture中讀取數(shù)據(jù)能夠解決上述問題,確保數(shù)據(jù)有效。
這是我的一個推斷,可能是其他原因,搜索以及debug無果,希望以后的開發(fā)中能徹底知曉原因。