Лучший способ обнаружить NaN в шейдерах OpenGL - PullRequest
17 голосов
/ 25 февраля 2012

Сегодня утром я натолкнулся на то, что казалось загадочной ошибкой, и мне очень повезло, что я довольно быстро наткнулся на решение.

Я делил на счетчик, чтобы получить среднее значение внутри фрагментного шейдера, и, конечно, когда счетчик равен нулю, результирующее значение цвета становится NaN.

Во время смешивания NVidia изящно обрабатываетNaN как значение 0, но Intel не делает и, по-видимому, каскадирует NaN, что приводит к появлению черных фрагментов.

И эта ошибка сохранялась, пока я не протестировал код на машине Intel.

Интересно, можно ли что-нибудь сделать, чтобы "перехватить" недопустимые значения.Кажется, что, как и в обычном программировании, единственный надежный (и даже тогда не чувствующий себя пуленепробиваемым) способ справиться с этим - тщательно рассмотреть все возможные случаи при делении чисел.

Стандартный способОбнаружить NaN означает, что число не равно самому себе.Могу ли я, возможно, построить отладочный шейдер, который проверяет каждый фрагмент, чтобы определить, не равен ли он сам себе, и, если это условие выполнено, установить мигающий, бросающийся в глаза цвет?Позволяет ли GLSL мне обнаруживать NaN таким образом, или я застреваю с неопределенным поведением всякий раз, когда значение недопустимо?

Ответы [ 2 ]

20 голосов
/ 25 февраля 2012

Я делил на счетчик, чтобы получить среднее значение внутри фрагментного шейдера, и, конечно, когда счетчик равен нулю, полученное значение цвета стало NaN.

Это не так, как работают поплавки. Когда вы делите на ноль, вы получаете INF , а не NaN. Если числитель также не равен нулю, в этом случае вы получаете NaN.

В любом случае GLSL предлагает функции isinf и isnan, которые выполняют то, что говорят.

6 голосов
/ 14 декабря 2015

Отсутствие isnan является проблемой для WebGL и Opengl ES 2.0.Polyfill, который работает для всех графических процессоров, у меня была возможность попробовать:

bool isnan( float val )
{
  return ( val < 0.0 || 0.0 < val || val == 0.0 ) ? false : true;
  // important: some nVidias failed to cope with version below.
  // Probably wrong optimization.
  /*return ( val <= 0.0 || 0.0 <= val ) ? false : true;*/
}
...