Éléments mathématiques¶
Ce projet est principalement centré sur le fait de prendre des concepts mathématiques et de les « traduire » en C#.
Les livres qui m’ont aidé sont :
Mathematical Elements for Computer Graphics - Second Edition écrit par David F. Rogers et J. Alan Adams.
Couverture de Mathematical Elements for Computer Graphics - Second Edition.¶
Inforgraphie II écrit par Philippe Schweizer
Couverture de Inforgraphie II.¶
Vecteurs¶
En math il y a deux types de grandeurs.
Tout d’abord il y a les grandeurs scalaires, elles sont déterminées par leur valeur et leurs unités.
Ensuite, il y a les grandeurs vectorielles, elles sont déterminées par leur valeur et leurs unités, mais possèdent en plus une orientation.
Le choix de l’une ou l’autre dépend de la nature de la grandeur. Par exemple la masse est une grandeur scalaire, car il n’y a pas d’orientation à celle-ci. Par contre, pour la vitesse, on utilisera un vecteur, car on ne va pas juste vite, on va vite dans une direction.
Cela dit, avoir juste une valeur et un angle n’est pas pratique pour faire des calculs. C’est pour cela qu’il existe deux moyens d’écrire un vecteur.
Les vecteurs polaires, qui ont une valeur et un angle. Par ex : \(\vec{v_{1}} = (v_{1} [m/s] ; \alpha °)\)
Et les vecteurs cartésiens, qui sont comme des coordonnées. Par ex : \(\vec{v_{1}} = (v_{1x}; v_{1y})\)
Dans le cadre de ce projet, les vecteurs sont utilisés afin de décrire une position (vecteur position). Nous utilisons donc des vecteurs cartésiens.
Matrices¶
Les matrices sont des tableaux de valeurs. Elles sont représentées comme ceci :
Les matrices ont différentes propriétés, notamment leur taille. Par exemple la matrice (1) à 2 lignes et 3 colonnes. On note cette taille : \(2 \times 3\).
On précise d’abord le nombre de lignes, puis le nombre de colonnes (ou [y, x]).
Une matrice peut également avoir une seule ligne :
En anglais on appelle ça une « row matrix », qui peut se traduire par matrice-ligne. S’il y a des matrices-ligne, ça veut dire qu’il y a aussi des matrices-colonnes (ou « column matrix ») :
Ces matrices peuvent être utilisées pour représenter des points, qui peuvent aussi être en 2D :
Les matrices de ce genre sont souvent appelées vecteur de position. En effet, un vecteur peut être considéré comme une matrice avec une seule ligne ou colonne.
Cela dit, il faut choisir si l’on veut travailler avec des vecteurs colonne ou des vecteurs ligne. Dans ce projet, j’ai choisi de travailler avec des vecteurs ligne, car c’est ce que le livre Mathematical Elements for Computer Graphics utilise.
Un point dans un espace 3D est donc représenté par :
Opérations¶
Multiplication par un nombre réel¶
Le résultat de la multiplication d’une matrice par un scalaire (un nombre réel) est une matrice dont tous les éléments sont multipliés par ce scalaire.
Exemple :
Addition et soustraction de matrices¶
Les matrices à additionner (soustraire) doivent être de même taille (m,n). Le résultat est alors une matrice de même taille (m,n) dont chaque élément est la somme (différence) des éléments à la même position des deux matrices.
Autrement dit, pour l’opération de matrices \(A \pm B = C\) l’élément de la ième ligne et jème colonne de C s’obtient de la manière suivante : \(C_{i,j} = A_{i,j} + B_{i,j}\).
Exemples :
Multiplication de matrices¶
Important
La multiplication de matrices n’est pas commutative : \(AB \ne BA\)
Pour multiplier deux matrices, il faut que le nombre de colonnes de la première soit égal au nombre de lignes de la deuxième : \((m,\textbf{n}) \cdot (\textbf{n},k)\)
La multiplication de matrices est associative : \((AB)C = A(BC)\)
Le résultat de la multiplication d’une matrice de taille \((m,n)\) par une matrice de taille \((n,k)\) est une matrice de taille \((m,k)\).
Pour le produit \(AB = C\) l’élément de la ième ligne et jème colonne de \(C\) est la somme des produits des éléments de même rang dans la ième ligne de \(A\) et dans la jème colonne de \(B\), c’est-à-dire :
Exemple :
Coordonnées homogènes¶
Dans 3D Viewer les points ne sont pas juste représentés par 3 points comme ceci :
Mais par 4 points :
Ce point utilise les coordonnées homogènes. C’est dans le but de pouvoir inclure les translations dans les transformations possibles.
Pour obtenir les coordonnées physiques, on peut utiliser cette formule :
Transformations dans le plan¶
Soit \([x, y, z, 1]\) un point dans le plan \(\mathbb{R} ^ 3\) (avec les coordonnées homogènes, comme précisé précédemment). On peut lui appliquer une transformation dans le plan. Pour connaître les coordonnées du point résultant, on applique à ce point une matrice particulière, c’est-à-dire qu’on multiplie le vecteur-ligne par la matrice correspondant à la transformation.
Pour appliquer une transformation à un segment, on applique cette transformation aux deux points qui sont les extrémités de ce segment. C’est le même principe pour une face, ou on applique la transformation sur les trois points de cette face.
Rotation¶
Axe X¶
Une rotation d’un angle \(\theta\) autour de l’axe X peut s’effectuer avec cette matrice :
Axe Y¶
Une rotation d’un angle \(\phi\) autour de l’axe Y peut s’effectuer avec cette matrice :
Axe Z¶
Une rotation d’un angle \(\psi\) autour de l’axe Z peut s’effectuer avec cette matrice :
Rotation autour d’un axe arbitraire¶
Avec un axe arbitraire dans l’espace passant par le point \(P_{0} = [x_{0}, y_{0}, z_{0}]\) et avec les cosinus directeurs \((c_{x}, c_{y}, c_{z})\).
Note
Les cosinus directeurs sont une liste d’angles qui vont de leur axe respectifs a un vecteur ou un point.
\(c_{x}\) : angle +x et le point/vecteur.
\(c_{y}\) : angle +y et le point/vecteur.
\(c_{z}\) : angle +z et le point/vecteur.
Afin d’effectuer une rotation d’un angle \(\delta\) autour de cet axe, il faut suivre ces étapes :
Effectuer une translation de l’objet vers l’origine
Faire les rotations appropriées afin que l’axe de rotation coïncide avec l’axe Z 1
Faire une rotation sur l’axe Z par l’angle \(\delta\)
Effectuer l’inverse des rotations combinées
Effectuer l’inverse de la translation
La transformation complète est donc :
Note
Si l’axe de rotation est déjà aligné avec l’axe Z, les étapes 1 et 2 ne sont pas nécessaires.
- 1
Le choix de l’axe Z est arbitraire.
Étape 1¶
Il faut effectuer une translation de manière à ce que l’axe de rotation passe à travers l’origine. Ceci est fait en faisant une translation par \(-P_{0} [-x_{0}, -y_{0}, -z_{0}]\). La matrice de translation et son inverse sont :
Étape 2¶
Il faut effectuer une rotation d’angle \(\alpha\) autour de l’axe X afin que l’axe de rotation se trouve dans le plan XZ. Afin de déterminer cet angle de rotation, il faut premièrement projeter le vecteur unitaire qui se trouve sur l’axe arbitraire sur le plan YZ. Les composants x et y du vecteur projeté sont \(c_{y}\) et \(c_{z}\), les cosinus de directions du vecteur unitaire sur le long de l’axe arbitraire. Il est possible de calculer la distance de la projection sur le plan YZ avec :
Ensuite l’angle peut être calculé avec :
Après avoir effectué la rotation autour de l’axe X sur le plan XZ, le composant z du vecteur est d et le composant x est \(c_{x}\), le cosinus directeur de la direction x. La longueur du vecteur unitaire est évidemment 1. Il est donc maintenant possible de calculer l’angle de rotation \(\beta\) autour de l’axe y afin de rendre l’axe arbitraire coïncidant avec l’axe Z est :
La matrice de rotation autour de l’axe X est
Et autour de l’axe Y
Étape 3¶
Puis finalement, la rotation autour de l’axe arbitraire est donnée par une matrice de rotation sur l’axe Z
Étapes 4 et 5¶
Il faut maintenant calculer l’inverse des matrices de translation et de rotation.
Sans cosinus directeurs¶
Si on ne connait pas les cosinus directeurs de l’axe arbitraire, on peut les obtenir à l’aide d’un autre point sur l’axe \((x_{1}, y_{1}, z_{1})\) en normalisant le vecteur du premier au second point. Le vecteur sur l’axe allant de \((x_{0}, y_{0}, z_{0})\) à \((x_{1}, y_{1}, z_{1})\) est
Normalisé, ça donne les cosinus directeurs
Homothétie¶
Une mise à l’échelle globale est obtenue en utilisant le quatrième élément diagonal :
Les coordonnées physiques peuvent être obtenues comme ceci :
Translation¶
La matrice de translation est :
Les coordonnées homogènes translatées sont obtenues par :
Ce qui veut dire que les coordonnées physiques transformées sont :
Plusieurs transformations¶
Plusieurs transformations peuvent être combinées dans une seule matrice \(4 \times 4\) qui donne le même résultat. Cela dit, la multiplication de matrices n’est pas commutative, il faut faire attention à l’ordre d’application. L’ordre est déterminé pas la position de la matrice de rotation par rapport au vecteur-position. La matrice la plus proche du vecteur générera la première transformation individuelle et la plus éloignée fera la dernière. Mathématiquement, ceci est exprimé comme :
Comme les transformations perspectives distordent les objets géométriques et les transformations projectives font perdre des informations, si ces matrices sont incluses, elles doivent être mises à la fin.
Projections¶
Les projections permettent de passer des points dans un espace 3D à un espace 2D (l’écran dans notre cas).
Orthographique¶
Une projection orthographique est une projection qui garde la vraie taille de l’objet. Les objets qui se trouvent loin ne sont donc pas plus petits. Cette projection a pour avantage d’être simple à implémenter, car elle équivaut au fait de juste garder deux des trois coordonnées de chaque point. Il est donc possible d’effectuer cette projection sur 3 axes :
X = 0, on garde Y et Z
Y = 0, on garde X et Z
Z = 0, on garde X et Y
Exemple de projection orthographique.¶
Les matrices pour ces projections sont :
Perspective¶
Une projection ou transformation perspective est une projection ou des objets tridimensionnels apparaissent plus petits quand ils sont éloignés de la caméra.
Les projections perspectives ne suivent pas les règles de la géométrie affine (classique). Par exemple, deux lignes parallèles ne le seront plus et la longueur d’un segment sera réduite en fonction de sa distance de l’observateur.
Les trois premiers éléments de la dernière ligne d’une matrice 4x4 correspondent à la perspective. C’est pour ça qu’on utilise des coordonnées homogènes.
Si la direction de la vision est alignée avec un axe principal, la création de la matrice perspective est simple. Afin de pouvoir y effectuer sur n’importe quel axe, on pourra utiliser un changement de repère afin d’aligner la vision à un axe principal.
Perspective selon un axe principal¶
Une manière d’imaginer la perspective est d’avoir un centre de projection (observateur) qui est face à un plan de projection ou les objets se trouveront. Le repère se trouve sur le plan de projection avec Y en haut, X à droite et Z en positif en direction du centre de projection. La distance entre le plan et le centre de projection se note \(L\).
Schema de la projection perspective tiré du livre Infographie II de Philipe Schweizer à la page 573.¶
Sachant que :
Centre de projection = \(\begin{bmatrix} 0 & 0 & L & 1 \end{bmatrix}\)
Direction de vision = \(\begin{bmatrix} 0 & 0 & -1 & 0 \end{bmatrix}\)
Plan de projection : \(Z = 0\)
Point : \(\begin{bmatrix} X & Y & Z & 1 \end{bmatrix}\)
Projection : \(\begin{bmatrix} X' & Y' & 0 & 1 \end{bmatrix}\)
On peut donc calculer les coordonnées projetées avec :
En divisant le numérateur et dénominateur par \(-L\), les équations de perspective peuvent aussi s’écrire comme suit :
On peut écrire ces équations matriciellement comme :
Cette matrice correspond à une transformation perspective et non une projection perspective. Afin d’obtenir une projection, il faut la multiplier par la matrice de projection orthographique Z.
On peut ensuite projeter un point en le multipliant par cette matrice :
Projection perspective générale¶
Pour que la perspective soit utile, il faut pouvoir créer une matrice qui marche dans un cas quelconque. Il est possible de faire ça en faisant un changement de repère puis d’appliquer la projection perspective sur l’axe Z. Le repère est déterminé par la position de l’observateur O et un point visé V.
Le changement de repère peut aussi se dire qu’on passe du world space au view space. Ce passage se fait par une succession de transformations élémentaires, les mêmes que pour la rotation autour d’un axe quelconque.
Les étapes pour ce changement sont :
\(T^{-1}\) Translation à l’observateur
\(R_{Z}^{-1}\) Rotation d’axe Z
\(R_{Y}^{-1}\) Rotation d’axe Y
\(E^{-1}\) Échange des coordonnées (dans le cas ou axes ne se trouvent pas au même endroit entre le world space et le view space)
La première étape est de translater le repère actuel à l’observateur, la matrice pour cette transformation est :
La rotation Z d’angle \(\varphi\) est :
Finalement la matrice de rotation autour de l’axe Y d’un angle \(\theta\) est :
Si maintenant on veut échanger les axes (ce que je n’ai pas fait dans mon code), on peut le faire avec une matrice de permutation. Par exemple, pour une permutation ou
X = Y
Y = Z
Z = X
La matrice pour effectuer ce changement est :
Une fois que nous sommes dans le repaire de l’observateur, on peut effectuer la perspective à l’aide de la matrice de transformation perspective.
Les sinus et cosinus des angles \(\varphi\) et \(\theta\) grâce au vecteur direction de vision \(\vec{D}\). Ce vecteur peut être calculé avec \(\vec{D} = \vec{O} - \vec{E}\). Il faut également calculer la projection de celui-ci (\(\vec{D}_{proj}\)). Les sinus et cosinus recherchés sont :
Dans mon code pour faire ce système, j’ai créé deux méthodes statiques dans mon struct Matrix4 : LookAt et CreatePerspectiveFieldOfView.
La méthode Matrix4 LookAt(Vector3 eye, Vector3 target, Vector3 up) s’occupe de créer la matrice de changement de repère globale.
Puis, la méthode Matrix4 CreatePerspectiveFieldOfView(double fovy, double aspect, double depthNear, double depthFar), va créer la matrice de projection perspective.
Caméra virtuelle¶
Afin de pouvoir projeter de n’importe où, il faut intégrer un système de caméra virtuelle. Le principe de base est de transformer les objets du world space au view space (donc face à la caméra), puis d’y projeter avec une matrice de projection.
Pour faire ceci, dans mon code j’ai créé une classe Camera.
Elle possède une position qui permet de savoir où elle se trouve dans l’espace.
Elle a également deux variables (propriété) d’angles Pitch et Yaw qui permettent de savoir où elle regarde dans l’espace.
Finalement, elle possède trois vecteurs : Front, Up et Right qui déterminent les axes du view space.
Quand les propriétés Pitch ou Yaw sont mises à jour, une méthode nommée UpdateVectors() est appelée.
Celle-ci s’occupe de mettre à jour les axes du view space grâce à de la trigonométrie.
Une fois que l’on veut projeter à l’aide de la caméra, il faut appeler les propriétés ViewMatrix et ProjectionMatrix
qui respectivement appellent les méthodes Matrix4.LookAt et Matrix4.CreatePerspectiveFieldOfView.
La direction de vision de la caméra est déterminée par le vecteur Front.