2011-02-04 2 views
20

Je veux ajuster les couleurs en fonction de leur position xyz dans le monde.GLSL: Comment obtenir la position du monde des pixels x, y, z?

J'ai essayé dans mon shader fragment:

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; 
} 

, mais il semble que les couleurs changent en fonction de mon angle de la caméra/position, comment puis-je faire les coords indépendants de ma position de la caméra/angle?

Heres mon vertex shader:

varying vec4 verpos; 

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

Edit2: titre changé, donc je veux coords monde, pas écran coords!

Edit3: ajouté mon code complet

+2

Ne pas multiplier par votre gl_ModelViewMatrix. – Hannesh

Répondre

27

Dans vertex shaders vous avez gl_Vertex (ou quelque chose d'autre si vous ne l'utilisez pipeline fixe) qui est la position d'un sommet en coordonnées modèle. Multipliez la matrice du modèle par gl_Vertex et vous obtiendrez la position du vertex dans les coordonnées du monde. Affectez-le à une variable variant, puis lisez sa valeur dans fragment shader et vous obtiendrez la position du fragment dans les coordonnées du monde. Maintenant, le problème est que vous n'avez pas nécessairement de matrice de modèle si vous utilisez la matrice modelview par défaut d'OpenGL, qui est une combinaison de matrices de modèle et de vue. Je résous généralement ce problème en ayant deux matrices séparées au lieu d'une matrice modelview:

    matrice modèle
  1. (coordonnées modèle de cartes aux coordonnées monde), et
  2. matrice de vue (monde cartes vers les coordonnées caméra).

Donc, passez simplement deux matrices différentes à votre vertex shader séparément. Vous pouvez le faire en définissant

uniform mat4 view_matrix; 
uniform mat4 model_matrix; 

Au début de votre vertex shader. Et puis au lieu de ftransform(), disent:

gl_Position = gl_ProjectionMatrix * view_matrix * model_matrix * gl_Vertex; 

Dans le programme principal, vous devez écrire des valeurs à ces deux nouvelles matrices. Tout d'abord, pour obtenir la matrice de vue, effectuez les transformations de la caméra avec glLoadIdentity(), glTranslate(), glRotate() ou gluLookAt() ou ce que vous préférez normalement, puis appelez glGetFloatv (GL_MODELVIEW_MATRIX, & array); afin d'obtenir les données de la matrice à un tableau. Et d'autre part, de manière similaire, pour obtenir la matrice du modèle, appelez aussi glLoadIdentity(); et faites les transformations d'objet avec glTranslate(), glRotate(), glScale() etc. et enfin appelez glGetFloatv (GL_MODELVIEW_MATRIX, & array); Pour extraire les données de la matrice d'OpenGL, vous pouvez l'envoyer à votre vertex shader. Notez en particulier que vous devez appeler glLoadIdentity() avant de commencer à transformer l'objet. Normalement, vous devez d'abord transformer la caméra, puis transformer l'objet, ce qui donne une matrice qui fait à la fois la vue et les fonctions du modèle. Mais parce que vous utilisez des matrices séparées, vous devez réinitialiser la matrice après les transformations de la caméra avec glLoadIdentity(). Gl_FragCoord sont les coordonnées des pixels et non les coordonnées du monde.

+1

@ltjax merci, édité ma réponse. – kynnysmatto

+0

je ne peux pas le faire fonctionner, il varie encore les couleurs quand je change ma position de la caméra/rotation. voir mon code actuel dans les modifications. – Rookie

+0

@Rookie, désolé, j'ai édité ma réponse plusieurs fois. avez-vous lu et compris cette dernière version? – kynnysmatto

-2

Le moyen le plus simple est de faire passer la position du monde à partir du vertex shader via une variable variable.

Cependant, si vous devez vraiment le reconstruire à partir de gl_FragCoord, la seule façon d'y parvenir est d'inverser toutes les étapes qui ont conduit aux coordonnées gl_FragCoord. Consultez les spécifications OpenGL, si vous devez vraiment le faire, car une compréhension approfondie des transformations sera nécessaire.

10

Ou vous pouvez simplement diviser la coordonnée z par la coordonnée w, ce qui désactive essentiellement la projection perspective; vous donnant vos coordonnées mondiales originales.

ie.

depth = gl_FragCoord.z/gl_FragCoord.w; 

Bien sûr, cela ne fonctionne que pour les coordonnées non-écrêtées ..

Mais qui se soucie de clipsé ceux de toute façon?

+1

Cela me donnera essentiellement la distance de la caméra à un fragment? Doux ... c'est exactement ce que je voulais. – mpen

0

Vous devez passer la matrice du monde/modèle en uniforme pour le vertex shader, puis multiplier par la position du sommet et l'envoyer comme variant au 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; 
} 
Questions connexes