我正在使用OpenGL中的2D图形 - 分形和其他有趣的东西^ _ ^。我的基本设置是渲染几个三角形来填充屏幕并使用片段着色器在它们上绘制很酷的东西。我想稍稍解决问题,所以我开始研究超级采样。对我来说,如何解决这个问题并不明显。这是我到目前为止所尝试的......
首先,我查看了Apple docs on anti-aliasing。我更新了像素格式初始化:
NSOpenGLPixelFormatAttribute attrs[] =
{
NSOpenGLPFADoubleBuffer,
NSOpenGLPFADepthSize, 24,
NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion4_1Core,
NSOpenGLPFASupersample,
NSOpenGLPFASampleBuffers, 1,
NSOpenGLPFASamples, 4,
0
};
我还添加了glEnable(GL_MULTISAMPLE);
行。 GL_MULTISAMPLE_FILTER_HINT_NV
似乎没有定义(文档似乎已过时),所以我不确定该怎么做。
这使我的渲染速度变慢但似乎没有做抗锯齿,所以我尝试了OpenGL Wiki on Multisampling中描述的“Render-to-FBO”方法。我尝试过各种各样的变化,包括各种结果:成功渲染(看起来似乎没有消除锯齿),渲染垃圾到屏幕上(好玩!),崩溃(app蒸发,我得到一个系统对话框)关于图形问题),并使我的笔记本电脑在光标旁边没有响应(在硬重启后获得有关图形问题的系统对话框)。
我在绘图之前检查我的帧缓冲区的状态,所以我知道这不是问题。而且我确定我用硬件而不是软件渲染 - 在其他帖子上看到了这个建议。
我花了相当多的时间在上面,但仍然不太明白如何处理这个问题。我喜欢的一件事就是如何查询GL以查看是否正确启用了超级采样,或者如何判断我的片段着色器被调用了多少次等等。我也对某些调用的位置感到困惑go - 我发现大多数示例只是说要调用哪些方法,但是没有指定哪些方法需要进入draw
回调。任何人都有一个简单的SSAA示例,其中包含OpenGL 3或4以及OSX ...或其他可以尝试的内容?
编辑:绘图代码 - 超级破碎(不要评判我),但供参考:
- (void)draw
{
glBindVertexArray(_vao); // todo: is this necessary? (also in init)
glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(GLfloat), points, GL_STATIC_DRAW);
glGenTextures( 1, &_tex );
glBindTexture( GL_TEXTURE_2D_MULTISAMPLE, _tex );
glTexImage2DMultisample( GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA8, _width * 2, _height * 2, false );
glGenFramebuffers( 1, &_fbo );
glBindFramebuffer( GL_FRAMEBUFFER, _fbo );
glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, _tex, 0 );
GLint status;
status = glCheckFramebufferStatus( GL_FRAMEBUFFER );
if (status != GL_FRAMEBUFFER_COMPLETE) {
NSLog(@"incomplete buffer 0x%x", status);
return;
}
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBindFramebuffer(GL_READ_FRAMEBUFFER, _fbo);
glDrawBuffer(GL_BACK);
glClear(GL_COLOR_BUFFER_BIT);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBlitFramebuffer(0, 0, _width * 2, _height * 2, 0, 0, _width, _height, GL_COLOR_BUFFER_BIT, GL_LINEAR);
glDeleteTextures(1, &_tex);
glDeleteFramebuffers(1, &_fbo);
glBindFramebuffer( GL_FRAMEBUFFER, 0 );
}
更新 我根据Reto的建议更改了我的代码:
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _fbo);
glClear(GL_COLOR_BUFFER_BIT);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindFramebuffer(GL_READ_FRAMEBUFFER, _fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBlitFramebuffer(0, 0, _width * 2, _height * 2, 0, 0, _width, _height,
GL_COLOR_BUFFER_BIT, GL_LINEAR);
这导致程序向屏幕渲染垃圾。然后我摆脱了* 2
乘数,它仍然在屏幕上画垃圾。然后我关闭了与多/超采样相关的NSOpenGLPFA
选项,并且它正常渲染,没有消除锯齿。
我也尝试使用非多重采样纹理,但不断发现附件错误。我不确定这是否是由于OpenGL维基上提到的NVidia问题(因为我没有足够的代表发布超过2个链接而发布评论)或其他内容。如果有人可以建议找出附件不完整的原因,那将非常非常有用。
最后,我尝试使用渲染缓冲区而不是纹理,并发现指定宽度和高度大于glRenderbufferStorage
中的视口大小似乎没有按预期工作。
GLuint rb;
glGenRenderbuffers(1, &rb);
glBindRenderbuffer(GL_RENDERBUFFER, rb);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, _width * 2, _height * 2);
// ...
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _fbo);
glClear(GL_COLOR_BUFFER_BIT);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindFramebuffer(GL_READ_FRAMEBUFFER, _fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBlitFramebuffer(0, 0, _width * 2, _height * 2, 0, 0, _width, _height,
GL_COLOR_BUFFER_BIT, GL_LINEAR);
...在屏幕的左下角1/4处渲染。虽然看起来不太顺畅......
更新2:将视口大小加倍,它不会更顺畅。转动NSOpenGLPFASupersample
仍会导致它将垃圾吸引到屏幕上。 >。<
更新3:我是个白痴,它更加顺畅。它只是看起来不好,因为我使用的是丑陋的配色方案。我必须将所有坐标加倍,因为视口是2倍。那好吧。我仍然喜欢帮助理解NSOpenGLPFASupersample
导致这种疯狂行为的原因......
答案 0 :(得分:1)
这里的通话顺序看起来不像你想要的那样:
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBindFramebuffer(GL_READ_FRAMEBUFFER, _fbo);
glDrawBuffer(GL_BACK);
glClear(GL_COLOR_BUFFER_BIT);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBlitFramebuffer(0, 0, _width * 2, _height * 2, 0, 0, _width, _height, GL_COLOR_BUFFER_BIT, GL_LINEAR);
当您致电glClear()
和glDrawArrays()
时,您当前的绘制帧缓冲区(由最后一次调用glBindFramebuffer(GL_DRAW_FRAMEBUFFER, ...)
确定)是默认的帧缓冲区。所以你永远不会渲染到FBO。让我注释上面的内容:
// Set draw framebuffer to default (0) framebuffer. This is where the rendering will go.
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
// Set read framebuffer to the FBO.
glBindFramebuffer(GL_READ_FRAMEBUFFER, _fbo);
// This is redundant, GL_BACK is the default draw buffer for the default framebuffer.
glDrawBuffer(GL_BACK);
// Clear the current draw framebuffer, which is the default framebuffer.
glClear(GL_COLOR_BUFFER_BIT);
// Draw to the current draw framebuffer, which is the default framebuffer.
glDrawArrays(GL_TRIANGLES, 0, 6);
// Copy from read framebuffer (which is the FBO) to the draw framebuffer (which is the
// default framebuffer). Since no rendering was done to the FBO, this will copy garbage
// into the default framebuffer, wiping out what was previously rendered.
glBlitFramebuffer(0, 0, _width * 2, _height * 2, 0, 0, _width, _height,
GL_COLOR_BUFFER_BIT, GL_LINEAR);
要使其正常工作,您需要在渲染时将绘制帧缓冲区设置为FBO,然后将读取帧缓冲区设置为FBO,并将绘制帧缓冲区设置为副本的默认值:
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _fbo);
glClear(GL_COLOR_BUFFER_BIT);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindFramebuffer(GL_READ_FRAMEBUFFER, _fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBlitFramebuffer(0, 0, _width * 2, _height * 2, 0, 0, _width, _height,
GL_COLOR_BUFFER_BIT, GL_LINEAR);
回顾:
GL_DRAW_FRAMEBUFFER
。glBlitFramebuffer()
份从GL_READ_FRAMEBUFFER
复制到GL_DRAW_FRAMEBUFFER
。关于代码的更多评论:
由于您要创建两倍大小的多重采样纹理,因此您可以同时使用多重采样和超级采样:
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, _tex);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA8,
_width * 2, _height * 2, false);
这完全合法。但它......很多抽样。如果您只想要超级采样,则可以使用常规纹理。