I've been struggling to understand the output of glReadPixels, which appears to be straightforward in theory, but actually produces puzzling (at least to me) results.
Let's assume I have a simple fragment shader that draws a single triangle with a color value of vec4(0.2, 0, 0, 0), whereas the background color is set to (0.3, 1.0, 1.0, 0.0), like so:
Below is the complete code (with the exception of shader construction) that I use to produce the image above:
#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;
}
Note, that I am using a default framebuffer, which will treat my color values as normalized signed integers and will convert them to the range between [0-255], i.e. my background color is going to be (76, 255, 255, 0), whereas my geometry color is going to be (51, 0, 0, 0).
And so after I draw my geometry and swap the buffers, I get my image. Now I want to read out the color values. In order to do it, I insert the necessary glReadPixels related code right before I swap buffers:
GLubyte* data = new GLubyte[DISPLAY_WIDTH * DISPLAY_HEIGHT];
glReadPixels(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT, GL_RED, GL_UNSIGNED_BYTE, data);
In order to facilitate the process of examining pixel values that I read out from the framebuffer, I just extract red channel, hence the size of data necessary to accommodate pixel data is DISPLAY_WIDTH * DISPLAY_HEIGHT. Furthermore, it means that the values I print out are supposed to be '76' for the background color, and '51' for geometry.
Surprisingly, every single red channel pixel data (all the DISPLAY_WIDTH * DISPLAY_HEIGHT pixels are printed) I print out happens to be '76', as if geometry is ignored. Note that I read pixels after the draw call and before I swap buffers.
I would greatly appreciate if you could let me know what I am missing in here.
