2017-09-18 18 views
0

La cible est de dessiner une forme, disons un triangle, pixel-parfait (sommets doivent être spécifiés en pixels) et être en mesure de le transformer dans la 3ème dimension.OpenGL Perspective Projection pixel parfait dessin

Je l'ai essayé avec une matrice de projection orthogonale et tout fonctionne très bien, mais la forme n'a pas de profondeur - si je tourne autour de l'axe Y il semble que j'escaladeraient juste autour du X axe. (car une projection orthogonale se comporte évidemment comme ceci). Maintenant, je veux l'essayer avec une projection perspective. Mais avec cette projection, le système de coordonnées change complètement, et pour cette raison je ne peux pas spécifier mes vertices de triangles avec des pixels. Aussi, si la taille de ma fenêtre change, la taille de la forme change aussi (à cause du système de coordonnées modifié).

Y a-t-il un moyen de changer le système de coordonnées de la projection perspective afin que je puisse spécifier mes sommets comme si j'utiliserais la projection orthogonale? Ou est-ce que quelqu'un a une idée comment atteindre la cible décrite dans la première phrase?

+5

Les deux exigences sont par nature impossible à réaliser les deux en même temps, parce que la perspective de transformer implique une étape de division qui peut entraîner non -les coordonnées de l'intégrateur. Le mieux que vous pouvez espérer est d'avoir un "plan z" où les coordonnées du vertex traduisent 1: 1 en pixels, mais devant ou derrière ce plan, vous aurez toujours des non-entiers. – Thomas

+0

Quel serait le meilleur moyen d'atteindre ce "z-plane"? Je pense que c'est exactement ce que je veux. – Met

+1

La valeur 'z' pour ce" plan de pixels "dépendra du champ de vision de votre projection. Il est facile à trouver avec une géométrie de triangle simple. – derhass

Répondre

0

La matrice de projection décrit la correspondance entre les points 3D d'une scène et les points 2D de la fenêtre. Il se transforme de l'espace des yeux en espace de clip, et les coordonnées dans l'espace du clip sont transformées en coordonnées de périphérique normalisées (NDC) en divisant par le composant w des coordonnées du clip. Les NDC sont compris entre (-1, -1, -1) et (1,1,1).

Lors de la projection en perspective, la matrice de projection décrit le mappage de points 3D dans le monde tels qu'ils sont vus depuis une caméra sténopé, vers des points 2D de la fenêtre.
Les coordonnées de l'espace des yeux dans le tronc de la caméra (une pyramide tronquée) sont mappées sur un cube (les coordonnées normalisées de l'appareil).

enter image description here

Perspective Projection Matrix:

r = right, l = left, b = bottom, t = top, n = near, f = far 

2*n/(r-l)  0    0    0 
0    2*n/(t-b)  0    0 
(r+l)/(r-l) (t+b)/(t-b) -(f+n)/(f-n) -1  
0    0    -2*f*n/(f-n) 0 

où:

aspect = w/h 
tanFov = tan(fov_y * 0.5); 

prjMat[0][0] = 2*n/(r-l) = 1.0/(tanFov * aspect) 
prjMat[1][1] = 2*n/(t-b) = 1.0/tanFov 


Je suppose que la matrice de vue est la matrice d'identité, et donc les coordonnées de l'espace d'affichage sont égales aux coordonnées du monde.
Si vous voulez dessiner un polygone, où les coordonnées du vertex sont traduites 1: 1 en pixels, vous devez dessiner le polygone dans le plan parallèle à la fenêtre. Cela signifie que tous les points doivent être dessinés avec la même profondeur.
La profondeur doit choisir de cette façon, que la transformation d'un point en coordonnées normalisées de l'appareil, par la matrice de projection inverse donne les coordonnées du vertex en pixel. Notez, les coordonnées homogènes données par la transformation avec la matrice de projection inverse, doivent être divisées par la composante w des coordonnées homogènes, pour obtenir des coordonnées cartésiennes.
Cela signifie que la profondeur du plan dépend du champ de l'angle de vue de la projection:

En supposant que vous configurez une projection comme en perspective ceci:

float vp_w = .... // width of the viewport in pixel 
float vp_h = .... // height of the viewport in pixel 
float fov_y = ..... // field of view angle (y axis) of the view port in degrees < 180° 

gluPerspective(fov_y, vp_w/vp_h, 1.0, vp_h*2.0f); 

Puis le depthZ du plan avec une relation 1: 1 de coordonnées des sommets et des pixels, est calculé comme suit:

float angRad = fov_y * PI/180.0; 
float depthZ = -vp_h/(2.0 * tan(angRad/2.0)); 

note, le point central de la saillie de l'orifice de vue est (0,0), de sorte que le point d'angle inférieur gauche de l'avion est (-vp_w/2, -vp_h/2, depthZ) et le point d'angle supérieur droit est (vp_w/2, vp_h/2, depthZ). Assurez-vous que le plan proche de la perspective perspective est inférieur à -depthZ et que le plan lointain est supérieur à -depthZ.

Voir plus:

+0

Merci beaucoup, votre approche fonctionne bien. J'ai seulement une chose qui ne fonctionne pas comme prévu. Quand je dessine un Quad de 300x300, faites-le pivoter de 45 degrés sur l'axe des X, la perspective de mon quad change avec la hauteur de ma fenêtre/vue. Cela ne se produit pas si la largeur change. J'ai téléchargé une vidéo pour vous montrer ce comportement: https://www.youtube.com/watch?v=XI_WaX3W8qM&feature=youtu.be Peut-être avez-vous une idée pour résoudre ce problème? – Met

+0

@Met Le lien ne fonctionne pas pour moi! Je n'ai probablement pas accès à vos vidéos YouTube. – Rabbid76

+0

@Note, le champ de l'angle de vue est ajusté à la hauteur de la fenêtre, donc il est appelé 'fov_y'. La largeur est toujours corrigée par 'aspect = w/h'. Et la profondeur de l'avion dépend de la hauteur de la fenêtre 'depthZ = -vp_h/(2.0 * tan (angRad/2.0));' – Rabbid76