Table des matières

3D : Théories et Mathématiques - PART 2

Projection sur l'écran

Il nous reste à aborder le passage de la 3D à la 2D (pour nos “simple” écrans)…

Nous avons transformé des points (qui peuvent former des objets) dans un espace à 3 dimensions, avec un point remarquable (0,0,0) qui est le centre de l'univers cartésiens ainsi décrit.

Par défaut, si l'on applique les formules de projection ci-dessous, l'observateur sera un point “remarquable” (et immobile) situé en (0,0,0) et qui regarderait vers le fond (0°,0°,0°) … :D

Projection sans distance, projection orthonormée (projection du fainéant)

Si l'on désire représenter un point 3D en 2D, après transformation(s), on peut simplement ignorer la coordonnées 'Z'

x prime = x

y prime = y

Centrer l'écran

Sachant qu'un écran informatique peut afficher des points de 0,0 à sizex, sizey et que les valeurs de x' et y' peuvent quand à elles varier t entre -∞ et +∞, il convient de centrer le 0,0 sur l'écran et d'éliminer les valeurs “hors écran”

x_screen = x_transformed - (sizex/2);
y_screen = y_transformed - (sizey/2) ;
 
if ((x_screen>=0) and (x_screen<sizex) and (y_screen>=0) and (y_screen<sizey))
  draw_pixel(x_screen,y_screen,1);

Projection Simple dit aussi Projection du pauvre

Si l'on désire représenter un point 3D en 2D, après transformation(s), on simuler l'éloignement (par rapport à l'observateur) en faisant un rapport sur la valeur z, après transformation:

x prime = x / z

y prime = y / z

Cette projection transforme un point 3D en 2D en tenant compte de l'éloignement, plus le Z est grand, plus les points projetés se “rapprochent” les un des autres autour du 0,0, et donc donneront l’illusion d’être “plus loin”.

C'est la technique qui est utilisée en peinture (technique du “point de fuite”) pour donner un sentiment de “profondeur” à l'image, on parle alors de perspective.

Dans cette projection, Il convient toutefois de prendre en compte le risque d'avoir un z nulle avant d'appliquer la projection.

Cas du 'Z' nul

On peut soit ignorer les points qui sont sur l'origine, soit les afficher en utilisant la projection du fainéant, je conseille de quand même les afficher.

if (z_screen==0)
{
  x_screen = x_screen;
  y_screen = y_screen;
}
else
{
  x_screen = x_screen / z_screen;
  y_screen = y_screen / z_screen;
}

Cette gestion ne vous empêches pas de quand même centrer votre 0,0 et les “hors-écran”, donc alourdis un peu la projection.

Projection sur l'écran

Considérons un instant l'écran (de projection) comme pouvant se situé entre l'observateur et l'objet observé, il convient de prendre en compte cette différence, afin notamment de gérer l'effet de focale (et éventuellement de traiter le centrage)…

la projection sera dès lors calculée avec les formules suivantes

x prime = x*(ez/z) + ex

y prime = y*(ez/z) + ey

Si l'on considère que ex = -(sizex/2) et ey = -(sizey/2), et que ez=1, alors nous retombons sur la formule de la projection du pauvre… qui tiens nativement compte du centrage de l'écran…

Caméra et point de vue

Dans les projections précédentes, nous avons toujours fait bouger les points de l'univers autours du 0,0,0 et non fait bouger un observateur dans cet univers, la logique voudrait que ce soit en effet l'observateur qui se déplace et non l'univers.

Si l'on désire faire entrer la notion d'observateur(caméra)/point de vue, il convient d'inclure ce point (et là ou il regarde) dans les calculs de transformation/projection et d'appliquer aux points de l'univers une transformation spéciale.

Si l'on désire appliquer les transformations en prenant en compte la position de l'observateur, il convient d'appliquer la transformation de la caméra, cette transformation inclu une rotation autour de l'axe Z, de l'axe Y et de l'axe X de chaque point par rapport à la position de l'observateur/caméra et à son orientation (du regard).

x,y,z : coordonnées cartésienne du point a transformer

ox,oy,oz : coordonnées cartésienne, position de l'oeil dans l'espace.

ax,ay,az : angles de vue , ces angles définissent la direction du regard à partir du point de l'observateur (ox,oy,oz).

Alors la matrice de transformation devient

delim{|}{  matrix{4}{1}  {nx ny nz nw}}{|} = 
delim{|}{  matrix{4}{4}  { 1  0  0 0 0 (cos(ax)) (sin(ax)) 0  0 ( -sin(ax)) (cos(ax)) 0 0 0 0 1 }}{|} *
delim{|}{  matrix{4}{4}  { (cos(ay))  0  ( -sin(ay)) 0 0  0  1 0 (sin(ay)) (cos(ay)) 0 0 0 0 0 1 }}{|} * 
delim{|}{  matrix{4}{4}  { (cos(az))  ( -sin(az)) 0  0 ( -sin(az)) (cos(az)) 0 0  0 0 1 0 0 0 0 1 }}{|} * (
delim{|}{  matrix{4}{1}  { x y z w}}{|} - 
delim{|}{  matrix{4}{1}  { ox oy oz ow }}{|} 
)

Dans l'introduction à la projection, j'ai évoqué l'observateur comme étant un point remarquable du système localisé en (0,0,0), et ayant une direction de regard a angle nul (0°,0°,0°)

Si l'on n'a pas d'angle de vue (ax=ay=az=0), les matrices de rotation deviennent des matrices “unités” (car (sin(0)=0 et cos(0)=1), et l'on peut dès lors simplifier le produit en “translation”:

delim{|}{  matrix{4}{1}  {nx ny nz nw}}{|} = 
delim{|}{  matrix{4}{1}  {x y z w}}{|} -
delim{|}{  matrix{4}{1}  {ox oy oz ow}}{|}

Mais il ne faut pas oublié que l'observateur est le 0,0,0; ce qui veut dire que ox=oy=oz=0, alors

delim{|}{  matrix{4}{1}  {nx ny nz nw}}{|} = 
delim{|}{  matrix{4}{1}  {x y z w}}{|}

Et l'on retombe bien sur une matrice toute simple.

Conclusions

Il est impossible de conclure simplement, mais je vais tenter de résumer au mieux tout ce qui a été vu, et de fournir une matrice/formule simple

vec quelques définitions voici les formules que nous allons implémenter.

ox,oy,oz : coordonnées cartésienne, position de l'oeil dans l'espace.

w : 1 (valeur de 1 pour simplifier)

x[],y[],z[] : coordonnées cartésienne des points a transformer

ex,ey,ez : coordonnées cartésienne de l'écran avec ex=-(sizex/2), ey=-(sizey/2) et ez=1

ax,ay,az : angles de vue , ces angles définissent la direction du regard à partir du point de l'observateur (ox,oy,oz).

cx = cos(ax), sx = sin(ax), cy = cos(ay), …

nx,ny,,nz : coordonnées cartésienne, position temporaire de calcul

pseudo code:

foreach 
{
  dx = x[]-ox
  dy = y[]-oy
  dz = z[]-oz

  nx = cy*(sz*dy + cz*dx) - sy*dz
  ny = sx*(cy*dz + sy*(sz*dy + cz*dx)) + cx*(cz*dy - sz*dx)
  nz = cx*(cy*dz + sy*(sz*dy + cz*dx)) - sx*(cz*dy - sz*dx)

  x' = nx*(ez/nz) + ex
  y' = ny*(ez/nz) + ey
}

Références