![](/img/trans.png)
[英]Performance boost for glReadPixels in Android by OpenGL ES 3.0
[英]OpenGL ES - glReadPixels
我正在使用glReadPixels截取屏幕截圖,以在兩個圖像之間執行“交叉”效果。
在Marmalade SDK模擬器上,屏幕截圖很好,“交叉”效果很有效:
但是,這是它在iOS和Android設備上的外觀 - 已損壞:
(來源: eikona.info )
我總是將屏幕視為RGBA 1字節/通道,因為文檔說它總是被接受。
以下是用於截屏的代碼:
uint8* Gfx::ScreenshotBuffer(int& deviceWidth, int& deviceHeight, int& dataLength) {
/// width/height
deviceWidth = IwGxGetDeviceWidth();
deviceHeight = IwGxGetDeviceHeight();
int rowLength = deviceWidth * 4; /// data always returned by GL as RGBA, 1 byte/each
dataLength = rowLength * deviceHeight;
// set the target framebuffer to read
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
uint8* buffer = new uint8[dataLength];
glReadPixels(0, 0, deviceWidth, deviceHeight, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
return buffer;
}
void Gfx::ScreenshotImage(CIwImage* img, uint8*& pbuffer) {
int deviceWidth, deviceHeight, dataLength;
pbuffer = ScreenshotBuffer(deviceWidth, deviceHeight, dataLength);
img->SetFormat(CIwImage::ABGR_8888);
img->SetWidth(deviceWidth);
img->SetHeight(deviceHeight);
img->SetBuffers(pbuffer, dataLength, 0, 0);
}
這是一個驅動程序錯誤。 就那么簡單。
驅動程序在視頻內存中的表面間距錯誤。 您可以在上面的行中清楚地看到這一點。 此外,您在圖像下部看到的垃圾是驅動程序認為存儲圖像的存儲器,但存在不同的數據。 可能是紋理/頂點數據。
對不起,我知道無法解決這個問題。 您可以通過不同的表面格式或啟用/禁用多重采樣獲得更好的運氣。
最后,它缺乏記憶力。 “new uint8 [dataLength];” 從來沒有返回一個存在的指針,因此整個過程都被破壞了。
TomA,你清理緩沖區的想法實際上幫助我解決了這個問題。 謝謝。
我不知道你正在使用的android或SDK,但是當我拍攝截圖時,我必須使緩沖區的大小與下一個POT紋理相同,如下所示:
int x = NextPot((int)screenSize.x*retina);
int y = NextPot((int)screenSize.y*retina);
void *buffer = malloc( x * y * 4 );
glReadPixels(0,0,x,y,GL_RGBA,GL_UNSIGNED_BYTE,buffer);
函數NextPot只給我下一個POT大小,所以如果屏幕大小是320x480,x,y將是512x512。
也許你看到的是緩沖區的環繞,因為它期望更大的緩沖區大小?
這也許是它在模擬器中而不是在設備上工作的原因,我的顯卡沒有POT大小限制,我得到類似(奇怪的外觀)結果。
我假設發生的是你試圖在覆蓋的窗口上使用glReadPixels
。 如果覆蓋了視圖區域,則glReadPixels
的結果未定義。
請參閱如何使用glDrawPixels()和glReadPixels()? 和像素所有權問題 。
至於說在這里 :
解決方案是制作一個屏幕外緩沖區(FBO)並渲染到FBO。
另一個選擇是確保在使用glReadPixels
時窗口未被覆蓋。
我沒有解決glReadPixels的問題。 我的建議是你改變算法以避免需要從屏幕上讀回數據。
看看這個頁面 。 這些人在Flash中完成了翻頁效果。 一切都是二維的,只有陰影漸變才能實現幻覺。
我認為你可以使用類似的方法,但在3D方面要好一些。 基本上你必須將效果分成三個部分:正面朝上的首頁(雲),底頁(女孩)和首頁的背面。 你必須分別繪制每個部分。 您可以在同一屏幕中輕松地將正面朝上的首頁和底部頁面繪制在一起,您只需要為每個繪圖代碼調用一個預設剪裁區域,該剪裁區域與頂部頁面彎曲的分割線對齊。 在繪制了頂部和背面部分后,可以在頂部繪制灰色背面部分,也與分割線對齊。
使用這種方法,你唯一丟失的是雲圖像開始彎曲時的一點變形,當然我的方法不會發生變形。 希望這不會減少效果,我認為陰影對於給出深度效果更為重要,並且會隱藏這種輕微的不一致性。
我正在使用glReadPixels獲取我的安卓游戲的屏幕截圖,沒有任何問題。
我不確定你的情況有什么問題,需要更多的信息。 所以讓我們開始:
我建議你不要指定PixelStore格式。 我擔心你的1字節對齊,你真的“用它”/“知道它做了什么”? 看起來你得到了你指定的內容 - 一個額外的字節(看你的圖像,一直有一個額外的像素!)而不是完全打包的圖像。 所以試着刪除這個:
glPixelStorei(GL_UNPACK_ALIGNMENT,1); glPixelStorei(GL_PACK_ALIGNMENT,1);
我不確定在C代碼中,因為我只在java中工作,但這看起來可能有點:
// width / height deviceWidth = IwGxGetDeviceWidth(); deviceHeight = IwGxGetDeviceHeight();
你有設備尺寸嗎? 您應該使用OpenGL表面大小,如下所示:
public void onSurfaceChanged(GL10 gl, int width, int height) {
int surfaceWidth = width;
int surfaceHeight = height;
}
接下來你用捕獲的圖像做什么? 你是否意識到你從opengl獲得的內存塊是RGBA,但所有非opengl圖像操作都期望ARGB? 例如,在您的代碼中,您希望alpha是第一位,而不是最后一位:
img-> SetFormat(CIwImage :: ABGR_8888);
如果1,2和3沒有幫助,您可能希望將捕獲的屏幕保存到手機SD卡以便稍后檢查。 我有一個程序將opengl RGBA塊轉換為普通位圖,以便在PC上進行檢查。 我可以和你分享。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.