如何在WebGL/WebGL2着色器中禁用使用统一体的浮点算术优化

如何在WebGL/WebGL2着色器中禁用使用统一体的浮点算术优化,webgl,shader,fragment-shader,webgl2,Webgl,Shader,Fragment Shader,Webgl2,我正在尝试在基于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;

我正在尝试在基于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中的类似问题上也存在类似的stackoverflow问题 建议在函数“split”中使用“precise”修饰符。不幸的是,在WebGL/WebGL2着色器中没有此类修改器


你有什么建议吗?在我的例子中,如何摆脱优化并实现“拆分”功能?

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

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
因为精度错误。当您使用uniform时,编译器采用了优化表达式的路径,该表达式生成了数学上严格的零

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

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

}
另一方面,
highp
不能保证WebGL着色器中的32位浮点。根据硬件的不同,它可能是24位浮点,甚至16位浮点,这是由于回退到mediump(如果片段着色器中不支持highp)。查看您可以使用的实际精度
gl.getShaderPrecisionFormat


如果在片段着色器中指定highp,则会在片段着色器中获得highp,否则将无法编译。它自动回退到mediump是违反规范的。相反,如果你指定了mediump,你可能会得到highp。顺便说一句,在webgl2中,highp浮点值保证为32位。至少在GLES 2.0中,Mali 4xx GPU(目前唯一重要的mediump卡)的驱动程序会自动返回mediump,而不会出现错误,不管规格如何。我还没有尝试过WebGL,但我怀疑也可能是这样。