2012-02-25 8 views
13

Me encontré con lo que parecía un misterioso error esta mañana y me siento muy afortunado de haber tropezado con una solución muy rápidamente.La mejor manera de detectar NaN en sombreadores OpenGL

Estaba dividiendo por un contador para producir un promedio dentro de un sombreador de fragmentos, y por supuesto cuando el contador es cero, el valor de color resultante se convirtió en NaN.

Durante la mezcla, NVidia trata con gracia un NaN como un valor de 0, pero Intel no lo hace y parece que conecta en cascada el NaN, lo que produce fragmentos negros.

Y este error persistió hasta que probé el código en una máquina Intel.

Me pregunto si hay algo que podría hacer para "atrapar" los valores no válidos. Parece que, al igual que en la programación regular, la única forma infalible (y aun así no se siente a prueba de balas) de tratar con esto es considerar cuidadosamente todos los casos posibles al dividir los números.

La forma estándar de detectar un NaN es ver si un número no es igual a él. ¿Podría quizás construir un sombreador de depuración que verifique cada fragmento para ver si no es igual a él mismo, y si se cumple esa condición, establezca un color intermitente y llamativo? ¿GLSL me permite detectar un NaN de esta manera o me quedo con un comportamiento indefinido cuando un valor no es válido?

+0

¿Por qué se divide por 0 en total? ¿No puedes ver que el contador es 0 o cambiar tu algoritmo? – djmj

+2

Es razonable que un programador siempre compruebe si un denominador potencial podría ser cero, pero la comprobación podría generar un costo de rendimiento. Mi pregunta está relacionada con la detección de valores incorrectos después del hecho. –

Respuesta

16

Estaba dividiendo por un contador para producir un promedio dentro de un sombreador de fragmentos, y por supuesto cuando el contador es cero, el valor de color resultante se convirtió en NaN.

Así no es como funcionan las carrozas. Cuando divide por cero, obtiene INF, no NaN. A menos que el numerador también sea cero, en cuyo caso obtienes NaN.

En cualquier caso, GLSL ofrece las funciones isinf y isnan, que hacen lo que dicen.

+0

Ah. Eso es muy conveniente. Resulta que eran NaN ya que el numerador siempre sería cero si el denominador lo fuera. –

3

La falta de isnan es un problema para WebGL y OpenGL ES 2.0. Polyfill que funciona para todas las GPU que tuve la oportunidad de probar:

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;*/ 
} 
+1

[OpenGL ES GLSL 3+ tiene 'isnan'] (https://www.khronos.org/opengles/sdk/docs/man31/). –

+1

Gran información, gracias chicos –

+1

NVIDIA no puede hacer frente a esto debido a su optimizador muy agresivo. – Ruslan

Cuestiones relacionadas