glReadPixels - 图像看起来很抖动

时间:2011-07-27 15:14:45

标签: opengl glreadpixels cimg

我希望捕获我在openGL中渲染的图像。我使用glReadPixels,然后使用CImg保存图像。不幸的是,结果是错误的。见下文。左边的图像是正确的。我用GadWin PrintScreen捕获了它。右侧的图像不正确。我用glReadPixels和CImg创建了它:

enter image description here enter image description here

我已经做了很多关于可能出错的网络研究,但是我没有办法去追求。这里代码捕获图像:

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

2 个答案:

答案 0 :(得分:5)

你清楚地从帧缓冲区获取图像,但行长似乎关闭了。您设置了包装对齐(好),但有更多可设置的参数:

  • GL_PACK_ROW_LENGTH
  • GL_PACK_SKIP_PIXELS
  • GL_PACK_SKIP_ROWS

将它们设置为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);