着色器 - 使用高值分割时出现意外行为

时间:2018-03-05 08:29:33

标签: opengl-es glsl shader

我有这一行:

gl_FragColor = vec4(worldPos.x / maxX, worldPos.z / maxZ, 1.0, 1.0);

worldPos.x和worldPos.y从0到19900.maxX和maxZ是浮动制服。当maxX和maxZ设置为5000.0(渐变为白色,高于5000,全部为白色)时,它按预期工作,但当maxX和maxZ设置为19900.0时,它全部变为蓝色。为什么这样以及如何绕过它?对这些值进行硬编码并没有什么区别,即:

gl_FragColor = vec4(worldPos.x / 5000.0, worldPos.z / 5000.0, 1.0, 1.0);

按预期工作:

gl_FragColor = vec4(worldPos.x / 19900.0, worldPos.z / 19900.0, 1.0, 1.0);

全部变成蓝色。这只发生在某些设备上而不是其他设备上。

更新

添加highp修饰符(如下面的迈克尔所建议)解决了一个设备的问题,但是当测试另一个设备时,它没有任何区别。然后我尝试在CPU上进行除法(也由Michael建议):

在java中,在将它作为统一传递之前:

float maxX = 1.0f / 19900.0f;
float maxZ = 1.0f / 19900.0f;
program.setUniformf(maxXUniform, maxX);
program.setUniformf(maxZUniform, maxZ);
着色器中的

uniform float maxX;
uniform float maxZ;

...
gl_FragColor = vec4(worldPos.x * maxX, worldPos.z * maxZ, 1.0, 1.0);
...

最后的闷闷不乐:

这仍然没有削减它。现在这些值太小了,因此当传入着色器时,由于浮点精度太低,它们会变为0。然后我尝试将它乘以100然后传入,然后在着色器内将其乘以0.01。

在java中:

float maxX = 100.0f / 19900.0f;
float maxZ = 100.0f / 19900.0f;
program.setUniformf(maxXUniform, maxX);
program.setUniformf(maxZUniform, maxZ);
着色器中的

uniform float maxX;
uniform float maxZ;

...
gl_FragColor = vec4(worldPos.x * 0.01 * maxX, worldPos.z * 0.01 * maxZ, 1.0, 1.0);
...

这解决了这个问题。现在不需要highp修饰符。也许这不是最漂亮的闷热,但它有效而且健壮。

1 个答案:

答案 0 :(得分:2)

我猜你在运行OpenGL ES?嗯,浮动精度很多,通常是相当古老的设备。在移动硬件着色器中实现级联阴影映射时,我有过几次类似的问题。

确保对这些变量使用highp限定符。 (注意 - 这可能无法解决问题,但值得尝试)

另一种可能的解决方案:不要在着色器中执行除法。无论如何,对于许多旧的和弱的实现来说,这是一个非常繁重的操作。尽量避免使用division,sqrt(),pow()。运行着色器分析器,你会惊讶地发现那些操作是多么重要! (Mac上的iOS模拟器有一个很好的着色器分析器)尝试直接将结果作为uniforms传递。我不确定在你的情况下会出现问题,因为我看不到任何这些变量绑定到每个片段的执行。

如果它仍然没有帮助,那么通常你无能为力。这是旧的硬件/ GLSL实现问题。但我相信,如果你在CPU上计算并将结果作为制服上传,那应该可以解决问题。