【问题标题】:How to achieve downsampling AA/filtering in OpenGL如何在OpenGL中实现下采样AA/过滤
【发布时间】:2014-05-07 19:27:41
【问题描述】:

我正在开发一款使用像素艺术的游戏和一个与像素艺术大小不一一匹配的相机。为了使像素看起来像像素,我想以更高的分辨率渲染整个游戏,然后将其下采样到实际的窗口分辨率(类似于黑暗之魂 2 中的 GeDoSaTo 模组所做的),并在游戏中简单地使用最近的过滤纹理作为 mag 过滤器。如何在代码中进行这种下采样?

【问题讨论】:

  • 为什么不在shazzam-tool.com 中使用像Pixelate.fx 这样的着色器?
  • 最近的过滤会让你回到第一格。如果您以比显示器高于的分辨率进行渲染,然后使用点采样(最近邻)对其进行采样,实际上会引入大量高频噪声。这正是创建 mipmap 的原因。
  • 我的意思是,在游戏中对纹理使用最近过滤(作为 mag 过滤器),同时正确过滤更高分辨率的渲染结果。我将更新问题以使其更清楚。
  • 再一次,你认为这一切都错了。您想要做的是使用 linear 过滤将过采样颜色缓冲区传输到默认帧缓冲区。是否使用glBlitFramebuffer (...) 或绘制纹理四边形取决于您,但您需要线性过滤。如果需要,您可以实现自己的过滤器,例如 bicubic 或 lanczos,但速度会明显变慢。
  • 是的,这正是我的意思。我不想对游戏对象上使用的实际纹理使用过滤,但过采样缓冲区当然会用于过滤。我需要知道的是如何创建该缓冲区以及如何渲染到该缓冲区而不是默认帧缓冲区。

标签: opengl antialiasing downsampling


【解决方案1】:

我已经为您编写了一些伪代码,展示了如何设置具有维度的 FBO:

  scale * (res_x x res_y)。

        2x 超级采样将使用 2.0 的 scale。

我做了一些额外的工作来为您的颜色缓冲区获取纹理图像附件,以便您可以使用带纹理的四边形(更好的性能)而不是 blitting 来绘制它。但是,由于这样做需要编写一个(简单的)着色器,glBlitFramebuffer (...) 是最快的解决方案。

初始化 FBO 的代码:

GLuint supersample_fbo,
       supersample_tex,
       supersample_rbo_depth;

glGenTextures (1, &supersample_tex);
glBindTexture (GL_TEXTURE_2D, supersample_tex);

glGenRenderbuffers (1, &supersample_rbo_depth);
glBindRenderbuffer (GL_RENDERBUFFER, supersample_rbo_depth);

// Allocate storage for your texture (scale X <res_x,res_y>)
glTexImage2D  (GL_TEXTURE_2D, 0, GL_RGBA8, res_x * scale, res_y * scale, 0, GL_RGBA, GL_FLOAT, NULL);

// Allocate storage for your depth buffer
glRenderBufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, res_x * scale, res_y * scale);

glGenFramebuffers (1, &supersample_fbo);
glBindFramebuffer (GL_FRAMEBUFFER, supersample_fbo);

// Attach your texture to the FBO: Color Attachment 0.
glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, supersample_tex, 0);

// Attach the depth buffer to the FBO.
glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, supersample_rbo_depth);

绘制到 FBO 的代码:

glBindFramebuffer (GL_FRAMEBUFFER, supersample_fbo);

// You need to modify the viewport mapping to reflect the difference in size.
// Your projection matrix can stay the same since everything is uniformly scaled.
//
glViewport        (0, 0, res_x * scale, res_y * scale);

  // DRAW

将 FBO Blit 到默认帧缓冲区的代码:

glBindFramebuffer (GL_READ_FRAMEBUFFER, supersample_fbo); // READ:  Supersampled
glBindFramebuffer (GL_DRAW_FRAMEBUFFER, 0);               // WRITE: Default

// Downsample the supersampled FBO using LINEAR interpolation
glBlitFramebuffer (0,0,res_x * scale, res_y * scale,
                   0,0,res_x,         res_y,
                   GL_COLOR_BUFFER_BIT,
                   GL_LINEAR);

恢复绘制到默认帧缓冲区的代码:

// You probably want all subsequent drawing to go into the default framebuffer...
glBindFramebuffer (GL_FRAMEBUFFER, 0);
glViewport        (0,0,res_x,res_y);

此代码中有很多缺失的错误检查,并且 FBO非常容易出错,但它应该可以让你找到正确的方向。

【讨论】:

  • 关于这个的一个问题,如果我不使用深度测试(在 2D 游戏的情况下),我应该跳过与深度渲染缓冲区相关的所有内容吗?
  • 是的,我在假设您需要深度测试的情况下添加了深度附件。你提到了黑暗之魂,所以我有点明白你在做 3D 渲染;)如果你不需要深度缓冲区,那么删除渲染缓冲区的东西。
  • 是的,但是有一个上限。您需要在运行时查询GL_MAX_TEXTURE_SIZE 的值; res_x * scale 和 res_y * scale 都不能超过这个值。因此,以这种方式完成的最大超级采样量实际上取决于初始分辨率。多重采样将提供更好的性能(它不必为每个额外的样本运行片段着色器)并且可以克服这里的一些大小问题,但会受到超级采样所没有的着色器/纹理混叠的影响。
  • 对于高于 2 倍的采样,我是否必须多次通过,每次 2 倍,或者我可以简单地将比例更改为更高?在将其提高到 2 倍以上后,我得到了一些看起来不正确的结果。
  • 问题的截图,4x 似乎比 2x 锯齿状更多: 2x: i.imgur.com/YNvtJVE.png 4x: i.imgur.com/5080lYY.png
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-03-19
  • 1970-01-01
  • 1970-01-01
  • 2022-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多