为什么在片段着色器中无法访问纹理 lod

Why no access to texture lod in fragment shader

我正在尝试了解 OpenGL ES 2.0 片段着色器中 mipmapped 纹理的细节级别。

根据this answer it is not possible to use the bias parameter to texture2D to access a specific level of detail in the fragment shader. According to this post,详细程度是根据相邻片段的并行执行自动计算的。我必须相信这就是事情的运作方式。

我无法理解的是为什么为什么 无法访问特定级别的详细信息,而这样做确实应该非常简单? 为什么 必须依赖复杂的固定功能?

对我来说,这似乎非常违反直觉。毕竟,整个 OpenGL 相关的东西都是从固定功能发展而来的。并且 OpenGL ES 旨在涵盖比 OpenGL 更广泛的硬件范围,因此仅支持许多事物的简单版本。因此,如果规范的开发人员决定 LOD 参数是强制性的(可能默认为零),并且由着色器程序员以他认为合适的任何方式计算出合适的 LOD,我将完全理解。添加一个自动执行该计算的函数似乎是我在桌面 OpenGL 中所期望的。

不提供对特定级别的直接访问对我来说根本没有任何意义,无论我怎么看。特别是因为 bias 参数表明我们确实可以调整细节级别,所以显然这不是关于为并行处理的一堆片段的单个级别从内存中获取数据。我想不出任何其他原因。


当然,为什么问题往往会吸引意见。但由于 Stack Overflow 不接受基于意见的答案,请 post 您的意见仅作为评论。另一方面,答案应该基于可验证的事实,例如具有明确知识的人的陈述。如果有开发者讨论这个事实的记录,那就完美了。如果里面有人发博客post讨论这个问题,那还是很好的。

由于 Stack Overflow 问题应该处理真正的编程问题,有人可能会争辩说询问原因是一个糟糕的问题。获得答案不会使显式 lod 访问突然出现,因此不会帮助我解决眼前的问题。但我觉得这里的原因可能是由于 OpenGL ES 如何工作的一些重要方面,我到目前为止还没有掌握。如果是这样的话,那么理解这个决定背后的动机将帮助我和其他人更好地理解整个 OpenGL ES,从而在他们的程序中更好地利用它,在性能、准确性、可移植性等方面.因此,我可能会把这个问题表述为“我错过了什么?”,这对我来说是一个非常真实的编程问题。

texture2DLod (...) 在顶点着色器纹理查找中起着非常重要的作用,这在片段着色器中不是必需的。

当在片段着色器中进行纹理查找时,片段着色器可以访问当前正在着色的图元的每个属性梯度(偏导数,例如 dFdx (...)dFdy (...)),并且它使用此信息来确定在过滤期间从哪个 LOD 中获取相邻的纹素。

在顶点着色器 运行 的时候,没有关于基元的信息是已知的,也没有这样的梯度。在顶点着色器中使用 mipmap 的唯一方法是显式获取特定的 LOD,这就是引入该功能的原因。

桌面版 OpenGL 更智能地解决了这个问题,它为顶点着色器提供了一种纹理查找变体,它实际上将渐变作为其输入之一。该函数称为 textureGrad (...),它是在 GLSL 1.30 中引入的。 ESSL 1.0 源自 GLSL 1.20,并没有受益于所有相同的基本硬件功能。

ES 3.0 没有这个限制,桌面 GL 3.0 也没有。当显式 LOD 查找被引入桌面 GL (3.0) 时,它可以从任何着色器阶段完成。这可能只是一个疏忽,或者可能存在一些基本的硬件限制(回想一下,旧的 GPU 曾经有专门的顶点和像素着色器硬件,而嵌入式 GPU 从来没有处于 GPU 设计的前沿)。


无论此限制的最初原因是什么,它已在后来的 OpenGL ES 2.0 扩展中得到纠正,并且是 OpenGL ES 3.0 的核心。在给定以下扩展的情况下,现代 GL ES 2.0 实现实际上很可能支持片段着色器中的显式 LOD 查找:

GL_EXT_shader_texture_lod

显示片段着色器中显式 LOD 查找的伪代码:

#version 100
#extension GL_EXT_shader_texture_lod : require

attribute vec2      tex_st;
uniform   sampler2D sampler;

void main (void)
{
  // Note the EXT suffix, that is very important in ESSL 1.00
  gl_FragColor = texture2DLodEXT (sampler, tex_st, 0);
}