Странная арифметика с плавающей точкой в ​​фрагментном шейдере WebGL - PullRequest
1 голос
/ 18 декабря 2010

Я пишу простую программу WebGL. Я застрял со странным поведением в шейдерной программе:

условие ( 1.01 * 2.0 > 1.0 ) оценивается как истинное, но состояние ( 0.99 * 2.0 > 1.0 ) оценивается как вспышка

Каждый раз, когда я умножаю число меньше 1.0 на что-то другое, я получаю число меньше 1.0

Почему это так?

[EDIT]

Я использую фрагментный шейдер для изменения 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. Я полагаю, что я ничего не понимаю в арифметике с плавающей запятой.

Ответы [ 2 ]

2 голосов
/ 23 декабря 2010

Возможно, он не использует поплавки.

Попробуйте это:

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

Это помогает? Если это так, возможно, по какой-то причине компилятор (или оборудование) преобразует их в int.

1 голос
/ 16 июня 2013

Вы должны раздеть шейдер до наименьшего возможного случая.

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).Вполне возможно, что в синтаксическом анализе констант есть слишком много значащих цифр.

...