Outils pour utilisateurs

Outils du site


back2root:programmation:3d-theories-et-mathematiques-part-2

Ceci est une ancienne révision du document !


Tutoriaux: 3D : Théories et Mathématiques - PART 1

Introduction

Petite piqûre de rappel; le calcul en 3 dimension n’est pas plus compliqué que le calcul en 2 (ou en 1) dimension, tous le monde est capable d'additionner et de multiplier des nombres…

Le calcul en 1 dimension est en fait le calcul d’algèbre classique, que vous faites tous les jours en faisant vos courses par exemple.

Le calcul en 2 dimension est de la géométrie simple, rappelez vous les translations, homothéties, rotations, (bon ce dernier point est souvent abordé en cours de trigonométrie), mais en réalité, le calcul 3D n’est jamais que l’extension des deux premiers espaces, ou si on est « positif », le calcul en 2 dimensions ou algébrique n’est jamais qu’une simplification du calcul en 3D.

Malheureusement, pour comprendre et “masteriser” la 3d sur ordinateur, un gros bloc de théorie mathématique est a lire, je vais essayer de le faire aussi court mais complet que possible…

Système de références

Tout est une question de références, il existes trois grands systèmes pour décrire un espace en trois dimensions, il existe trois grands « système » de représentation mathématique.

Le système cartésien

Sans doute le plus simple a comprendre car le plus proche de notre mode « mathématique ».

Une coordonnée est exprimée « simplement » avec avec trois coordonnées : x, y, z

Radian vs Degré

Très souvent, dans les fonctions de trigonométriques informatiques, les angles sont exprimés en radian, et non en degrés (d'angle).

un radian est une valeur réel, alors qu'un degré d'angle est généralement un entier.

Notre cerveau a plus facile a manipuler la notion même de degré d'angle, car les valeurs nous sont plus communes : 0°, 90° pour un angle droit, 180°, etc…

pourtant, il est impératif d'utiliser des radians lorsqu'on fait des calculs trigonométriques, nous allons directement voir la relation entre radian et degré d'angle (180 degré d'angle, correspondent à Π radian)

eta radian = 180 degre

Donc 1 radian vaut +/- 57.2958 degré d'angle (suivant la valeur de eta pour effectuer la conversion) pour connaître la valeur (exacte) d'un radian, il suffit de:

1 radian = 180/eta degre

Les formules de conversion sont donc les suivantes:

degré -> radian

x radian = angle * (eta/180)

radian -> degré

x degre = rad * (180/eta)

le système sphérique

C’est le système qui est utilisé pour la géolocalisation ou la définition d’objets céleste ; on parle de coordonnées angulaire (appelées latitude et longitude dans la géolocalisation) et d’un rayon (l’altitude pour ce qui est de la géolocalisation, ou distance dans le cas d’objets céleste) :

Une coordonnée est exprimée avec un rayon r et deux angles : r, theta,varphi.

le système cylindrique

Ce système est le moins rependu, et souvent utilisé pour pour l’étude de mouvements hélicoïdaux ou en rotation autour d’un axe.

Une coordonnée est exprimée via deux angles : rho, varphi et une distance : z

Conversions entre systèmes de références

Sphérique → Cartésien

x = r * sin (theta) * cos (phi)

y = r * sin (theta) * cos (phi)

z = r * cos (theta)

Cylindrique → Cartésien

x = rho cos(phi)

y = rho sin(phi)

z = z

Calculs et matrices

En calcul 3D, le calcul matriciel la méthode la plus simple pour résoudre les transformations que l'on veut appliquer.

De plus, les opérations nécessaires se limitent surtout à deux opérations majeurs : la multiplication des matrices (produit matriciel) et l'addition de matrices.

Pour additionner 2 matrices, il s’agit de faire la somme de leurs membres:

delim{|}{matrix{2}{2}{a1 b1 a2 b2}}{|} + delim{|}{matrix{2}{2}{c1 d1 c2 d2}}{|} = delim{|}{matrix{2}{2}{(a1+c1) (b1+d1) (a2+c2) (b2+d2)}}{|}

Pour la multiplication, on utilisera la technique “LICOL” (Ligne Colonne), on multiplie chaque ligne par la colonne.

delim{|}{matrix{2}{2}{a1 b1 a2 b2}}{|} * 
delim{|}{matrix{2}{2}{c1 d1 c2 d2}}{|} = 
delim{|}{matrix{2}{2}{(a1*c1)+(b1*c2) (a1*d1)+(b1*d2) (a2*c1)+(b2*c2) (a2*d1)+(b2*d2)}}{|}

Note sur la multiplication par 1

Dans un calcul simple, quand on multiplie n'importe quelle valeur par 1 on obtient toujours la valeur d'origine :

x prime = x * 1

et donc x' = x

En calcul matriciel , la valeur '1' se présente comme ceci:

delim{|}{matrix{2}{2}{1 0 0 1}}{|}

Pour des questions pratiques, je ne me pencherais que sur le système cartésien, plus lisible et surtout plus commun, mais sachez qu’il est tout a fait possible de convertir une carte de la galaxie (qui est trouvable en coordonnées sphérique) dans un système cartésien:

(x,y,z)

et, ainsi la multiplication d'une matrice par '1' se présente comme ceci :

delim{|}{matrix{3}{1}{x y z}}{|} = 
delim{|}{matrix{3}{1}{x y z}}{|} * 
delim{|}{matrix{3}{3}{1 0 0 0 1 0 0 0 1}}{|}

Comme tous les langages de programmations n'incluent pas nativement le support de calcul matriciel, il convient de traduire ce produit matriciel en fonction simple (ou en une dimension) et de le faire pour chaque membre de la coordonnée que l'on veut calculer, vu la méthode LICOL que nous avons vu plus haut, cela devient donc:

x prime = (x*1) + (y*0) + (z*0)

y prime = (x*0) + (y*1) + (z*0)

z prime = (x*0) + (y*0) + (z*1)

Ce qui dans ce cas précis peut s'optimiser par l'application des formules suivantes:

x prime = x * 1

y prime = y * 1

z prime = z * 1

Coordonnées homogènes

Toutefois, pour pouvoir correctement appliquer certaines transformations (notamment la translation), dans certaines littératures, on rends homogènes les matrices, en ajoutant une 4ème valeur w, qui doit TOUJOURS être mise à 1, on parle alors de matrices homogènes :

delim{|}{matrix{4}{4}{ 
1 0 0 0 
0 1 0 0 
0 0 1 0 
0 0 0 1}}{|}

Ce qui peut se traduire simplement :

x prime = (x*1) + (y*0) + (z*0) + (w*0)

y prime = (x*0) + (y*1) + (z*0) + (w*0)

z prime = (x*0) + (y*0) + (z*1) + (w*0)

w prime = (x*0) + (y*0) + (z*0) + (w*1)

Ou encore en mode “optimisé”, afin de démontré que les matrices, c'est simple :

x prime = x * 1

y prime = y * 1

z prime = z * 1

w prime = w * 1

En résumé, un produit matriciel d'une matrice point “P” avec une matrice de transformation “T” s'écrit comme ceci:

delim{|}{matrix{4}{1}{ nx ny nz nw}}{|} = 
delim{|}{matrix{4}{1}{ x y z w}}{|} * 
delim{|}{matrix{4}{4}{ 
xa xb xc xd
ya yb yc yd
za zb zc zd
wa wb wc wd
}}{|}

Et se résous avec les équations suivantes:

x prime = (x*xa) + (y*xb) + (z*zb) + (w*xd)

y prime = (x*ya) + (y*yb) + (z*yb) + (w*yd)

z prime = (x*za) + (y*zb) + (z*zb) + (w*zd)

w prime = (w*wa) + (w*wb) + (w*wb) + (w*wd)

On constate immédiatement que l'ajout de la coordonnée “w” a dans cette série d'équations peut influencé grandement (ou pas) les résultats.

Transformations

Tout ensemble de transformations géométrique doit se faire dans un certain ordre qu'il convient de décider à l'avance.

Une rotation suivit d'une translation et d'un changement d'échelle, dans cet ordre, ne donneront pas le même résultat qu'un changement d'échelle suivit d'une rotation et enfin de la translation…

Sans compter qu'il existe des transformations “plus fun” comme le scissaillement ou le mirroir suivant un plan…

Dans cette je ne fournirais que les matrices (et leurs traductions sans optimisation).

Les changement d'échelle

Sans doute la matrice la plus simple, la matrice de transformation d'échelle:

delim{|}{matrix{4}{4}{ 
ex  0  0  0 
 0 ey  0  0
 0  0 ez  0
 0  0  0  1
}}{|}

On peut soit avoir une même échelle pour tout les axes : ex = ey = ez = échelle ou faire un changement d'échelle propre à chaque axes (ce qui peut amener des résultats rigolo).

Voici les formules a appliquer si l'on désire transformer un point particulier:

x prime = (x*ex) + (y* 0) + (z* 0) + (w* 0)

y prime = (x* 0) + (y*ey) + (z* 0) + (w* 0)

z prime = (x* 0) + (y* 0) + (z*ez) + (w* 0)

w prime = (x* 0) + (y* 0) + (z* 0) + (w* 1)

Translation

Si il existe une transformation souvent sous estimée, c'est bien celle-ci, le déplacement d'un point dans l'espace:

delim{|}{matrix{4}{4}{ 
 1  0  0  0 
 0  1  0  0
 0  0  1  0
tx ty tz  1
}}{|}

Voici les formules a appliquer si l'on désire transformer un point particulier:

x prime = (x* 1) + (y* 0) + (z* 0) + (w*tx)

y prime = (x* 0) + (y* 1) + (z* 0) + (w*ty)

z prime = (x* 0) + (y* 0) + (z* 1) + (w*tz)

w prime = (x*tx) + (y*ty) + (z*tz) + (w* 1)

Rappelez vous que w = 1, et donc nos formules peuvent se traduire par:

x prime = x+tx

y prime = y+ty

z prime = z+tz

Ce qui doit normalement vous rappeler des souvenirs.

Réflexion par rapport à un axe

Avec cette transformation, il est facile d'avoir le miroir d'un point par rapport à un des axes, cela peut servir soit pour créer un double de l'objet, soit pour le représenter “en mode miroir”… (a vous de voir si vous dupliquez ou non le point)

Le plan de “miroir” est toujours défini par rapport a deux axes:

Effet miroir par rapport au plan x/y (chaque coordonnée 'z' sera inversée):

delim{|}{matrix{4}{4}{
 1  0  0  0
 0  1  0  0
 0  0 (-1)  0
 0  0  0  1 }}{|}

Voici les formules a appliquer si l'on désire transformer un point particulier:

x prime = (x* 1) + (y* 0) + (z* 0) + (w* 0)

y prime = (x* 0) + (y* 1) + (z* 0) + (w* 0)

z prime = (x* 0) * (y* 0) * (z*-1) + (w* 0)

w prime = (x* 0) + (y* 0) + (z* 0) + (w* 1)

Effet miroir par rapport au plan x/z (chaque coordonnée 'y' sera inversée):

delim{|}{matrix{4}{4}{
 1  0  0  0
 0 (-1)  0  0
 0  0  1  0
 0  0  0  1 }}{|}

Voici les formules a appliquer si l'on désire transformer un point particulier:

x prime = (x* 1) + (y* 0) + (z* 0) + (w* 0)

y prime = (x* 0) + (y*-1) + (z* 0) + (w* 0)

z prime = (x* 0) * (y* 0) * (z* 1) + (w* 0)

w prime = (x* 0) + (y* 0) + (z* 0) + (w* 1)

Effet miroir par rapport au plan y/z (chaque coordonnée 'x' sera inversée):

delim{|}{matrix{4}{4}{
(-1)  0  0  0
 0  1  0  0
 0  0 1  0
 0  0  0  1 }}{|}

Voici les formules a appliquer si l'on désire transformer un point particulier:

x prime = (x*-1) + (y* 0) + (z* 0) + (w* 0)

y prime = (x* 0) + (y* 1) + (z* 0) + (w* 0)

z prime = (x* 0) * (y* 0) * (z* 1) + (w* 0)

w prime = (x* 0) + (y* 0) + (z* 0) + (w* 1)

Rotation autour des axes de références

C'est dans les rotations que les choses se compliquent, et que la trigonométrie commence, c'est aussi dans les rotations que l'on prends vraiment la troisième dimension “dans les yeux”; Nous allons différencier les 3 axes, mais en réalité les matrices sont particulièrement similaires…

Autour de l'axe Y, avec un angle de ay degré

delim{|}{
matrix{4}{4}{
(cos(ay)) 0 (- sin(ay)) 0
      0  1   0   0
(sin(ay)) 0  (cos(ay)) 0
 0 0  0  1}}{|}

Voici les formules a appliquer si l'on désire transformer un point particulier:

x prime = (x* cos(ay)) + (y*       0) + (z*-sin(ay)) + (w* 0)

y prime = (x*       0) + (y*       1) + (z*       0) + (w* 0)

z prime = (x* sin(ay)) + (y*       0) + (z* cos(ay)) + (w* 0)

w prime = (x*       0) + (y*       0) + (z*       0) + (w* 1)

Autour de l'axe X, avec un angle de ax degré

delim{|}{
matrix{4}{4}{1 0 0 0 
0 (cos(ax))  (sin(ax)) 0
0 ( -sin(ax))  (cos(ax))  0
 0 0  0  1}}{|}

Voici les formules a appliquer si l'on désire transformer un point particulier:

x prime = (x* cos(ax)) + (y* 0) + (z*-sin(ay)) + (w* 0)

y prime = (x*       0) + (y* 1) + (z*       0) + (w* 0)

z prime = (x* sin(ax)) + (y* 0) + (z* cos(ay)) + (w* 0)

w prime = (x*       0) + (y* 0) + (z*       0) + (w* 1)

Autour de l'axe Z, avec un angle de az °

delim{|}{matrix{4}{4}{
(cos(az)) (sin(az)) 0 0
( -sin(az)) (cos(az)) 0 0
       0       0 1 0
       0       0 0 1}}{|}

Voici les formules a appliquer si l'on désire transformer un point particulier:

x prime = (x* cos(az)) + (y* sin(az)) + (z* 0) + (w* 0)

y prime = (x*-sin(az)) + (y* cos(az)) + (z* 0) + (w* 0)

z prime = (x*       0) + (y*       0) + (z* 1) + (w* 0)

w prime = (x*       0) + (y*       0) + (z* 0) + (w* 1)

Conclusions temporaires

Avec ces outils, il est possible de modifier un point (ou des points) dans l'espace, et de le(s) placer avec précision où l'on veut (on peut aussi appliquer une transformation puis une autre dans n'importe quel ordre), et créer a chaque fois un nouveau point…

Ces transformations modifient la positions des points dans l'univers; nous y reviendrons plus tard…

Il est important de noter que ces transformations sont des outils aidant à créer d'autre points, ainsi si l'on dessine une forme (avec des points) sur un plan X/Y, il est très facile de dupliquer ces points en faisant 36 rotations de 10° à chaque fois, et ainsi de créer un objet en 3D “tourné” a partir d'un simple profile.

Dans la suite de cet article, je resterais (sauf exception) sur des matrices “classiques” à 3 valeurs (x,y,z).

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' = x' - (sizex/2) y' = y' - (sizey/2)

if 1)

draw_pixel(x',y',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' = x / z y' = 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'ilusion d'etre “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==0)
{
  x' = x
  y' = y
}
else
{
  x' = x / z
  y' = y / z
}

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' = x*(ez/z) + ex y' = 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).

Soit: 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

x' 1 0 0 cos(ay) 0 -sin(ay) cos(az) sin(az) 0 x ox
y' = 0 cos(ax) sin(ax) * 0 1 * -sin(az) cos(az) 0 * (y - oy
z' 0 -sin(ax) cos(ax) sin(ay) 0 cos(ay) 0 0 1 z oz

Note:

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”

x' x ox
y' = y - oy
z' z oz

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

x' x
y' = y
z' z

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.

soit: ox,oy,oz : coordonnées cartésienne, position de l'oeil dans l'espace. 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

3D et vrai Relief J.J.Meyer ISBN: 2-7091-0990-5 https://www.amazon.co.uk/3D-vrai-relief-images-synthese/dp/2709109905

PC Interdit 2eme édition Windows 95 & Jeux 3D Boris Bertelsons, Mathias Rasch et Jan Erik Hoffmann ISBN: 2-7429-0500-6 https://www.amazon.fr/PC-interdit-Collectif/dp/2742905006

Mathematics of 3D Graphics Juan David Gonzalez Cobas Universidad de Oviedo Blender Conference 2004 https://www.cs.trinity.edu/~jhowland/class.files.cs357.html/blender/blender-stuff/m3d.pdf

http://www.ecere.com/3dbhole/mathematics_of_3d_graphics.html

https://en.wikipedia.org/wiki/3D_projection

https://fr.wikipedia.org/wiki/Projection_(g%C3%A9om%C3%A9trie)

https://fr.wikipedia.org/wiki/Perspective_axonom%C3%A9trique

1)
x'>=0) and (x'<sizex) and (y'>=0) and (y<sizey
back2root/programmation/3d-theories-et-mathematiques-part-2.1620001218.txt.gz · Dernière modification : 2021/05/03 02:20 de frater