【发布时间】:2017-03-17 06:43:59
【问题描述】:
我正在使用 OpenGL 制作一个程序,该程序在 GPU 中渲染帧,然后我将其传输到内存中,以便可以在另一个程序中使用它们。我不需要窗口或渲染到屏幕,所以我使用的是 GLFW,但有一个隐藏的窗口和上下文。在 opengl-tutorial.com 之后,我设置了一个带有纹理和深度渲染缓冲区的帧缓冲区,这样我就可以渲染到纹理然后读取它的像素。只是为了检查一下我可以让窗口可见,然后我将纹理重新渲染到屏幕上的四边形并使用直通着色器。
我的问题是,当我直接渲染到屏幕(没有帧缓冲区或纹理)时,图像看起来很棒而且很流畅。但是,当我渲染到纹理然后将纹理渲染到屏幕时,它看起来是锯齿状的。我不认为问题出在将纹理渲染到屏幕上时,因为我还将读取的像素保存到 .jpg 中,而且那里看起来也参差不齐。
窗口和纹理的大小都是 512x512 像素。
这是我设置帧缓冲区的代码:
FramebufferName = 0;
glGenFramebuffers(1, &FramebufferName);
glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName);
//GLuint renderedTexture;
glGenTextures(1, &renderedTexture);
glBindTexture(GL_TEXTURE_2D, renderedTexture);
glTexImage2D(GL_TEXTURE_2D, 0, textureFormat, textureWidth, textureHeight, 0, textureFormat, GL_UNSIGNED_BYTE, 0);
numBytes = textureWidth * textureHeight * 3; // RGB
pixels = new unsigned char[numBytes]; // allocate image data into RAM
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
//GLuint depthrenderbuffer;
glGenRenderbuffers(1, &depthrenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, depthrenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, textureWidth, textureHeight);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthrenderbuffer);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, renderedTexture, 0);
DrawBuffers[0] = GL_COLOR_ATTACHMENT0;
glDrawBuffers(1, DrawBuffers); // "1" is the size of DrawBuffers
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
std::cout << "Couldn't set up frame buffer" << std::endl;
}
g_quad_vertex_buffer_data.push_back(-1.0f);
g_quad_vertex_buffer_data.push_back(-1.0f);
g_quad_vertex_buffer_data.push_back(0.0f);
g_quad_vertex_buffer_data.push_back(1.0f);
g_quad_vertex_buffer_data.push_back(-1.0f);
g_quad_vertex_buffer_data.push_back(0.0f);
g_quad_vertex_buffer_data.push_back(-1.0f);
g_quad_vertex_buffer_data.push_back(1.0f);
g_quad_vertex_buffer_data.push_back(0.0f);
g_quad_vertex_buffer_data.push_back(-1.0f);
g_quad_vertex_buffer_data.push_back(1.0f);
g_quad_vertex_buffer_data.push_back(0.0f);
g_quad_vertex_buffer_data.push_back(1.0f);
g_quad_vertex_buffer_data.push_back(-1.0f);
g_quad_vertex_buffer_data.push_back(0.0f);
g_quad_vertex_buffer_data.push_back(1.0f);
g_quad_vertex_buffer_data.push_back(1.0f);
g_quad_vertex_buffer_data.push_back(0.0f);
//GLuint quad_vertexbuffer;
glGenBuffers(1, &quad_vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, g_quad_vertex_buffer_data.size() * sizeof(GLfloat), &g_quad_vertex_buffer_data[0], GL_STATIC_DRAW);
// PBOs
glGenBuffers(cantPBOs, pboIds);
for(int i = 0; i < cantPBOs; ++i) {
glBindBuffer(GL_PIXEL_PACK_BUFFER, pboIds[i]);
glBufferData(GL_PIXEL_PACK_BUFFER, numBytes, 0, GL_DYNAMIC_READ);
}
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
index = 0;
nextIndex = 0;
这是我渲染到纹理的代码:
glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName);
glViewport(0,0,textureWidth,textureHeight); // Render on the whole framebuffer, complete from the lower left corner to the upper right
// Clear the screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
for(int i = 0; i < geometriesToDraw.size(); ++i) {
geometriesToDraw[i]->draw(program);
}
其中 draw(ShaderProgram) 是调用 glDrawArrays 的函数。这是我将纹理渲染到屏幕的代码:
// Render to the screen
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// Render on the whole framebuffer, complete from the lower left corner to the upper right
glViewport(0,0,textureWidth,textureHeight);
// Clear the screen
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(shaderTexToScreen.getProgramID());
// Bind our texture in Texture Unit 0
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, renderedTexture);
// Set our "renderedTexture" sampler to user Texture Unit 0
glUniform1i(shaderTexToScreen.getUniformLocation("renderedTexture"), 0);
// 1rst attribute buffer : vertices
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer);
glVertexAttribPointer(
0,
3,
GL_FLOAT,
GL_FALSE,
0,
(void*)0
);
glDrawArrays(GL_TRIANGLES, 0, 6);
glDisableVertexAttribArray(0);
这是我直接将场景渲染到屏幕时得到的:
这就是我在将场景渲染为纹理时得到的结果:
我可以包含用于将纹理渲染到屏幕的顶点和片段着色器的代码,但是当我直接从纹理中读取像素数据并将其写入文件时,它看起来仍然是锯齿状的,所以我没有认为这就是问题所在。如果您还希望我包含任何其他内容,请告诉我!
我认为可能是在对纹理进行渲染时存在一些隐藏的缩放,因此 GL_NEAREST 使它看起来很糟糕,但如果它真的是像素到像素(窗口和纹理的大小相同),那么应该'不会有问题吧?
【问题讨论】:
-
GPU 驱动程序中是否强制启用多重采样?
-
这些是Nvidia控制面板中的设置imgur.com/UYnAh8i
-
Welp,可能是时候发minimal reproducible example了。
-
渲染看起来非常好。正如 genpfault 已经暗示的那样:RTT 解决方案根本没有抗锯齿。请参阅本教程的结尾:opengl-tutorial.org/intermediate-tutorials/…
-
你完全正确!感谢您指出了这一点。我设置了两个帧缓冲区,一个带有多重采样,我渲染场景,然后我从那个到另一个将各种样本转换为一个。然后我可以将附加到第二个帧缓冲区的纹理渲染到屏幕上,它看起来很平滑。我会尽快用代码示例写一个完整的答案。
标签: c++ opengl framebuffer artifacts render-to-texture