WebGL 片段着色器中奇怪的浮点运算

发布于 2024-10-08 19:33:57 字数 1538 浏览 8 评论 0原文

我正在编写一个简单的 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.RGBgl.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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

氛圍 2024-10-15 19:33:57

也许它没有使用浮动。

试试这个:

float xa = 1.01; //then change to 0.99
float xb = 1.0;
float xc = 2.0;
if (xa * xb > xc)
    ...

这有帮助吗?如果是这样,也许编译器(或硬件)出于某种原因将它们转换为 int 。

Maybe it isn't using floats.

Try this:

float xa = 1.01; //then change to 0.99
float xb = 1.0;
float xc = 2.0;
if (xa * xb > xc)
    ...

Does that help? If so, maybe the compiler (or hardware) is converting them to int for some reason.

逆蝶 2024-10-15 19:33:57

您应该将着色器精简到尽可能小的情况。

if( 1.0*2.0 > 1.1 ) gl_FragData[0] = vec4(1,0,0,1);
else gl_FragData[0] = vec4(1,0,1,1);

以及

if( 0.999999*2.0 > 1.1 ) gl_FragData[0] = vec4(1,0,0,1);
else gl_FragData[0] = vec4(1,0,1,1);

需要添加多少个 9 才能触发该错误?只用0.9还会出现这种情况吗?

完成此操作后,使用该代码报告 Chrome 或 Firefox 的错误(它们使用相同的 GLSL 解析器)。解析具有太多有效数字的常量时完全有可能存在错误。

You should strip down the shader to the smallest possible case.

if( 1.0*2.0 > 1.1 ) gl_FragData[0] = vec4(1,0,0,1);
else gl_FragData[0] = vec4(1,0,1,1);

and

if( 0.999999*2.0 > 1.1 ) gl_FragData[0] = vec4(1,0,0,1);
else gl_FragData[0] = vec4(1,0,1,1);

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文