如何在WebGL/WebGL2着色器中禁用使用统一体的浮点算术优化
我正在尝试在基于32位浮点的WebGL或WebGL2着色器上实现64位算术。需要的基本函数之一是将任意浮点数拆分为两个“非重叠”浮点数的函数。第一个浮点包含原始浮点分数位的前一半,第二个浮点包含后一半。以下是此功能的实现:如何在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;
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,但我怀疑也可能是这样。