c++ - glReadPixels 始终在 glClearColor 中返回相同的值

标签 c++ opengl

我一直在努力理解 glReadPixels 的输出,这在理论上似乎很简单,但实际上会产生令人费解的(至少对我而言)结果。

假设我有一个简单的片段着色器,它绘制一个颜色值为 vec4(0.2, 0, 0, 0) 的三角形,而背景颜色设置为 (0.3, 1.0, 1.0, 0.0),例如所以:

enter image description here

下面是我用来生成上图的完整代码(着色器构造除外):

#include "shader.h" // shader compile/link/use 
#include <GLFW\glfw3.h>
#include <iostream>

const int DISPLAY_WIDTH = 16; 
const int DISPLAY_HEIGHT = 16; 

//============= shader code ==========================

const GLchar *vertexShaderSource = R"glsl(#version 440
in vec2 position;
void main()
{
    gl_Position = vec4(position, 0.0, 1.0);
})glsl";

const GLchar *fragmentShaderSource = R"glsl(#version 440
out vec4 outColor;

void main()
{   
    outColor = vec4(0.2,0.,0.,0.);
})glsl";

//============= c++ entry point ==========================

int main(int argc, char** argv) {

    glfwInit();
    GLFWwindow* window = glfwCreateWindow(DISPLAY_WIDTH, DISPLAY_HEIGHT, "test", NULL, NULL);
    glfwMakeContextCurrent(window);

    GLenum res = glewInit();

    // triangle data (xy-position)
    float vertices[] = {
    0.0f, 0.5f, 
    0.5f, -0.5f, 
    -0.5f, -0.5f  
    };

    GLuint vbo;
    glGenBuffers(1, &vbo); 
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    // enable vertex xy-position attribute 
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(0);

    // compile, link and use shader program
    Shader shader(vertexShaderSource, fragmentShaderSource);
    shader.Use();

    // rendering loop
    while (!glfwWindowShouldClose(window)) {

       glClearColor(0.3f, 1.0f, 1.0f, 0.0f);
       glClear(GL_COLOR_BUFFER_BIT);

       glDrawArrays(GL_TRIANGLES, 0, 3);
       glFlush();

       // read pixels from backbuffer 
       GLubyte data[DISPLAY_WIDTH * DISPLAY_HEIGHT];
       glReadPixels(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT, GL_RED, GL_UNSIGNED_BYTE, data);

       for (int i = 0; i < DISPLAY_WIDTH * DISPLAY_HEIGHT; i++) {
           int a = data[i]; // implicit conversion of unsigned char to int
           std::cout << a << std::endl;
       }
       std::getchar(); // wait for user input

       glfwSwapBuffers(window);
       glfwPollEvents();
    }

   glfwTerminate(); 
   return 0;
}

请注意,我使用的是默认帧缓冲区,它将我的颜色值视为标准化的有符号整数,并将它们转换为 [0-255] 之间的范围,即我的背景颜色将为 (76, 255, 255, 0),而我的几何颜色将是 (51, 0, 0, 0)。

所以在我绘制几何图形并交换缓冲区后,我得到了我的图像。现在我想读出颜色值。为此,我在交换缓冲区之前插入必要的 glReadPixels 相关代码:

GLubyte* data = new GLubyte[DISPLAY_WIDTH * DISPLAY_HEIGHT];
glReadPixels(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT, GL_RED, GL_UNSIGNED_BYTE, data);

为了便于检查从帧缓冲区中读取的像素值的过程,我只提取红色 channel ,因此容纳像素数据所需的数据大小为 DISPLAY_WIDTH * DISPLAY_HEIGHT。此外,这意味着我打印出的值对于背景颜色应该是“76”,对于几何形状应该是“51”。

令人惊讶的是,我打印出的每个红色 channel 像素数据(所有 DISPLAY_WIDTH * DISPLAY_HEIGHT 像素都被打印出来)恰好是“76”,就好像忽略了几何形状一样。请注意,我在绘制调用之后和交换缓冲区之前读取像素。

如果您能让我知道我在这里缺少什么,我将不胜感激。

最佳答案

在我的 Debian Stretch box 上运行良好:

GLEW version: 2.0.0
GLFW version: 3.2.1 X11 GLX EGL clock_gettime /dev/js Xf86vm shared
GL_VERSION  : 3.0 Mesa 13.0.6
GL_VENDOR   : Intel Open Source Technology Center
GL_RENDERER : Mesa DRI Intel(R) Kabylake GT2 

76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 
76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 
76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 
76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 
76 76 76 76 51 51 51 51 51 51 51 51 76 76 76 76 
76 76 76 76 76 51 51 51 51 51 51 76 76 76 76 76 
76 76 76 76 76 51 51 51 51 51 51 76 76 76 76 76 
76 76 76 76 76 76 51 51 51 51 76 76 76 76 76 76 
76 76 76 76 76 76 51 51 51 51 76 76 76 76 76 76 
76 76 76 76 76 76 76 51 51 76 76 76 76 76 76 76 
76 76 76 76 76 76 76 51 51 76 76 76 76 76 76 76 
76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 
76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 
76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 
76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 
76 76 76 76 76 76 76 76 76 76 76 76 76 76 76 76

全部(将着色器 #version 降为 130 因为 Mesa 在非核心上下文中不支持任何超过 GL 3.0 的内容):

// g++ main.cpp -lGLEW -lGL -lglfw
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <cstdarg>

struct Program
{
    static GLuint Load( const char* shader, ... )
    {
        GLuint prog = glCreateProgram();
        va_list args;
        va_start( args, shader );
        while( shader )
        {
            const GLenum type = va_arg( args, GLenum );
            AttachShader( prog, type, shader );
            shader = va_arg( args, const char* );
        }
        va_end( args );
        glLinkProgram( prog );
        CheckStatus( prog );
        return prog;
    }

private:
    static void CheckStatus( GLuint obj )
    {
        GLint status = GL_FALSE;
        if( glIsShader(obj) ) glGetShaderiv( obj, GL_COMPILE_STATUS, &status );
        if( glIsProgram(obj) ) glGetProgramiv( obj, GL_LINK_STATUS, &status );
        if( status == GL_TRUE ) return;
        GLchar log[ 1 << 15 ] = { 0 };
        if( glIsShader(obj) ) glGetShaderInfoLog( obj, sizeof(log), NULL, log );
        if( glIsProgram(obj) ) glGetProgramInfoLog( obj, sizeof(log), NULL, log );
        std::cerr << log << std::endl;
        exit( EXIT_FAILURE );
    }

    static void AttachShader( GLuint program, GLenum type, const char* src )
    {
        GLuint shader = glCreateShader( type );
        glShaderSource( shader, 1, &src, NULL );
        glCompileShader( shader );
        CheckStatus( shader );
        glAttachShader( program, shader );
        glDeleteShader( shader );
    }
};

const GLchar *vertexShaderSource = R"glsl(#version 130
in vec2 position;
void main()
{
    gl_Position = vec4(position, 0.0, 1.0);
})glsl";

const GLchar *fragmentShaderSource = R"glsl(#version 130
out vec4 outColor;

void main()
{   
    outColor = vec4(0.2,0.,0.,0.);
})glsl";


const int DISPLAY_WIDTH = 16; 
const int DISPLAY_HEIGHT = 16; 


int main(int argc, char** argv)
{
    glfwInit();
    GLFWwindow* window = glfwCreateWindow(DISPLAY_WIDTH, DISPLAY_HEIGHT, "test", NULL, NULL);
    glfwMakeContextCurrent(window);

    GLenum res = glewInit();

    std::cout << "GLEW version: " << glewGetString(GLEW_VERSION) << std::endl;
    std::cout << "GLFW version: " << glfwGetVersionString() << std::endl;
    std::cout << "GL_VERSION  : " << glGetString( GL_VERSION ) << std::endl;
    std::cout << "GL_VENDOR   : " << glGetString( GL_VENDOR ) << std::endl;
    std::cout << "GL_RENDERER : " << glGetString( GL_RENDERER ) << std::endl;

    // triangle data (xy-position)
    float vertices[] =
    {
        0.0f, 0.5f, 
        0.5f, -0.5f, 
        -0.5f, -0.5f  
    };

    GLuint vbo;
    glGenBuffers(1, &vbo); 
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    // enable vertex xy-position attribute 
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(0);

    // compile, link and use shader program
    GLuint program = Program::Load
        (
        vertexShaderSource, GL_VERTEX_SHADER,
        fragmentShaderSource, GL_FRAGMENT_SHADER,
        NULL
        );
    glUseProgram( program );

    // rendering loop
    while (!glfwWindowShouldClose(window)) {

    glClearColor(0.3f, 1.0f, 1.0f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    glDrawArrays(GL_TRIANGLES, 0, 3);
    glFlush();

    // read pixels from backbuffer 
    GLubyte data[DISPLAY_WIDTH * DISPLAY_HEIGHT];
    glReadPixels(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT, GL_RED, GL_UNSIGNED_BYTE, data);

    int i = 0;
    for (int y = 0; y < DISPLAY_HEIGHT; y++)
    {
        for (int x = 0; x < DISPLAY_WIDTH; x++)
        {
            int a = data[i]; // implicit conversion of unsigned char to int
            std::cout << a << " ";;
            i++;
        }
        std::cout << std::endl;
    }
    std::cout << std::endl;

    glfwSwapBuffers(window);
    glfwPollEvents();
    }

    glfwTerminate(); 
    return 0;
}

关于c++ - glReadPixels 始终在 glClearColor 中返回相同的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46610617/

相关文章:

c++ - 命名空间函数的链接

C++ Hermite多项式实现

c++ - OpenGL 立体 : alternating between left and right textures

c++ - GLSL 纹理映射不起作用

c++ - 纹理在opengl中消失

c++ - Qt中提交QSqlRecord到MySQL数据库

c++ - 为什么这不起作用? libcurl 和 C++

c++ - NVIDIA NVCC 在使用模板特征类型时更改编译时间常量

opengl - 现代 GLSL 中的每像素光照?

c++ - Qt/OpenGL : Am I using PBO correctly ?