【问题标题】:GLSL - different precision in different parts of fragment shaderGLSL - 片段着色器不同部分的不同精度
【发布时间】:2019-12-26 03:09:30
【问题描述】:

我有一个简单的片段着色器,可以绘制测试网格图案。

我真的没有问题 - 但我注意到一种奇怪的行为,这对我来说是莫名其妙的。不要介意奇怪的常量——它们在编译之前的着色器组装过程中被填充。另外,vertexPosition 是世界空间中实际计算的位置,因此我可以在网格本身移动时移动着色器纹理。

这是我的着色器的代码:

#version 300 es

precision highp float;

in highp vec3 vertexPosition;

out mediump vec4 fragColor;

const float squareSize = __CONSTANT_SQUARE_SIZE;
const vec3 color_base = __CONSTANT_COLOR_BASE;
const vec3 color_l1 = __CONSTANT_COLOR_L1;

float minWidthX;
float minWidthY;

vec3 color_green = vec3(0.0,1.0,0.0);

void main()
{
    // calculate l1 border positions
    float dimention = squareSize;
    int roundX = int(vertexPosition.x / dimention);
    int roundY = int(vertexPosition.z / dimention);
    float remainderX = vertexPosition.x - float(roundX)*dimention;
    float remainderY = vertexPosition.z - float(roundY)*dimention;

    vec3 dyX = dFdy(vec3(vertexPosition.x, vertexPosition.y, 0));
    vec3 dxX = dFdx(vec3(vertexPosition.x, vertexPosition.y, 0));
    minWidthX = max(length(dxX),length(dyX));
    vec3 dyY = dFdy(vec3(0, vertexPosition.y, vertexPosition.z));
    vec3 dxY = dFdx(vec3(0, vertexPosition.y, vertexPosition.z));
    minWidthY = max(length(dxY),length(dyY));


    //Fill l1 suqares
    if (remainderX <= minWidthX)
    {
        fragColor = vec4(color_l1, 1.0);
        return;
    }

    if (remainderY <= minWidthY)
    {
        fragColor = vec4(color_l1, 1.0);
        return;
    }

    // fill base color
    fragColor = vec4(color_base, 1.0);
    return;
}

因此,使用此代码一切正常。 然后我想通过在绘制垂直线之后移动仅涉及水平线的计算来对其进行一点优化。因为如果垂直线检查为真,这些计算将毫无用处。像这样:

#version 300 es

precision highp float;

in highp vec3 vertexPosition;

out mediump vec4 fragColor;

const float squareSize = __CONSTANT_SQUARE_SIZE;
const vec3 color_base = __CONSTANT_COLOR_BASE;
const vec3 color_l1 = __CONSTANT_COLOR_L1;

float minWidthX;
float minWidthY;

vec3 color_green = vec3(0.0,1.0,0.0);

void main()
{
    // calculate l1 border positions
    float dimention = squareSize;
    int roundX = int(vertexPosition.x / dimention);
    int roundY = int(vertexPosition.z / dimention);
    float remainderX = vertexPosition.x - float(roundX)*dimention;
    float remainderY = vertexPosition.z - float(roundY)*dimention;

    vec3 dyX = dFdy(vec3(vertexPosition.x, vertexPosition.y, 0));
    vec3 dxX = dFdx(vec3(vertexPosition.x, vertexPosition.y, 0));
    minWidthX = max(length(dxX),length(dyX));

    //Fill l1 suqares
    if (remainderX <= minWidthX)
    {
        fragColor = vec4(color_l1, 1.0);
        return;
    }

    vec3 dyY = dFdy(vec3(0, vertexPosition.y, vertexPosition.z));
    vec3 dxY = dFdx(vec3(0, vertexPosition.y, vertexPosition.z));
    minWidthY = max(length(dxY),length(dyY));

    if (remainderY <= minWidthY)
    {
        fragColor = vec4(color_l1, 1.0);
        return;
    }

    // fill base color
    fragColor = vec4(color_base, 1.0);
    return;
}

但即使看起来这不应该影响结果 - 它确实。差一点。 下面是两张截图。第一个是原始代码,第二个是“优化”的。哪个效果不好。

原版:

优化版(看起来差很多):

请注意线条是如何变得“模糊”的,即使看起来根本没有数字应该改变。

注意:这不是因为 minwidthX/Y 是全局的。我最初通过使它们本地化来进行优化。 我最初也将RoundY和remainderY的计算移到了X检查的下方,结果是一样的。

注意 2:我尝试专门为每个计算添加 highp 关键字,但这并没有改变任何东西(不是我期望的那样,但我还是尝试了)

谁能解释一下为什么会这样?我想知道我未来的着色器,实际上我也想优化这个。我想在这里了解精度损失背后的原理,因为它对我来说没有任何意义。

【问题讨论】:

标签: opengl-es glsl shader precision fragment-shader


【解决方案1】:

答案我会参考OpenGL ES Shading Language 3.20 Specification,在这一点上和OpenGL ES Shading Language 3.00 Specification是一样的。

8.14.1。导数函数

[...] 在非统一控制流中未定义导数。

还有更多

3.9.2。统一和非统一控制流

在片段着色器中执行语句时,控制流以统一控制流开始;所有片段都进入 main() 中的相同控制路径。当不同的片段通过控制流语句(选择、迭代和跳转)采用不同的路径时,控制流变得不统一。[...]

这意味着,在第一种情况下(您的问题)的导数函数的结果是明确定义的。

但在第二种情况下却不是:

if (remainderX <= minWidthX)
{
   fragColor = vec4(color_l1, 1.0);
   return;
}

vec3 dyY = dFdy(vec3(0, vertexPosition.y, vertexPosition.z));
vec3 dxY = dFdx(vec3(0, vertexPosition.y, vertexPosition.z));

因为return 语句就像一个选择。并且带有return语句的代码块之后的所有代码都处于非统一控制流中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-01-02
    • 1970-01-01
    • 1970-01-01
    • 2019-03-31
    • 2017-04-12
    • 1970-01-01
    • 2013-11-13
    相关资源
    最近更新 更多