2011-11-21 187 views
9

我正在用glReadPixels进行截图,以在两幅图像之间执行“交叉”效果。OpenGL ES - glReadPixels

在果酱SDK模拟器截图取就好了和“交叉”效果的作品一种享受: enter image description here

然而,这是它的外观上的iOS和Android设备 - 损坏: http://www.eikona.info/images/81269689420703803966.png

我总是阅读屏幕RGBA 1字节/通道,因为它总是被接受的documentation says

这里是用来拍摄截图代码:

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); 
} 
+1

如果你删除你的'up-down'块,腐败消失了吗?只是倒过来?还是它被颠倒了? – sarnold

+0

事情是,我没有设备,所以我需要发送给我的客户,然后等待他安装和测试......所有这些可能需要几天时间:-( –

+0

上述评论是现在无需重新编辑我的消息,以反映我的新发现 –

回答

5

最后,它是内存不足。 “new uint8 [dataLength];”从来没有返回一个存在的指针,因此整个过程都被破坏了。

TomA,您清理缓冲区的想法实际上帮助我解决了这个问题。谢谢。

5

这是一个驱动程序的bug。就那么简单。

驱动程序错误地获取了视频内存中曲面的音高。您可以在上面的行中清楚地看到这一点。此外,您在图像下部看到的垃圾是驱动程序认为存储图像的内存,但是存在不同的数据。纹理/顶点数据也许。

对不起,我知道没有办法解决这个问题。使用不同的曲面格式或启用/禁用多重采样可能会带来更好的运气。

+0

我希望这是真实的,在iOS和Android都会出现这种腐败现象,所以在我身边肯定有其他的错误... –

+0

比尔,它很可能是相同的SGX 3D芯片,在Android上具有相同的ARM驱动程序, iOS版。 –

3

我不知道Android或正在使用的SDK,但在IOS时,我采取截图我必须使缓冲区中的下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大小限制,并且我得到了类似(看起来很奇怪)的结果。

1

我没有固定glReadPixels的解决方案。我的建议是,你改变你的算法,以避免需要从屏幕上读回数据。

看看this page。这些人在Flash中完成了翻页效果。全都是二维的,幻影只是用阴影渐变实现的。

我想你可以使用类似的方法,但在3D中稍好一点。基本上你必须将效果分成三部分:正面朝上的首页(云),底部页面(女孩)和首页的背面。您必须分别绘制每个部分。您可以在同一屏幕中轻松地将正面朝上的首页和底部页面绘制在一起,您只需调用每个预设裁剪区域的绘图代码,该区域与首页弯曲的分割线对齐。在绘制顶部和底部页面之后,您可以在顶部绘制灰色的背面部分,也与分割线对齐。

使用这种方法,你只会失去一点变形,云图像开始向上弯曲,当然我的方法不会发生变形。希望这样做不会降低效果,我认为阴影对于提供深度效果更重要,并且会隐藏这种微小的不一致。

3

我认为正在发生的事情是您正试图在覆盖的窗口上使用glReadPixels。如果查看区域被覆盖,则glReadPixels的结果未定义。

请参阅How do I use glDrawPixels() and glReadPixels()?The Pixel Ownership Problem

正如所述here

的解决方案是使离屏缓冲器(FBO)和渲染到 FBO。

另一种选择是确保当您使用glReadPixels时窗口不被覆盖。

1

我正在使用glReadPixels的android设备上没有任何问题,我的android游戏的屏幕截图。

我不确定你的情况是什么问题,需要更多的信息。 所以,让我们开始:

  1. 我建议你不要指定PixelStore格式。我担心你在1字节中的对齐,你真的“使用它”/“知道它做了什么”?看起来你得到了你指定的东西 - 一个额外的字节(看你的图像,一个额外的像素一直!),而不是完整打包的图像。所以试图删除它:

    glPixelStorei(GL_UNPACK_ALIGNMENT,1); glPixelStorei(GL_PACK_ALIGNMENT,1); glPixelStorei(GL_PACK_ALIGNMENT,1);

  2. 我不知道在C代码,如我的工作只在Java中,但是这看起来尽可能点:

    //宽度/高度 deviceWidth = IwGxGetDeviceWidth(); deviceHeight = IwGxGetDeviceHeight();

您是否正在获取设备尺寸?你应该用你的OpenGL面的大小,类似这样的:

public void onSurfaceChanged(GL10 gl, int width, int height) { 
int surfaceWidth = width; 
int surfaceHeight = height; 
} 
  1. 你在接下来拍摄的图像在做什么?你知道你从opengl获得的内存块是RGBA,但是所有非opengl图像操作都期望ARGB? 例如,在您的代码中,您希望alpha是第一位,而不是最后一位:

    img-> SetFormat(CIwImage :: ABGR_8888);

  2. 如果1,2和3没有帮助,您可能想要将捕获的屏幕保存到手机SD卡中以供日后检查。我有一个程序,将opengl RGBA块转换为普通位图,在PC上进行检查。我可能会与你分享。