我一直在努力理解 glReadPixels 的输出,它在理论上似乎很简单,但实际上产生了令人费解的结果(至少对我来说)。
假设我有一个简单的片段着色器,它绘制一个颜色值为 vec4(0.2, 0, 0, 0) 的三角形,而背景颜色设置为 (0.3, 1.0, 1.0, 0.0),如下所示:
下面是我用来生成上面图像的完整代码(除了着色器构造):
#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);
为了便于检查从帧缓冲区读出的像素值的过程,我只提取红色通道,因此容纳像素数据所需的数据大小为DISPLAY_WIDTH * DISPLAY_HEIGHT
。此外,这意味着我打印出来的值应该是背景颜色的“76”,几何形状的值应该是“51”。
令人惊讶的是,我打印出来的每个红色通道像素数据(所有 DISPLAY_WIDTH * DISPLAY_HEIGHT 像素都被打印)恰好是“76”,就好像几何被忽略一样。请注意,我在绘制调用之后和交换缓冲区之前读取像素。
如果您能让我知道我在这里缺少什么,我将不胜感激。