WebGL 片段着色器中奇怪的浮点运算
我正在编写一个简单的 WebGL 程序。我在着色器程序中遇到了奇怪的行为:
条件 ( 1.01 * 2.0 > 1.0 )
计算结果为 true 但 条件 ( 0.99 * 2.0 > 1.0 )
计算结果为 flase
每次我将小于 1.0
的数字乘以其他值时,都会得到小于 1.0
的数字代码>
为什么会这样呢?
[编辑]
我正在使用片段着色器使用窗口级别和窗口高度(线性渐变)将 16 位无符号整数数据更改为 8 位位图并显示在屏幕上。 由于在 WebGL 中没有直接的方法将 16 位数据存储为内部格式(据我所知),我决定创建 Uint8Array(width*height*3),将第一个字节存储在 R 通道中,第二个字节存储在 B 通道中并将其放入 gl.RGB
、gl.UNSIGNED_BYTE
纹理中(也许 LUMINESCANCE_ALPHA
会更好)。
在着色器中,我重建字形式字节并进行调平。 着色器程序:
#ifdef GL_ES
precision highp float;
#endif
uniform highp sampler2D s_texture;
uniform highp float u_ww;
uniform highp float u_wc;
varying highp vec2 v_texcoord;
void main(void)
{
highp vec3 color = texture2D(s_texture, v_texcoord).rgb;
highp float S = 255.;
highp float d = 65280.;
highp float m = 0.9;
highp float c = color.g*d + color.r*S;
float dp = 0.;
float min = u_wc - u_ww/2.;
float max = u_wc + u_ww/2.;
if( 1.0*2.0 > 1.1 ) gl_FragData[0] = vec4(1,0,0,1);
else{
if( c<min ) c=0.;
else if( c>max ) c=255.;
else c=(255.*(max-c))/u_ww;
c = c/S;
gl_FragData[0] = vec4(c,c,c,1);
}
}
如您所见,有一行愚蠢的代码 if( 1.0*2.0 > 1.1 ) gl_FragData[0] = vec4(1,0,0,1);
这是我测试浮点运算的地方。在此示例中,整个图像为红色,但当条件为 0.999999999*2.0 > 时,整个图像为红色。 1.1 答案是错误的。当我在重新采样的 16 位图像中发现奇怪的伪像时,我开始怀疑一些事情。
我在 Chrome 8 和 Firefox 4 上测试了它。我相信我不了解浮点运算。
I'm writing a simple WebGL program. I'm stuck with a strange behavior in a shader program:
condition ( 1.01 * 2.0 > 1.0 )
evaluates to true but
condition ( 0.99 * 2.0 > 1.0 )
evaluates to flase
Every time I multiply a number lesser than 1.0
by something else I get a number lesser than 1.0
Why is it so?
[EDIT]
I'm using a fragment shader to change 16bit unsigned integer data to 8bit bitmap using window level and window hight ( linear ramp ) and display on screen.
Since there are no direct way of storing 16bit data as an internal format in WebGL (AFAIK) I decided to create Uint8Array(width*height*3)
, store first byte in R channel, second in B channel and put it in gl.RGB
, gl.UNSIGNED_BYTE
texture (maybe LUMINESCANCE_ALPHA
would be better).
In shader I reconstruct word form bytes and do the leveling.
The shader program:
#ifdef GL_ES
precision highp float;
#endif
uniform highp sampler2D s_texture;
uniform highp float u_ww;
uniform highp float u_wc;
varying highp vec2 v_texcoord;
void main(void)
{
highp vec3 color = texture2D(s_texture, v_texcoord).rgb;
highp float S = 255.;
highp float d = 65280.;
highp float m = 0.9;
highp float c = color.g*d + color.r*S;
float dp = 0.;
float min = u_wc - u_ww/2.;
float max = u_wc + u_ww/2.;
if( 1.0*2.0 > 1.1 ) gl_FragData[0] = vec4(1,0,0,1);
else{
if( c<min ) c=0.;
else if( c>max ) c=255.;
else c=(255.*(max-c))/u_ww;
c = c/S;
gl_FragData[0] = vec4(c,c,c,1);
}
}
As you can see, there is a stupid line if( 1.0*2.0 > 1.1 ) gl_FragData[0] = vec4(1,0,0,1);
It's place where I test floating point arithmetic. In this example whole image is red, but when the condition is 0.999999999*2.0 > 1.1
the answer is false. I started to suspect something when I got strange artifacts in my resampled 16bit image.
I tested it on Chrome 8 and Firefox 4. I believe I don't understand something about floating point arithmetics.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
也许它没有使用浮动。
试试这个:
这有帮助吗?如果是这样,也许编译器(或硬件)出于某种原因将它们转换为 int 。
Maybe it isn't using floats.
Try this:
Does that help? If so, maybe the compiler (or hardware) is converting them to int for some reason.
您应该将着色器精简到尽可能小的情况。
以及
需要添加多少个 9 才能触发该错误?只用0.9还会出现这种情况吗?
完成此操作后,使用该代码报告 Chrome 或 Firefox 的错误(它们使用相同的 GLSL 解析器)。解析具有太多有效数字的常量时完全有可能存在错误。
You should strip down the shader to the smallest possible case.
and
How many 9s do you need to add to trigger the bug? Does it still happen with just 0.9?
Once you have done that, use that code to report a bug with Chrome or Firefox (they use the same GLSL parser). It's entirely possible that there is a bug in parsing constants with too many significant digits.