Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Problema generando normales GLSL

Iniciado por killgt, 31 de Enero de 2010, 07:10:04 PM

« anterior - próximo »

killgt

Saludos, este es mi primer post en este gran foro y como veo que por aqui hay expertos...

Veréis, estoy generando proceduralmente heightmaps en la GPU. El problema llega a la hora de generar las normales por pixels, que vengo hago con este shader que he escrito:

uniform sampler2D textura;
uniform vec2 tamanoTextura;
uniform float escala;


float altura(vec4 color){
return (0.30*color.x + 0.59*color.y + 0.11*color.z);
}

void main ()
{
vec2 pase = 1.0/tamanoTextura;
vec2 uv = gl_TexCoord[0].st;



vec3 izquierda = vec3(uv.s - pase.x, 0, uv.t );//texture2D(textura, uv + vec2(-pase.x,0.0)).rgb;
vec3 superior = vec3(uv.s , 0, uv.t + pase.y );//texture2D(textura, uv + vec2(0.0,pase.y)).rgb;
vec3 derecha = vec3(uv.s + pase.x, 0, uv.t );// texture2D(textura, uv + vec2(pase.x,0.0)).rgb;
vec3 inferior = vec3(uv.s , 0, uv.t - pase.y );//texture2D(textura, uv + vec2(0.0,-pase.y)).rgb;
vec3 actual = vec3(uv.s , 0, uv.t );


izquierda.y = altura( texture2D( textura, uv + vec2(-pase.x, 0.0) ) );
superior.y = altura( texture2D( textura, uv + vec2(0.0, pase.y) ) );
derecha.y = altura( texture2D( textura, uv + vec2(pase.x, 0.0) ) );
inferior.y = altura( texture2D( textura, uv + vec2(0.0, -pase.y) ) );
actual.y = altura( texture2D( textura, uv) );

/*
  v4
  |
v1----v3
  |
  v2

*/
vec3 v4 = izquierda - actual;
vec3 v3 = inferior - actual;
vec3 v2 = derecha - actual;
vec3 v1 = superior - actual;

vec3 n1 = normalize(cross(v1,v2));
vec3 n2 = normalize(cross(v2,v3));
vec3 n3 = normalize(cross(v3,v4));
vec3 n4 = normalize(cross(v4,v1));

vec4 t =  vec4(normalize(n1+n2+n3+n4),1.0);

gl_FragColor = t;

}


El resultado que produce es tal que:


Puede que este equivocado, pero generando normales, es de suponer que no debería de haber puntos negros,¿ no? ¿Quizás tengo algo mal en el shader?

Saludos y gracias.


EDIT:
A la izquierda como creo debería ser, en el centro el heightmap de origen y a la derecha lo que produce mi algoritmo.

tamat

hay algunas cosas que no acabo de entender:

la funcion altura qué hace? no entiendo cómo construyes la altura usando diferentes componentes de color de la textura, pero supondré que empaquetas el heightmap de alguna manera extraña para conseguir más resolucion.

cuando creas los vectores, hay algo que no me encaja del todo, la componente X y Z estas seguro que estan en un rango similar al de la componente Y? es que por las imagenes me da que X y Z miden mucho más, por eso al normalizar sale tan saturado.

Repasa la parte donde creas los vectores, lo demas parece correcto
Por un stratos menos tenso

killgt

Cita de: tamat en 01 de Febrero de 2010, 12:21:02 PM
hay algunas cosas que no acabo de entender:

la funcion altura qué hace? no entiendo cómo construyes la altura usando diferentes componentes de color de la textura, pero supondré que empaquetas el heightmap de alguna manera extraña para conseguir más resolucion.

cuando creas los vectores, hay algo que no me encaja del todo, la componente X y Z estas seguro que estan en un rango similar al de la componente Y? es que por las imagenes me da que X y Z miden mucho más, por eso al normalizar sale tan saturado.

Repasa la parte donde creas los vectores, lo demas parece correcto

Hola tamat, gracias por responder.

La función altura me devuelve el peso de ese pixel del heightmap en escala NTSC, de todos modos no importa si uso el canal R solo para tomar como referencia para la altura.

El componente x y z se corresponden con el S y el T respectivamente, de la textura, los cuales si no tengo mal entendido van de 0 a 1. ¿Quizás no es así y ahí es donde falla?


En cuanto llegue a casa lo pruebo.

Saludos.

tamat

para simplificar yo hacia que la X y la Z fueran -1 o 1, en función de la muestra que cojo, y luego me preocupaba de que la Y fuese entre -1 y 1 (aunque si van de 0 a 1 ya está bien=, de esta manera ya tenía los valores dentro de un rango aceptable, pero es importante garantizar que el rango es correcto.

otra cosa importante es probar de acumular los vectores sin normalizar y luego normalizarlos, en teoria si los vectores son correctos no necesitas normalizar hasta el vector final.

Para visualizar si los datos son correctos a mi me ayudaba pintar una unica componente de color del normalmap, así ves si los degradados son correctos, o utilizar un heightmap que sea muy simple (una guassiana)

pero ya te digo que conceptualmente todo parece correcto
Por un stratos menos tenso

Shaitan

Hola,
Quizás me equivoque, pero creo que las normales tienen que ir en el rango -1 a +1. Ten en cuenta que si, por ejemplo la x de la normal sale negativa, te va a dar un valor R=0. Aunque siempre tienen algo de color (porque no hay una normal con las 3 componentes negativas), puede que al normalizar te de algo muy similar a 0.
Lo que se suele hacer para transformar la normal del espacio (-1, 1) a (0,1) es algo asi: 0.5 * (normalize(normal) + 1.0);

De todas formas,  el mapa de normales que tienes en coloresazulados esta generado en espacio tangente y no en espacio normal...

(ya digo, puede que este equivocado)

J.
<º))))><.·´¯`·.Shaitan´¯`·.¸.·´¯`·._.·

tamat

ya me diras tú como va a haber una normal con Y negativa en un terreno...
Por un stratos menos tenso

killgt

He estado haciendo algunos cambios, como por ejemplo que todas las posiciones sean -1,0 en el caso de la izquierda, 0,1 en la de la superior y tal. Si mantengo el color a escala 0..1 la imagen que me genera es totalmente verde ( eje y ) , en cambio si lo multiplico por la escala que voy a usar en el heightmap sale con bastante más detalle.

Esta tarde pongo como ha quedado el shader y los resultados que produce, creo que ya son correctos...

Por cierto, el método que hago para representar el heightmap es mandar un grid de vertices en en el vertex shader cambio su posición y en función de lo que hay en esa parte de la textura correspondiente, ¿es así como lo hacéis?

Saludos.

tamat

lees la textura desde el vertex shader? no todas las tarjetas soportan eso.

otro problema que te encontraras es que desde CPU no podras hacer calculos de colision ya que no tienes la mesh deformada en RAM.

si me dices que en tu juego no importa si colisionas contra el suelo entonces perfecto.

A mi siempre me ha resultado más comodo guardar la mesh ya con el heighmap aplicado, y con las normales computadas, y subirlo a la tarjeta como una mesh más, usando el shader para temas de coloreado (que las zonas altas tengan nieve, las bajas cesped, las que tengan una pendiente muy pronunciada roca, etc).
Por un stratos menos tenso

Shaitan

Citarya me diras tú como va a haber una normal con Y negativa en un terreno..
Con una Y negativa no, pero con X y Z negativas si. Estas perdiendo todos los valores negativos de X y Z.
<º))))><.·´¯`·.Shaitan´¯`·.¸.·´¯`·._.·

tamat

pero nadie ha dicho de que X y Z no vayan de -1 a 1, solo acoté a 0-1 la Y
Por un stratos menos tenso

killgt

#10
Hola chicos, ante todo gracias por la ayuda.

Primero, respecto al Shader actualmente produce este resultado:



Usando una escala de Y de 0 a 100.

Si uso una escala de rgb por defecto, de 0 a 1, el resultado que produce es:



Supongo que es normal, si no es así, algo estaré haciendo mal.

Respecto al tema de las colisiones y demás, por el momento estoy intentando aprender nada más (por ahora no estoy demasiado preocupado por la compatibilidad), pero ya que lo comentas, creo que debería pasar los datos generados como las normales y mi textura generada proceduralmente a un VBO. Para ello ¿simplemente voy leyendo pixel a pixel?.

El código actual es:

uniform sampler2D textura;
uniform vec2 tamanoTextura;
uniform float escala;


float altura(vec4 color){
return (color.x)*escala;
}

void main ()
{
vec2 pase = 1.0/tamanoTextura;
vec2 uv = gl_TexCoord[0].st;



vec3 izquierda = vec3(-1.0, 0.0, 0.0);
vec3 supIzq = vec3(-1.0, 0.0, 1.0);
vec3 superior = vec3(0.0 , 0.0, 1.0);
vec3 supDer = vec3(1.0 , 0.0, 1.0);
vec3 derecha = vec3(1.0 , 0.0, 0.0);
vec3 infDer = vec3(1.0 , 0.0, -1.0);
vec3 inferior = vec3(0.0 , 0.0, -1.0);
vec3 infIzq = vec3(-1.0, 0.0, -1.0);
vec3 actual = vec3(0.0, 0.0, 0.0);


izquierda.y = altura( texture2D( textura, uv + vec2(-pase.x, 0.0) ) );
supIzq.y = altura( texture2D( textura, uv + vec2(-pase.x, pase.y) ) );

superior.y = altura( texture2D( textura, uv + vec2(0.0, pase.y) ) );

supDer.y = altura( texture2D( textura, uv + vec2(pase.x, pase.y) ) );
derecha.y = altura( texture2D( textura, uv + vec2(pase.x, 0.0) ) );

infDer.y = altura( texture2D( textura, uv + vec2(pase.x, -pase.y) ) );
inferior.y = altura( texture2D( textura, uv + vec2(0.0,-pase.y) ) );

infIzq.y = altura( texture2D( textura, uv + vec2(-pase.x, -pase.y) ) );
actual.y = altura( texture2D( textura, uv) );

/*
  v1
  |
v7----v3
  |
  v5

*/

vec3 v1 = superior - actual;
vec3 v2 = supDer - actual;
vec3 v3 = derecha - actual;
vec3 v4 = infDer - actual;
vec3 v5 = inferior - actual;
vec3 v6 = infIzq - actual;
vec3 v7 = izquierda - actual;

vec3 n1 = cross(v1,v2);
vec3 n2 = cross(v2,v3);
vec3 n3 = cross(v3,v4);
vec3 n4 = cross(v4,v5);
vec3 n5 = cross(v5,v6);
vec3 n6 = cross(v6,v7);
vec3 n7 = cross(v7,v1);

vec4 t =  vec4(normalize(n1+n2+n3+n4+n5+n6+n7),1.0);

gl_FragColor = t;

}




tamat

lo de guardar el resultado en un buffer nunca lo he hecho, pero seguirias teniendo el mismo problema ya que lo tendrías en GPU no en CPU.
No se si una mesh se puede bajar de GPU a CPU si la tienes en un VBO aunque estaría interesante.

Sobre la imagen que has puesto, no es normal que se vea todo verde, si el rango es entre 0 y 1 de la vertical, entonces el verde deberia reducirse en las zonas donde el terreno tenga pendiente.

Como te dije antes, prueba de imprimir solo una componente de color, va bien para debugar, pintas la componente X y miras si coincide con lo que esperarias, es decir, si las zonas donde la perpendicular está más alineada con el vector (1,0,0) se ven más rojas, y repites para las otras dos componentes.
Por un stratos menos tenso

killgt

Cita de: tamat en 02 de Febrero de 2010, 03:26:43 PM
lo de guardar el resultado en un buffer nunca lo he hecho, pero seguirias teniendo el mismo problema ya que lo tendrías en GPU no en CPU.
No se si una mesh se puede bajar de GPU a CPU si la tienes en un VBO aunque estaría interesante.

Sobre la imagen que has puesto, no es normal que se vea todo verde, si el rango es entre 0 y 1 de la vertical, entonces el verde deberia reducirse en las zonas donde el terreno tenga pendiente.

Como te dije antes, prueba de imprimir solo una componente de color, va bien para debugar, pintas la componente X y miras si coincide con lo que esperarias, es decir, si las zonas donde la perpendicular está más alineada con el vector (1,0,0) se ven más rojas, y repites para las otras dos componentes.
Probando con escala 0 a 1 y poniendo componente por componente, ningún componente muestra nada excepto el Y (G), voy a seguir dándole vueltas, pero no veo donde esta mi error :S.

Saludos

tamat

cuando pintes si quieres puedes guardar el abs( x ) para que los negativos se vuelvan positivos, sino tampoco se ven.
pero ya te digo que normalmente se ve algo ya que los colores van de 0 a 1 y las normales de -1 a 1, de hecho en muchos programadas de diseño de shaders tienes la opcion de ver las meshes coloreadas así
Por un stratos menos tenso

killgt

Llevo toda la tarde dándole vueltas y si no multiplico el color por 100, no consigo que las normales que genero tengan algo más que el componente verde... Seguiré buscando a ver si encuentro alguno ya hecho...






Stratos es un servicio gratuito, cuyos costes se cubren en parte con la publicidad.
Por favor, desactiva el bloqueador de anuncios en esta web para ayudar a que siga adelante.
Muchísimas gracias.