OpenGL-如何绘制到多样本帧缓冲区,然后将结果用作普通纹理? [英] OpenGL - How to draw to a multisample framebuffer and then use the result as a normal texture?

查看:484
本文介绍了OpenGL-如何绘制到多样本帧缓冲区,然后将结果用作普通纹理?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个小的gamedev库.该库的元素之一是Canvas(屏幕外绘图区域),它是通过OpenGL帧缓冲区实现的.到目前为止,一切都很好,我生成了一个纹理,将其附加到帧缓冲区中,进行渲染,然后将帧缓冲区的纹理用作Texture2D.

I'm developing a little gamedev library. One of the elements of this library is a Canvas (offscreen drawing area), which is implemented through an OpenGL framebuffer. So far, everything's been good, I generate a texture, attach it to a framebuffer, render to it, then use the framebuffer's texture as Texture2D.

现在,我想在我的库中添加抗锯齿功能,因此我希望能够在Canvas上设置多重采样.现在我很困惑,因为我发现您需要更改着色器以使用多样本纹理等等.

Now, I'd like to add antialiasing to my library, so I'd like to be able to set multisampling on a Canvas. Now I'm confused because I've found that you need to alter shaders to use multisample textures and so on.

那么,我应该怎么做才能对帧缓冲区启用多重采样,从而最大程度地减少更改库的其余代码?如果可能的话,我只想将渲染结果用作常规的Texture2D.

So, what should I do to enable multisampling for my framebuffers so that I minimize changing the rest of the code of the library? I'd like to just use the rendering result as a regular Texture2D if possible.

推荐答案

只是要确保没有混淆.您不能只是创建一个大于x倍的纹理,然后希望滤镜能起到神奇作用.因为GL_LINEAR等仅对四个纹理像素进行平均最接近要纹理化像素的中心.

Just to make sure that there's no confusion. You can't just create a texture that is x times bigger and then wish that filters will do the magic. Because GL_LINEAR, etc. only averages the four texels closest to the center of the pixel being textured.

要创建多样本纹理,您可以使用 (自3.2起在内核中可用).您可以像这样设置它.

To create a multisample texture you'd use glTexImage2DMultisample() (available in core since 3.2). You'd set it up like this.

glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, tex);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_RGBA8, width, height, false);

它应该是不言自明的,因为samples是多样本纹理中的样本数量.还可以根据需要更改internalformat.

It should be self-explanatory as samples being the amount of samples in the multisample texture. Also change the internalformat as you please.

要将纹理附加到帧缓冲区,您同样可以使用 glFramebufferTexture2D() .但是,不是将textarget设置为GL_TEXTURE_2D,而是将其设置为GL_TEXTURE_2D_MULTISAMPLE.

To attach the texture to a framebuffer you equally use glFramebufferTexture2D(). But instead of setting the textarget as GL_TEXTURE_2D you set it to GL_TEXTURE_2D_MULTISAMPLE.

glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, tex, 0);

记住要检查帧缓冲区的状态.

在着色器中,您还必须使用sampler2DMS才能访问多样本纹理.但是请注意,与常规纹理相比,多样本纹理的工作方式完全不同.如果要读取纹理,则必须使用 texelFetch() .

In your shader you'll also have to use sampler2DMS to be able to access the multisample texture. However note that multisample textures work quite differently compared to regular textures. If you want to read from the texture you'll have to use texelFetch().

因此,如果要从多重采样纹理中采样,则不能使用 texture() ,但必须使用

So if you want to sample from a multisample texture then you can't use texture() but would have to utilize texelFetch() with something like.

uniform int texSamples;
uniform sampler2DMS tex;

vec4 textureMultisample(sampler2DMS sampler, ivec2 coord)
{
    vec4 color = vec4(0.0);

    for (int i = 0; i < texSamples; i++)
        color += texelFetch(sampler, coord, i);

    color /= float(texSamples);

    return color;
}

请注意, texelFetch() 不会"要获取标准化的坐标,您可以使用以下方法来规避此问题:

Note that texelFetch() doesn't take normalized coordinates, you can circumvent this with something like:

vec2 uv = vec2(0.5, 0.5); // normalized coordinates
ivec2 texSize = textureSize(tex, 0);
ivec2 texCoord = ivec2(uv * texSize);
vec4 color = textureMultisample(tex, texCoord);

一天结束时,如果要显示清晰的抗锯齿结果,则必须将其显示在屏幕上.

At the end of the day if you want display the crisp anti-aliased result, you'll have to blit it to the screen.

glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
glDrawBuffer(GL_BACK);
glBlitFramebuffer(0, 0, src_width, src_height, 0, 0, dst_width, dst_height, GL_COLOR_BUFFER_BIT, GL_LINEAR);

如果您需要多样本深度缓冲区,请查看 glRenderbufferStorageMultisample() .

If you need a multisample depth buffer then look into glRenderbufferStorageMultisample().

还请确保该glEnable(GL_MULTISAMPLE).但是,今天大多数驱动程序默认情况下都启用它.

Also make sure that glEnable(GL_MULTISAMPLE). However today most drivers enable it by default.

最后但并非最不重要的是,这是您可能会发现有趣的与多重采样有关的其他一些Stack Overflow/Exchange问​​题.

Last but not least, here's a few other Stack Overflow/Exchange question related to multisampling that you might find interesting.

  • Filtering
  • texelFetch() vs texture()
  • Multisample Window Buffer

这篇关于OpenGL-如何绘制到多样本帧缓冲区,然后将结果用作普通纹理?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆