9

我正在使用 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);
}
4

6 回答 6

5

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

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

于 2011-11-30T11:57:47.657 回答
5

那是一个驱动程序错误。就那么简单。

驱动程序弄错了显存中表面的间距。您可以在上面的行中清楚地看到这一点。此外,您在图像下部看到的垃圾是驱动程序认为存储图像的内存,但那里有不同的数据。纹理/顶点数据可能。

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

于 2011-11-27T19:24:30.503 回答
3

我假设正在发生的是你试图glReadPixels在被覆盖的窗口上使用。如果视图区域被覆盖,则结果glReadPixels是未定义的。

请参阅如何使用 glDrawPixels() 和 glReadPixels()?像素所有权问题

正如这里所说:

解决方案是制作一个屏幕外缓冲区 (FBO) 并渲染到 FBO。

另一种选择是确保在使用glReadPixels.

于 2011-11-30T10:31:10.733 回答
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 大小限制,我得到类似(看起来很奇怪)的结果。

于 2011-11-28T10:34:40.217 回答
1

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

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

  1. 我建议您不要指定 PixelStore 格式。我担心您在 1 字节中对齐,您真的“使用它”/“知道它做什么”吗?似乎您得到的正是您指定的 - 一个额外的字节(看看您的图像,一直有一个额外的像素!)而不是完全打包的图像。所以尝试删除这个:

    glPixelStorei(GL_UNPACK_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 没有帮助,您可能希望将捕获的屏幕保存到手机 sdcard 以便稍后检查。我有一个程序可以将 opengl RGBA 块转换为普通位图以在 PC 上检查。我可以和你分享。

于 2011-11-30T11:15:27.853 回答
1

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

看看这个页面。这些家伙已经在 Flash 中完成了翻页效果。这一切都是 2D 的,这种错觉是通过阴影渐变来实现的。

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

使用这种方法,您唯一会失去的是云图像开始弯曲的一点变形,当然我的方法不会发生变形。希望这不会削弱效果,我认为阴影对于提供深度效果更为重要,并且会隐藏这种轻微的不一致。

于 2011-11-30T07:11:43.913 回答