我希望捕获我在openGL中渲染的图像。我使用glReadPixels,然后使用CImg保存图像。不幸的是,结果是错误的。见下文。左边的图像是正确的。我用GadWin PrintScreen捕获了它。右侧的图像不正确。我用glReadPixels和CImg创建了它:
我已经做了很多关于可能出错的网络研究,但是我没有办法去追求。这里代码捕获图像:
void snapshot() {
int width = glutGet(GLUT_WINDOW_WIDTH);
int height = glutGet(GLUT_WINDOW_HEIGHT);
glPixelStorei(GL_PACK_ROW_LENGTH, 0);
glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
glPixelStorei(GL_PACK_SKIP_ROWS, 0);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
int bytes = width*height*3; //Color space is RGB
GLubyte *buffer = (GLubyte *)malloc(bytes);
glFinish();
glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer);
glFinish();
CImg<GLubyte> img(buffer,width,height,1,3,false);
img.save("ScreenShot.ppm");
exit(0);
}
这是我调用快照方法的地方:
void display(void) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
drawIndividual(0);
snapshot();
glutSwapBuffers();
}
跟进评论,我抓住了位深度并打印到控制台。结果如下:
redbits=8
greenbits=8
bluebits=8
depthbits=24
答案 0 :(得分:5)
你清楚地从帧缓冲区获取图像,但行长似乎关闭了。您设置了包装对齐(好),但有更多可设置的参数:
将它们设置为0以进行紧密包装。 glReadPixels()之后的glFinish()也是超级的。 glReadPixels不能异步工作 - 它只在读取数据被复制到目标缓冲区后才返回(或者在写入PBO的情况下,从PBO获取数据将等待操作完成)。
答案 1 :(得分:2)
CImg不会交错颜色。也就是说,3个红色,绿色,蓝色像素将线性存储为:
R1,R2,R3,...,G1,G2,G3,...,B1,B2,B3,...
然而,OpenGL的glReadPixel和glDrawPixel期望像这样的交错颜色组件:
R1,G1,B1,R2,G2,B2,......
此外,OpenGL将原点(0,0)放在图像的左下角。 CImg使用更多的方法,原点位于图像的左上角。
这是我编写的例程,将交错颜色转换为CImg面向频道的格式。
void convertToNonInterleaved(int w, int h, unsigned char* tangled, unsigned char* untangled) {
//Take string in format R1 G1 B1 R2 G2 B2... and re-write it
//in the format format R1 R2 G1 G2 B1 B2...
//Assume 8 bit values for red, green and blue color channels.
//Assume there are no other channels
//tangled is a pointer to the input string and untangled
//is a pointer to the output string. This method assumes that
//memory has already been allocated for the output string.
int numPixels = w*h;
int numColors = 3;
for(int i=0; i<numPixels; ++i) {
int indexIntoInterleavedTuple = numColors*i;
//Red
untangled[i] = tangled[indexIntoInterleavedTuple];
//Green
untangled[numPixels+i] = tangled[indexIntoInterleavedTuple+1];
//Blue
untangled[2*numPixels+i] = tangled[indexIntoInterleavedTuple+2];
}
}
我应该添加代码来解释原点的变化,但我觉得很懒,并决定使用CImg来做到这一点。运行此例程后,此代码将创建图像对象:
unsigned char* p = (unsigned char *)malloc(bytes);
convertToNonInterleaved(width, height, buffer, p);
CImg<unsigned char> img(p, width, height,1,3);
free(p);
img.mirror('y');
CImgDisplay main_disp(img,"Snapshot");
while (!main_disp.is_closed() ) {
main_disp.wait();
}
据我所知,我不需要设置任何包装参数。这是我用来从OpenGL渲染目标中获取像素的代码:
bytes = width*height*3; //Color space is RGB
if(buffer)
free(buffer);
buffer = (GLubyte *)malloc(bytes);
glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer);