【问题标题】:OpenGL rendering to texture looks jaggedOpenGL 渲染到纹理看起来参差不齐
【发布时间】: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


【解决方案1】:

正如 genpfault 和 Frischer Hering 所指出的,渲染到普通纹理时没有抗锯齿。但是,您可以渲染到 Multisample 纹理,它将根据您的请求保存尽可能多的样本信息。要将其渲染到屏幕上,您需要对纹理进行采样以获得每个像素的一种颜色,这可以通过调用 glBlitFramebuffer 来完成。根据 glBlitFramebuffer 上的 OpenGL 参考:

如果读取帧缓冲区的 SAMPLE_BUFFERS 大于零且绘制帧缓冲区的 SAMPLE_BUFFERS 为零,则源中每个像素位置对应的样本在写入目标之前会转换为单个样本。

这两个链接也很有帮助:

http://www.learnopengl.com/#!Advanced-OpenGL/Anti-aliasing http://ake.in.th/2013/04/02/offscreening-and-multisampling-with-opengl/

这是我的解决方案,创建对象:

/// FRAMEBUFFER MULTISAMPLE

framebufferMS = 0;
glGenFramebuffers(1, &framebufferMS);
glBindFramebuffer(GL_FRAMEBUFFER, framebufferMS);

glGenTextures(1, &renderedTextureMS);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, renderedTextureMS);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, SAMPLES, textureFormat, textureWidth, textureHeight, GL_TRUE);

glGenRenderbuffers(1, &depthrenderbufferMS);
glBindRenderbuffer(GL_RENDERBUFFER, depthrenderbufferMS);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, SAMPLES, GL_DEPTH24_STENCIL8, textureWidth, textureHeight);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthrenderbufferMS);

glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, renderedTextureMS, 0);
DrawBuffersMS[0] = GL_COLOR_ATTACHMENT0;
glDrawBuffers(1, DrawBuffersMS);

if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
    std::cout << "Couldn't set up frame buffer" << std::endl;
}

/// FRAMEBUFFER SIMPLE

framebuffer = 0;
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);

glGenTextures(1, &renderedTexture);
glBindTexture(GL_TEXTURE_2D, renderedTexture);
glTexImage2D(GL_TEXTURE_2D, 0, textureFormat, textureWidth, textureHeight, 0, textureFormat, GL_UNSIGNED_BYTE, 0);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

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;
}

以及渲染过程:

// Render to framebuffer multisample
glBindFramebuffer(GL_FRAMEBUFFER, framebufferMS);
glViewport(0,0,textureWidth,textureHeight);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

for(int i = 0; i < geometriesToDraw.size(); ++i) {
    geometriesToDraw[i]->draw(program);
}

// Sample to normal texture
glBindFramebuffer(GL_READ_FRAMEBUFFER, framebufferMS);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer);
glBlitFramebuffer(0, 0, textureWidth, textureHeight, 0, 0, textureWidth, textureHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);

您还可以在 stackoverflow 上找到有关该主题的更多问题,因为我搜索“锯齿状”之类的术语而不是多重采样:P

非常感谢您的帮助!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-30
    • 2014-08-09
    • 1970-01-01
    • 2012-06-03
    • 2014-07-22
    • 2013-10-05
    • 1970-01-01
    相关资源
    最近更新 更多