2013-06-18 3 views
1

En ces jours je lis le livre Learning Modern 3D Graphics Programming de Jason L. McKesson. Fondamentalement, il s'agit d'un livre sur l'OpenGL 3.3 et je suis maintenant au chapter 4, qui est sur la vue orthographique et en perspective. A la fin du chapitre, sous la section "Further Study", il suggère d'essayer quelques choses comme implémenter un point de vue variable (il a utilisé au début (0, 0, 0) dans l'espace de caméra pour la semplicité) et une perspective arbitraire emplacement de l'avion. Il dit que je vais devoir décaler les positions d'espace de caméra X, Y des sommets par E_x et E_y respectivement.Comment définir un point de vue spécifique en utilisant une vue en perspective avec des shaders

Je ne peux pas comprendre ce passage, comment suis-je supposé utiliser un point d'œil variable en ne modifiant que les décalages X, Y?

Editer: pourrait-il être quelque chose comme ça?

#version 330 

layout(location = 0) in vec4 position; 
layout(location = 1) in vec4 color; 

smooth out vec4 theColor; 

uniform vec2 offset; 
uniform vec2 E; 
uniform float zNear; 
uniform float zFar; 
uniform float frustumScale; 


void main() 
{ 
    vec4 cameraPos = position + vec4(offset.x, offset.y, 0.0, 0.0); 
    vec4 clipPos; 

    clipPos.xy = cameraPos.xy * frustumScale + vec4(E.x, E.y, 0.0, 0.0); 

    clipPos.z = cameraPos.z * (zNear + zFar)/(zNear - zFar); 
    clipPos.z += 2 * zNear * zFar/(zNear - zFar); 

    clipPos.w = cameraPos.z/(-E.z); 

    gl_Position = clipPos; 
    theColor = color; 
} 

Edit2: merci Boris, votre image a beaucoup aidé :) surtout parce que:

  • il fait clairement ce que vous avez déjà dit au sujet de la pensée E comme position de lieu de projection et non la position du point d'oeil
  • il souligne que la taille du plan de projet doit toujours être [-1, 1], passage que j'ai lu sur le livre sans comprendre complètement ce que cela signifiait

J As-tu une curiosité, pourquoi dis-tu de multiplier après soustraction? Est-ce pour la même raison que le livre dit, c'est le ratio d'aspect? Parce que tout me pousse logiquement à faire exactement le contraire, c'est d'abord la traduction (-2) puis la multiplication (/ 5). Ou peut-être avec le terme «scaling», le livre se réfère à la fonction de remodelage?

+1

J'ai édité ma réponse, en améliorant ce que j'ai écrit à l'origine, et en ajoutant une explication avec du vrai code et une figure illustrant ce que je pense est demandé dans le livre. – Boris

+0

Heureux que cela a aidé. Je multiplie puis soustrait car c'est le résultat correct: -P Souvenez-vous que dans votre NDC, la zone colorée est le cube unité: les limites X de la zone rouge dans le chiffre en haut à droite sont 1/5 et 3/5 (ces proportions sont où les lignes grises croisent le plan de projection bleu dans la figure en haut à gauche). Ensuite, si vous faites ce que vous suggérez d'appliquer à ces deux valeurs {1/5 | 3/5}, vous obtenez: ({1/5 | 3/5} - 2) * 5 = {-9; -7}. Et si vous le faites dans le bon ordre: ({1/5 | 3/5} * 5) - 2 = {-1; 1} :-) – Boris

+0

Par ailleurs, le plan de projection ne doit pas - être dimensionné [-1; 1]. C'est juste la convention prise dans le livre: l'auteur préfère mettre à l'échelle l'espace avant (scaleFrustrum), ce qui équivaut à mettre à l'échelle le plan de projection (sauf si E.xy! = 0, je n'en ai pas vraiment tenu compte dans mon code...). Notez que Ez et frustrumScale sont redondants: déplacer le plan de projection plus loin l'oeil équivaut à réduire sa taille, ce qui équivaut à augmenter frustrumScale (équivalent à zoomer) – Boris

Répondre

5

Ici, nous nous intéressons au calcul d'une transformation de coordonnées de caméra (CC) en coordonnées normalisées de périphériques (NDC).

Pensez à E comme la position du plan de projection dans les coordonnées de la caméra, au lieu de la position du point de vue en fonction du plan de projection. Dans les Coordonnées Caméra, le point de vue est par définition situé à l'origine, au moins dans mon interprétation de ce que signifie "Caméra Coordonnée": un cadre de coordonnées centré à partir de l'endroit où vous regardez la scène. (Vous pouvez définir mathématiquement une transformation de perspective centrée de n'importe où, mais cela signifie que votre espace d'entrée n'est pas l'espace de la caméra, comme vous le verrez dans chapter 6)

Résumé :

  • vous êtes dans l'espace de la caméra, d'où votre point d'oeil est situé à (0,0,0)
  • vous êtes à la recherche vers l'axe Z négatif
  • votre plan de projection est parallèle à la xOy avion, avec une taille de [-1,1] dans les deux sens

Ceci est l'image ici (chaque tique est 0,5 unité):

enter image description here

Dans ce tableau, on peut voir que le plan de projection (côté inférieur du trapèze gris) est centré dans (0 , 0, -1), avec une taille de [-1,1] dans les deux directions X et Y.Maintenant, ce qui est demandé est de choisir (0,0, -1) pour le centre de ce plan, de choisir une position arbitraire (E.x, E.y, E.z) (suppose que E.z est négatif). Mais l'avion doit encore être parallèle à l'axe xOy et de la même taille.

Vous pouvez voir que la dimension E.xy joue un rôle très différent de E.z, par ce que E.xy sera impliqué dans une soustraction, tandis que E.z sera impliqué dans une division. Cela est facile à voir avec un exemple:

  1. supposer zNear = -ez (pas nécessairement le cas, mais vous pouvez en effet changer toujours frustumScale d'avoir une perspective équivalente satisfaisant cette)
  2. considèrent le point E (qui est le centre du plan de projection).

Quelle est sa coordonnée dans l'espace NDC? C'est (0,0, -1) par définition. Ce que vous avez fait est de soustraire E.xy, mais en divisant par -E_z.

Votre code a cette idée, mais certaines choses sont mal:

  1. Tout d'abord, vous avez défini uniform vec2 E; au lieu de uniform vec3 E; (juste une faute de frappe, pas une grosse affaire)
  2. La ligne clipPos.xy = ... ; est sur vec2 arithmétique. Par conséquent, vous ne pouvez multiplier que par des valeurs scalaires (c'est-à-dire, un flottant) ou ajouter/soustraire des valeurs vec2. Par conséquent, vec4(E.x, E.y, 0.0, 0.0) est de type incorrect, vous devez utiliser E.xy à la place, qui a le type correct vec2. Vous devez en fait soustraire E.xy au lieu de l'ajouter. C'est facile à voir dans mon exemple ci-dessus.
  3. Enfin, les choses sont plus subtiles ;-)

J'ai fait une photo pour illustrer les modifications:

enter image description here

Chaque tick est 1 unité dans cette image. En haut à gauche se trouve l'espace de coordonnées de votre caméra, avec zNear, zFar et deux plans de projection possibles. En bleu est celui utilisé dans l'explication et le shader here, et le rouge est celui que vous voulez maintenant utiliser. Les zones colorées correspondent à ce qui devrait être visible dans votre écran final, par ex. ce qui devrait être dans le cube [-1,1]^3 dans l'espace NDC. Par conséquent, si vous utilisez le plan de projection bleu, vous voulez obtenir l'espace en haut à droite, et si vous utilisez le plan de projection rouge, vous voulez obtenir l'espace en bas. Pour ce faire, vous pouvez observer que vous devez effectuer la mise à l'échelle et la traduction dans l'espace NDC, par ex. après la division de perspective! (Je pense que ce qui est écrit dans le livre est soit incorrect, ou interprète la question différemment).

Par conséquent, vous voulez faire, dans coordonnée euclidienne (c'est-à-dire, coordonnée non homogène, par ex.sans W coordonnées):

clipPosEuclideanRed.xy = clipPosEuclideanBlue.xy * (-E.z) - E.xy; 
clipPosEuclideanRed.z = clipPosEuclideanBlue.z; 

Cependant, parce que vous êtes en coordonnées homogènes, ces valeurs sont en fait:

clipPosEuclidean.xyz = clipPos.xyz/clipPos.w; // with clipPos.w = -cameraPos.z; 

Par conséquent, vous devez composate par écrit:

clipPosRed.xy = clipPosBlue.xy * (-E.z) - E.xy * (-cameraPos.z); 
clipPosRed.z = clipPosBlue.z; 

Donc, ma solution à ce problème serait d'ajouter une seule ligne:

void main() 
{ 
    vec4 cameraPos = position + vec4(offset.x, offset.y, 0.0, 0.0); 
    vec4 clipPos; 

    clipPos.xy = cameraPos.xy * frustumScale; 

    // only add this line 
    clipPos.xy = - clipPos.xy * E.z + E.xy * cameraPos.z; 

    clipPos.z = cameraPos.z * (zNear + zFar)/(zNear - zFar); 
    clipPos.z += 2 * zNear * zFar/(zNear - zFar); 

    clipPos.w = -cameraPos.z; 

    gl_Position = clipPos; 
    theColor = color; 
} 
+0

Salut Boris, merci pour votre longue réponse .. yep désolé, je voulais dire (0 , 0, 0) en ce qui concerne le point de vue. Donc je devrais avoir le plan de projection toujours parallèle à l'axe xOy. Je vais essayer ça – elect

+0

"* D'abord, contrairement à ce que vous écrivez, le point de vue est toujours fixé à (0,0,0). *" Non-sens. Vous pouvez générer une [projection en perspective à partir d'un emplacement arbitraire] (http://en.wikipedia.org/wiki/3D_projection#Perspective_projection). C'est juste que la matrice * standard * le fixe à l'origine, pour simplifier les calculs. Cela n'a pas à être à l'origine. –

+0

Oui je sais, mais je prends juste la convention du livre utilisé, pour rendre la question compréhensible dans le contexte de l'explication fournie dans le livre. C'est un bon point à mentionner de toute façon. – Boris

Questions connexes