2011-02-04 8 views
20

Quiero ajustar los colores dependiendo de la posición xyz que estén en el mundo.GLSL: ¿Cómo obtener la posición mundial de pixel x, y, z?

He intentado esto en mi fragment shader:

varying vec4 verpos; 

void main(){ 
    vec4 c; 
    c.x = verpos.x; 
    c.y = verpos.y; 
    c.z = verpos.z; 
    c.w = 1.0; 

    gl_FragColor = c; 
} 

pero parece que los colores cambian dependiendo de mi ángulo de la cámara/posición, ¿Cómo puedo hacer las coordenadas independiente de mi posición de la cámara/ángulo?

Heres mi sombreado de vértices:

varying vec4 verpos; 

void main(){ 
    gl_Position = ftransform(); 
    verpos = gl_ModelViewMatrix*gl_Vertex; 
} 

Edit2: título cambiado, así que quiero coords mundo, no coordenadas de pantalla!

Edit3: añadido mi código completo

+2

no se multiplican por su gl_ModelViewMatrix. – Hannesh

Respuesta

27

En vertex shader tiene gl_Vertex (o algo más si no se utiliza la tubería fija) que es la posición de un vértice en el modelo de coordenadas. Multiplique la matriz del modelo por gl_Vertex y obtendrá la posición del vértice en las coordenadas mundiales. Asignar esto a una variable variando, y luego lea su valor en el sombreador de fragmentos y obtendrá la posición del fragmento en las coordenadas mundiales.

Ahora el problema en esto es que no necesariamente tiene una matriz de modelo si usa la matriz de vista de modelo predeterminada de OpenGL, que es una combinación de matrices de modelo y de vista. Por lo general a resolver este problema haciendo que dos matrices separadas en vez de matriz de una sola modelview:

  1. matriz del modelo (modelo de mapas de coordenadas a coordenadas del mundo), y
  2. vista de matriz (mapas del mundo en coordenadas de la cámara).

Así que simplemente pase dos matrices diferentes a su vertex shader por separado. Puede hacerlo definiendo

uniform mat4 view_matrix; 
uniform mat4 model_matrix; 

Al comienzo de su sombreado de vértices. Y entonces, en lugar de ftransform(), dicen:

gl_Position = gl_ProjectionMatrix * view_matrix * model_matrix * gl_Vertex; 

En el programa principal debe escribir valores en estos dos nuevas matrices. Primero, para obtener la matriz de vistas, realice las transformaciones de la cámara con glLoadIdentity(), glTranslate(), glRotate() o gluLookAt() o lo que prefiera como lo haría normalmente, pero luego llame a glGetFloatv (GL_MODELVIEW_MATRIX, & matriz); para obtener los datos de la matriz en una matriz. Y en segundo lugar, de manera similar, para obtener la matriz del modelo, también llame a glLoadIdentity(); y hacer las transformaciones del objeto con glTranslate(), glRotate(), glScale() etc. y finalmente llamar a glGetFloatv (GL_MODELVIEW_MATRIX, & matriz); para obtener los datos de la matriz de OpenGL, para que pueda enviarlos a su vertex shader. Tenga en cuenta especialmente que debe llamar a glLoadIdentity() antes de comenzar a transformar el objeto. Normalmente, primero se transformaría la cámara y luego se transformaría el objeto, lo que daría como resultado una matriz que realiza las funciones de vista y modelo. Pero debido a que está utilizando matrices separadas, debe restablecer la matriz después de las transformaciones de la cámara con glLoadIdentity().

gl_FragCoord son las coordenadas de píxel y no las coordenadas del mundo.

+1

@ltjax gracias, editado mi respuesta. – kynnysmatto

+0

no puedo hacer que funcione, todavía varía los colores cuando cambio la posición/rotación de mi cámara. ver mi código actual en ediciones. – Rookie

+0

@Rookie, lo siento, edité mi respuesta un par de veces. ¿Has leído y entendido esta última versión? – kynnysmatto

-2

La manera más fácil es bajar la posición mundial desde el sombreador de vértices a través de una variable variable.

Sin embargo, si realmente debe reconstruirlo desde gl_FragCoord, la única forma de hacerlo es invertir todos los pasos que llevaron a las coordenadas gl_FragCoord. Consulte las especificaciones de OpenGL, si realmente tiene que hacer esto, porque será necesaria una comprensión profunda de las transformaciones.

10

O podría simplemente dividir la coordenada z por la coordenada w, lo que esencialmente deshabilita la proyección en perspectiva; dándote tus coordenadas mundiales originales.

es decir.

depth = gl_FragCoord.z/gl_FragCoord.w; 

Por supuesto, esto sólo funcionará para las coordenadas no recortadas ..

Pero, ¿quién se preocupa por los recortado de todos modos?

+1

Esto esencialmente me dará la distancia de la cámara a un fragmento? Dulce ... eso es exactamente lo que quería. – mpen

0

Tiene que pasar la matriz Mundial/modelo como un uniforme al vertex shader, y luego se multiplica por la posición de vértice y enviarlo como una variable para el fragment shader:

/*Vertex Shader*/ 

layout (location = 0) in vec3 Position 

uniform mat4 World; 
uniform mat4 WVP; 

//World FragPos 
out vec4 FragPos; 

void main() 
{ 
FragPos = World * vec4(Position, 1.0); 
gl_Position = WVP * vec4(Position, 1.0); 
} 

/*Fragment Shader*/ 

layout (location = 0) out vec4 Color; 

... 

in vec4 FragPos 

void main() 
{ 
Color = FragPos; 
} 
Cuestiones relacionadas