如何在WebGL / WebGL2着色器中禁用使用浮点运算的优化

问题描述 投票:1回答:1

我正在尝试基于32位浮点数在WebGL或WebGL2着色器上实现64位算术。需要的基本功能之一是将任何浮点数分成两个“非重叠”浮点的功能。第一个浮点数包含原始浮点数的小数位的前一半,第二个浮点数包含第二半数。这是此功能的实现:

precision highp float;
...
...
vec2 split(const float a)
{
  const float split = 4097.0; // 2^12 + 1
  vec2 result;
  float t = a * split; // almost 4097 * a
  float diff = t - a; // almost 4096 * a
  result.x = t - diff; // almost a
  result.y = a - result.x; //very small number 
  return result;
}

如果我将其传递给着色器中定义的参数,则该函数将按预期工作:

precision highp float;
...
...  
float number = 0.1;
vec2 splittedNumber = split(number);
if (splittedNumber.y != 0.0)
{
    // color with white    
    // we step here and see the white screen
}
else
{
   //color with black
}

但是只要数字以某种方式取决于任何制服,一切就会开始表现出不同:

precision highp float;
uniform float uniformNumber;
...
...
float number = 0.2;
if (uniformNumber > 0.0)    
{
  // uniform number is positive, 
  // so we step here
  number = 0.1;  
}  

vec2 splittedNumber = split(number);
if (splittedNumber.y != 0.0)
{
    // color with white    
}
else
{
   //color with black
   // we step here and see the black screen
}

因此,在第二种情况下,当“数字”取决于制服时,分割函数以某种方式得到优化,并以零y值返回vec2。

关于OpenGL Differing floating point behaviour between uniform and constants in GLSL中类似问题的stackoverflow也有类似问题。建议在函数“ split”中使用“ precise”修饰符。不幸的是,在WebGL / WebGL2着色器中没有这样的修改器。

您有任何建议如何摆脱我的情况下的优化并实现“拆分”功能吗?

webgl shader fragment-shader webgl2
1个回答
0
投票

从数学上讲,两个示例都应输出黑色像素。因为:

float diff = t - a;
result.x = t - diff; // t - diff = t - t + a = a
result.y = a - result.x; // a - a = 0

[可能是split()的常量参数(预先知道的值)的情况,编译器在优化表达式之前采用了计算函数的路径,由于精度错误,您得到了splittedNumber.y != 0.0。当您使用统一时,编译器会采用优化表达式的方式,该表达式产生数学上严格的零。

要验证是否是这种情况,您可以尝试以下比较:

if(abs(splittedNumber.y) > 1e-6)
{

}

附带说明,highp不保证WebGL Shaders中的32位浮点数。取决于硬件,由于回退到mediump(如果不支持highp),它可能是24位浮点数甚至是16位。要查看实际精度,可以使用gl.getShaderPrecisionFormat

https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/getShaderPrecisionFormat

© www.soinside.com 2019 - 2024. All rights reserved.