【问题标题】:how to make opengl mipmaps sharper?如何使opengl mipmaps更清晰?
【发布时间】:2011-08-24 18:20:01
【问题描述】:

我正在重写一个基于 opengl 的 gis/mapping 程序。除其他外,该程序允许您加载海图的光栅图像,将它们固定到经度/纬度坐标,并在它们上进行缩放和平移。

该程序的先前版本使用自定义平铺系统,实质上它手动创建原始图像的 mipmap,以 256x256 像素的平铺形式在各种二次方缩放级别。缩放级别为 n - 1 的图块由缩放级别 n 的四个图块构建而成,使用简单的四点平均算法。因此,它关闭了 opengl mipmapping,而是在需要以某个缩放级别绘制图表的某些部分时,它使用最接近匹配缩放级别的图块(即图块处于二次方缩放级别,但程序允许任意缩放级别)然后缩放图块以匹配实际缩放级别。当然,它还必须在各个级别管理所有这些切片的缓存。

在我看来,这个平铺系统过于复杂。看起来我应该能够让图形硬件为我完成所有这些 mipmapping 工作。所以在新程序中,当我读入一张图片时,我将它切成每个 1024x1024 像素的纹理。然后我将每个纹理固定到它的 lon/lat 坐标,然后在我缩放和平移时让 opengl 处理其余部分。

它有效,但问题是:我的结果比原始程序有点模糊,这对这个应用程序很重要,因为您希望能够尽早阅读图表上的文本,放大。因此,就清晰度而言,原始程序使用的简单四点平均算法似乎比 opengl + 我的 GPU 提供了更好的结果。

我知道有几个 glTexParameter 设置可以控制 mipmap 工作的某些方面。我已经尝试了 GL_TEXTURE_MAX_LEVEL(从 0 到 10 的任意位置)与 GL_TEXTURE_MIN_FILTER 的各种设置的各种组合。当我将 GL_TEXTURE_MAX_LEVEL 设置为 0(无 mipmap)时,我当然会得到“锐利”的结果,但它们锐利,因为像素只是在这里和那里掉落,所以数字在中间变焦。当我将 GL_TEXTURE_MAX_LEVEL 设置为更高的值时,当您拉远时(例如,当整个图表适合屏幕时),图像看起来非常好,但是当您放大到中间缩放时,您会注意到模糊,尤其是在查看时图表上的文字。 (即,如果不是文本,您可能会认为“哇,opengl 在平滑缩放我的图像方面做得很好。”但是对于文本,您会认为“为什么这张图表失焦了?”)

我的理解是,基本上你告诉 opengl 生成 mipmap,然后在放大时选择要使用的适当 mipmap,并且在两个最接近的 mipmap 级别之间进行插值有一些有限的选项,或者使用最接近的像素或平均附近的像素。但是,正如我所说,在图表上相同的缩放级别下,这些组合似乎都没有给出非常清晰的结果(即,文本很小但不是微不足道的缩放级别,例如相当于“7 点”或“ 8 点”大小),与之前基于图块的版本一样。

我的结论是,opengl 创建的 mipmap 比之前使用平均四点算法创建的程序更模糊,并且无论选择正确的 mipmap 或 LINEAR vs NEAREST 都不会获得我的清晰度需要。

具体问题

(1) 与原始程序中的平均四点算法相比,opengl 实际上制作的 mipmap 看起来是否正确?

(2) 在使用 glTexParameter 时,我是否可能忽略了一些可以使用 opengl 正在制作的 mipmap 提供更清晰结果的东西?

(3) 有什么方法可以让 opengl 首先制作更清晰的 mipmap,例如使用“立方”过滤器或以其他方式控制 mipmap 创建过程?或者就此而言,我似乎可以使用相同的平均四点代码来手动生成 mipmap 并将它们交给 opengl。但我不知道该怎么做...

【问题讨论】:

  • 从纹理坐标到像素的映射有点棘手。想象每个像素都是一个小方块。纹理坐标 0 和 1 不会击中中心的边界像素,但会击中边界。因此,通过对纹理内容进行简单的、基于像素的寻址,您可能会恰好到达像素之间的中间位置,从而引入一些“模糊”。
  • this。此外,您似乎正在使用描述中的 GL_GENERATE_MIPMAP 。虽然可能相同,但使用 EXT_FRAMEBUFFER_OBJECT 的 glGenerateMipmap 可能值得一试。如果着色器是一个选项,您可以使用硬件加速进行自己的 mip 过滤。最后,如果将文本标签与地形数据分开是一种可能的选择,您也可以这样做(例如,使用基于距离图的算法显示标签,该算法在所有放大倍率下都提供非常好的抗锯齿结果)。

标签: opengl gis mipmaps blurry


【解决方案1】:

回答你的具体点,你提到的四点过滤相当于box-filtering。这比高阶过滤器不那么模糊,但会导致混叠模式。最好的过滤器之一是 Lanczos 过滤器。我建议您使用 Lanczos 过滤器从基础纹理计算所有 mipmap 级别,并在显卡上提高各向异性过滤设置。

我假设原始代码本身管理纹理,因为它旨在查看太大而无法放入图形内存的数据集。这在过去可能是一个更大的问题,但仍然是一个问题。

【讨论】:

  • 好吧,这个程序实际上不需要读取如此大的图像(即,整个图像无法放入当前的图形内存中)。在这种情况下,缓存代码给代码库增加了很多复杂性和神秘性,因此简化代码有一个直接的实际原因。但是你的观点很好,一般来说,如果你想支持任意图像大小,你需要自己做一些缓存。
  • 对不起。我一定过得很糟糕。当我感到沮丧时,我不应该对问题发表评论,因为我正在尝试为自己的问题找到答案。
【解决方案2】:

(1) 似乎不太可能;我希望它只是使用一个盒子过滤器,平均四点有效。可能只是在不同的时刻从一种纹理切换到更高分辨率的纹理——例如它“选择最接近纹理像素大小的 mipmap”,因此将使用 256x256 贴图来纹理 383x383 区域,而它所替代的手动系统可能总是从 512x512 缩小到目标大小为 256x256或更少。

(2) 不是我在基本 GL 中知道的,但是如果您要切换到 GLSL 和可编程管道,那么如果问题是较低分辨率的贴图是当你不想要它时被使用。同样,GL_EXT_texture_lod_bias 扩展可以在固定管道中执行相同的操作。这是十年前的 NVidia 扩展,是所有可编程卡都可以做到的,所以你很有可能拥有它。

(编辑:更彻底地阅读扩展,纹理偏差在 1.4 版中迁移到 OpenGL 的核心规范中;显然我的手册页非常过时。检查 1.4 spec,第 279 页,您可以提供 GL_TEXTURE_LOD_BIAS)

(3) 是的——如果你禁用 GL_GENERATE_MIPMAP,那么你可以使用 glTexImage2D 为每个比例级别提供你喜欢的任何图像,这就是“级别”参数的规定。因此,如果需要,您可以提供完全不相关的 mip 贴图。

【讨论】:

  • 感谢您的快速回复。啊哈! "level" 参数是关键,所以现在我知道你可以使用 glTexImage2D 来提供你自己的 mipmap。如果它增加了清晰度,我会尝试并报告。作为一个后续问题,如果您为某个级别的 opengl 使用它提供 mipmap,并且如果您不提供它,它会为您生成一个(直到指定的最大 mipmap),它的工作方式是什么?它是预先生成这些 mipmap,还是仅在实际需要时生成?
  • 虽然如果你对问题(1)说的是真的,我似乎注定要失败。虽然如果你对问题 (2) 所说的是真的,我不一定注定要失败,但可能会做很多事情或工作......或者实际上,也许在 (3) 中,通过提供对于给定级别来说太大的 mipmap我也能达到同样的效果???
  • @M Katz:OpenGL 在早期版本中没有生成 mip 贴图,因此 glu 方法会在每个级别自动缩放和上传纹理。所以我认为默认的是GL什么都不做。 GL_GENERATE_MIPMAP 在 0 级上传时生成新的 mip 贴图,它在 3.0 中的替代品是 glGenerateMipmap,它仅根据命令生成 mip 贴图。因此,无论哪种方式,您都必须推动 GL 生成 mip 贴图。假设我对 (1) 的猜测是正确的,您应该能够按照我的编辑使用 GL_TEXTURE_LOD_BIAS 解决问题。
  • 哇哦!通过在 gl.glTexImage2D() 之前使用 gl.glTexEnvf( gl.GL_TEXTURE_FILTER_CONTROL, gl.GL_TEXTURE_LOD_BIAS, -0.5 ) 可以停止模糊效果。我仍然需要在多个缩放级别上将我的结果与旧程序进行比较,但到目前为止它看起来不错。感谢您的出色诊断。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-06-22
  • 1970-01-01
  • 1970-01-01
  • 2016-06-05
  • 2020-08-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多