对纹理的OpenGL渲染看起来是锯齿状的

时间:2016-11-03 15:36:06

标签: c++ opengl framebuffer artifacts render-to-texture

我正在使用OpenGL创建一个程序,在GPU中渲染帧,然后我将其传输到内存,以便我可以在另一个程序中使用它们。我不需要窗口或渲染到屏幕,所以我使用GLFW,但有一个隐藏的窗口和上下文。在opengl-tutorial.com之后,我设置了一个带有纹理和深度渲染缓冲的帧缓冲,这样我就可以渲染到纹理,然后读取它的像素。只是检查一下我可以使窗口可见的东西,然后我在四边形屏幕上渲染纹理并使用直通着色器。

我的问题是,当我直接渲染到屏幕(没有Framebuffer或纹理)时,图像看起来很棒,很流畅。但是,当我渲染到纹理然后将纹理渲染到屏幕时,它看起来是锯齿状的。在将纹理渲染到屏幕时,我不会想到问题,因为我还将我读取的像素保存为.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);

这是我将场景直接渲染到屏幕时得到的结果:

direct

这是我将场景渲染到纹理时得到的结果:

texture

我可以包含用于渲染纹理到屏幕的顶点和片段着色器的代码,但是当我直接从纹理读取像素数据并将其写入文件并且仍然看起来像是锯齿状时,我不会&#39 ;认为这是问题所在。如果还有其他任何您希望我加入的内容,请与我联系!

我想也许可能是在渲染纹理时有一些隐藏的缩放因此GL_NEAREST使它看起来很糟糕,但如果它确实是像素到点(窗口和纹理都是相同的大小)那么就不应该&# 39;那是一个问题吗?

1 个答案:

答案 0 :(得分:1)

正如genpfault和Frischer Hering所指出的,渲染到普通纹理时没有抗锯齿效果。但是,您可以渲染为多重采样纹理,该纹理将保存您请求的多个样本的信息。要将其渲染到屏幕,您需要对纹理进行采样以获得每个像素的一种颜色,这可以通过调用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上找到关于这个问题的更多问题,因为我搜索了像&#34; jagged&#34;这样的术语。而不是多重采样:P

非常感谢你的帮助!