Opengl es 必须改变纹理的精度,为什么?

Opengl es 必须改变纹理的精度,为什么?,opengl-es,glsl,shader,Opengl Es,Glsl,Shader,我在片段着色器上做了一些工作,以允许纹理渲染和颜色渲染。在我做了这些更改之后,我所有的纹理都是非常像素化的(就像一个旧的8位游戏),我必须将纹理坐标的精度提升到中等。这也给了我一个性能打击。我只是不明白为什么我一开始就突然改变了精度 以下是“原始”着色器: 以下是着色器在更改后的外观: varying mediump vec2 TexCoordOut; uniform sampler2D Texture; uniform lowp vec4 color; uniform lowp float

我在片段着色器上做了一些工作,以允许纹理渲染和颜色渲染。在我做了这些更改之后,我所有的纹理都是非常像素化的(就像一个旧的8位游戏),我必须将纹理坐标的精度提升到中等。这也给了我一个性能打击。我只是不明白为什么我一开始就突然改变了精度

以下是“原始”着色器:

以下是着色器在更改后的外观:

varying mediump vec2 TexCoordOut;
uniform sampler2D Texture;

uniform lowp vec4 color;
uniform lowp float opacity;
uniform int colorRender;

void main(void) {
    if (colorRender == 1)
    {
        gl_FragColor = color;
    } else {
        gl_FragColor = opacity * texture2D(Texture, TexCoordOut);
    }
}

将分别为每个片段计算纹理坐标。然而,在低精度的情况下,数字在每个片段的基础上进行量化,这意味着许多相邻片段将实际计算到非常相同的量化纹理坐标。原则上,纹理坐标变量的精度必须允许更多的量化步数,而不是采样方向上纹理中的像素/texel数。

lowp
的最小精度只有大约8位,因此如果纹理为128x128或更大,您将开始看到瑕疵,如果你的纹理大于256x256,一些纹理将完全丢失(你描述的严重像素化)

mediump
的精度至少为11位,因此最高可达1024x1024 texel(虽然是浮点类型,但如果纹理坐标未标准化,则可以获得像素化)

highp
的最小精度为24位(与IEEE单精度浮点相同),因此更好


请注意,根据规范,这些精度都是最低值——如果硬件速度更快,它们中的任何一个都可能会使用更高的精度。

您将性能损失归咎于切换到mediump,但也为着色器添加了分支。考虑到单个绘制调用的每个片段都将始终采用相同的路径,您应该有两个不同的着色器,每个着色器都没有分支。

性能影响与mediump无关。iOS上的lowp甚至比mediump更慢。分支很慢。int是慢的。@Jessy:lowp永远不应该比mediump慢(除非驱动程序坏了),因为驱动程序/硬件可以自由地使用更高的精度,如果它愿意的话(如果它可以更快的话,它应该)。该规范仅规定了最低精度要求。如果需要,可以称之为“断开”。我肯定会承认,缺乏关于驾驶员的文档是垃圾:“许多内置功能使用中等精度的输入和输出。如果应用程序提供低精度浮点值作为参数,或将结果指定给低精度浮点变量,则着色器可能必须包含其他指令来转换值。“@Jessy-lowp在许多情况下确实可以在iOS上运行得更快,尤其是在向量操作上。我见过一些案例,其中我使用lowp比mediump实现了近一个数量级的改进,但这是您几乎需要在个案基础上分析的内容。谢天谢地,在测试时很容易改变精度。我并不是说lowp在几乎所有情况下都不是碎片着色器计算的最快选项。它是。我是说,在非依赖纹理坐标中使用它是毫无意义的。是的,片段着色器中的分支对iOS上的性能有巨大影响。拆分成两个着色器程序是实现这一点的方法。哦,我没有意识到这一点。所以我只需要创建一个像旧的一样的着色器,并且只为颜色创建一个着色器,然后在不同的场景中调用不同的着色器?我现在实现了两个不同的着色器程序。这给了我一点性能提升。所以我想它起作用了。谢谢你的提示@jesusgumbau:问题在于纹理坐标上的精度限定符,而不是texel上的精度限定符。因此纹理的大小是非常相关的,而texel位深度是不相关的。
varying mediump vec2 TexCoordOut;
uniform sampler2D Texture;

uniform lowp vec4 color;
uniform lowp float opacity;
uniform int colorRender;

void main(void) {
    if (colorRender == 1)
    {
        gl_FragColor = color;
    } else {
        gl_FragColor = opacity * texture2D(Texture, TexCoordOut);
    }
}