This is an old revision of the document!


Laboratoire 03

Transformations 2D

Les objets 2D sont définis dans un système cartésien de coordonnées 2D, par exemple, XOY, XOZ ou YOZ. Dans ce laboratoire, nous allons mettre en oeuvre différents types de transformations qui peuvent être appliqués à des objets définis dans le plan XOY: translation, rotation et mise à l'échelle. Ceux-ci sont définis dans un format de matrice, en coordonnées homogènes, comme vous l'avez déjà appris dans le cours. Les matrices de ces changements sont les suivants:

Translation

$$ \begin{bmatrix} {x}'\\ {y}'\\ 1 \end{bmatrix} = \begin{bmatrix} 1 & 0 & t_x\\ 0 & 1 & t_y\\ 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} x\\ y\\ 1 \end{bmatrix} $$

Rotation

Rotation autour de l’origine

$$ \begin{bmatrix} {x}'\\ {y}'\\ 1 \end{bmatrix} = \begin{bmatrix} cos(u) & -sin(u) & 0\\ sin(u) & cos(u) & 0\\ 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} x\\ y\\ 1 \end{bmatrix} $$

La rotation relative à un certain point

La rotation relative à un certain point est résolu de cette façon:

  1. translater les deux points: le point au qui on applique la rotation et le point autour duquel la rotation est faite de sorte que le dernier est positionné à l'origine du système de coordonnées.
  2. La rotation normale (autour de l'origine)
  3. translater les résultats de sorte que le point autour duquel la rotation a été fait atteindre sa position initiale

Mise à l'échelle

Mise à l'échelle autour de l'origine

$$ \begin{bmatrix} {x}'\\ {y}'\\ 1 \end{bmatrix} = \begin{bmatrix} s_x & 0 & 0\\ 0 & s_y & 0\\ 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} x\\ y\\ 1 \end{bmatrix} $$

Si $sx = sy$ alors nous avons mise à l'échelle uniforme, sinon l'échelle non-uniforme.

Le mise à l'échelle autour un point arbitraire

Le mise à l'échelle par rapport à un point arbitraire peut être résolu similaire à la rotation par rapport à un certain point.

Utilisation de la bibliothèque GLM

Dans le laboratoire, on utilise la bibliothèque GLM est une bibliothèque implémentée avec des matrices en forme colonne, exactement le même format que OpenGL. La forme colonne diffère de la forme ligne par l'ordre de stockage des éléments de la matrice dans la mémoire. La matrice de translation est représentée de la manière suivante dans la mémoire:

glm::mat3 Translate(float tx, float ty)
{
	return glm::mat3( 
        	 1,  0, 0,     // colonne 1 en mémoire 
		 0,  1, 0,     // colonne 2 en mémoire
		tx, ty, 1);    // colonne 3 en mémoire
 
}

Pour cette raison, il est plus commode que la matrice être écrite manuellement dans cette forme:

glm::mat3 Translate(float tx, float ty)
{
	return glm::transpose(
		glm::mat3( 1, 0, tx, 
			   0, 1, ty, 
			   0, 0, 1)
	); 
}

Dans le cadre du laboratoire, le fichier Transform2D.h définit les fonctions de calcul des matrices de translation, de rotation et d’échelle. À ce stade, toutes les fonctions renvoient la matrice d'identité. Dans le laboratoire, vous devrez changer le code pour calculer les matrices.

Transformations composées

Pourquoi sont les matrices nécessaires? Pour représenter par une seule matrice de transformation une séquence de transformations élémentaires, au lieu d’appliquer une séquence de transformations élémentaires sur un objet.

Donc, si nous appliquons une rotation, une mise à l'échelle et une translation sur un objet, nous ne faisons pas la rotation de l'objet, l' échellage d’objet suivi par son translation, mais nous calculons une matrice qui représente la transformation composé (rotation, mise à l'échelle et la translation) et nous appliquons cette transformation composé sur l'objet qui doit être transformé.

Ainsi, si nous appliquons une rotation (la matrice de rotation $R$), suivie par un mise à l'échelle ($S$), suivie d'une translation ($T$) sur un point ($x$, $y$), le pointe tournée (${x}'$,${y}'$) est calculé comme suit:

$$ \begin{bmatrix} {x}'\\ {y}'\\ 1 \end{bmatrix} = \begin{bmatrix} 1 & 0 & t_x\\ 0 & 1 & t_y\\ 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} sx & 0 & 0\\ 0 & sy & 0\\ 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} cos(u) & -sin(u) & 0\\ sin(u) & cos(u) & 0\\ 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} x\\ y\\ 1 \end{bmatrix} $$

Ainsi, la matrice de transformation composée $M$ est $M = T * S * R$.

Dans le laboratoire, dans le fichier Laborator3.cpp, il existe un certain nombre d'objets (carrés) pour lesquels Update (), avant de dessiner, définit les matrices de transformation. La commande de dessin est donnée par la fonction RenderMesh2D().

   modelMatrix = glm::mat3(1);
   modelMatrix *= Transform2D::Translate(150, 250);
   RenderMesh2D(meshes["square1"], shaders["VertexColor"], modelMatrix);

Pour l'exemple précédent, la matrice de translation créée translaté le carré actuel en (150 250). Pour les effets d'animation continue, les étapes de translation doivent changer au fil du temps.

Exemple:

tx += deltaTimeSeconds * 100;
ty += deltaTimeSeconds * 100;
model_matrix *= Transform2D::Translate(tx, ty);

Remarque: Si vous ne tenez pas compte de la durée d'exécution d'une image (deltaTimeSeconds), vous créerez des animations dépendantes de la plateforme.

Exemple: Si sur chaque image vous grandissez sur TX avec un pas constant (ex: TX + = 0.01), l'animation se comportera différemment sur un ordinateur qui va plus vite que celui qui va plus lentement. Sur un ordinateur fonctionnant à 50 FPS, l’objet se déplacera de 0,01 * 50 = 0,5 unité vers la droite dans une seconde. Au lieu de cela, sur un ordinateur plus lent fonctionnant à 10 FPS, l'objet se déplacera de 0,01 * 10 = 0,1 unités vers la droite en une seconde, l'animation sera donc 5 fois plus lente.

Pour cette raison, il est bon de garder à l’esprit la vitesse de chaque ordinateur (date à travers le deltaTimeSeconds, qui représente la durée de la trame précédente) et de modifier les étapes de conversion, les angles de rotation et les facteurs en fonction de cette variable.

La transformation fenêtre-porte

Les dessins représentés dans un application graphique (2D ou 3D) sont habituellement présentés dans un système de coordonnées différent de celui de la zone d'affichage.

In exercitiile anterioare din acest laborator, coordonatele obiectelor au fost raportate la dimensiunea ferestrei definita prin glViewport().

Exemplu: Daca viewport-ul meu are coltul din stanga jos (0, 0) si are latimea 1280 si inaltimea 720, atunci toate obiectele ar trebui desenate in acest interval, daca vreau sa fie vizibile. Acest lucru ma conditioneaza sa imi gandesc toata scena in (0, 0) - (1280, 720). Daca vreau sa scap de aceasta limitare, pot sa imi gandesc scena intr-un spatiu logic (de exemplu imi creez toate obiectele in spatiul (-1, -1) - (1, 1), si apoi sa le desenez in poarta de afisare, dar aplicand ceea ce se numeste transformarea fereastra poarta.

In cele ce urmeaza vedem ce presupune aceasta transformare si cum pot sa imi gandesc scena fara sa fiu limitat de dimensiunea viewport-ului.

Définition mathématique

$$ \frac{xp - xpmin}{xpmax - xpmin} = \frac{xf - xfmin}{xfmax - xfmin} $$ $$ \frac{yp - ypmin}{ypmax - ypmin} = \frac{yf - yfmin}{yfmax - yfmin} $$

La transformation est définie par deux rectangles, dans les deux systèmes de coordonnées, appelée fenêtre (de visualisation) et porte (d’affichage).

F: un point dans la fenêtre

P: le point qui F devient par appliquer le transformation de visualisation

La position relative de P dans l’affichage de droite doit être la même position relative de F dans la fenêtre.

$$ sx = \frac{xpmax - xpmin}{xfmax - xfmin} $$

$$ sy = \frac{ypmax - ypmin}{yfmax - yfmin} $$

  • sx, sy dépend de la taille des deux fenêtres
  • tx, ty dépendent des positions des deux fenêtres de l'original système de coordonnées sont définies.

$$ tx = xpmin - sx * xfmin $$ $$ ty = ypmin - sy * yfmin $$

Enfin, la transformation fenêtre-porte a les équations suivantes:

$$ xp = xf * sx + tx $$ $$ yp = yf * sy + ty $$

Nous considérons un même orientation des axes de les deux systèmes de coordonnées. Si elles ont des orientations différentes (comme dans la première image), une correction supplémentaire de la correction de la coordonnée y doit être appliquée.

Les effets de la transformation

  • Augmentation / diminution en fonction de la taille de la fenêtre et la porte
  • Déformation: si la fenêtre et la porte ne sont pas des rectangles semblables
  • Mise à l'échelle uniforme, $s=min(sx,sy)$, l'affichage centrée dans la porte: translation additionnel sur l'axe Ox ou Oy:

$$Tsx = (xpmax - xpmin - s*(xfmax - xfmin)) / 2$$ $$Tsy = (ypmax - ypmin - s*(yfmax - yfmin)) / 2$$

  • Couper les primitives positionées à l'extérieur de la fenetre de visualization

Matricea transformarii fereastra-poarta

De retinut este ca transformarea fereastra poarta presupune o scalare si o translatie. Ea are urmatoarea expresie, cu formulele de calcul pentru sx, sy, tx, ty prezentate anterior:

$$ \begin{bmatrix} xp\\ yp\\ 1 \end{bmatrix} = \begin{bmatrix} sx & 0 & tx\\ 0 & sy & ty\\ 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} xf\\ yf\\ 1 \end{bmatrix} $$

Transformarea de vizualizare este deja implementata in clasa Laborator3_Vis2D:

//2D vizualization matrix
glm::mat3 Laborator3_Vis2D::VisualizationTransf2D(const LogicSpace & logicSpace, const ViewportSpace & viewSpace)
{
	float sx, sy, tx, ty;
	sx = viewSpace.width / logicSpace.width;
	sy = viewSpace.height / logicSpace.height;
	tx = viewSpace.x - sx * logicSpace.x;
	ty = viewSpace.y - sy * logicSpace.y;
 
	return glm::transpose(glm::mat3(
		sx, 0.0f, tx,
		0.0f, sy, ty,
		0.0f, 0.0f, 1.0f));
}

In cadrul laboratorului, in clasa Laborator3_Vis2D, este creat un patrat, in spatiul logic (0,0) - (4,4). De retinut este faptul ca acum nu mai trebuie sa raportam coordonatele patratului la spatiul de vizualizare (cum se intampla in exercitiile anterioare), ci la spatiul logic pe care l-am definit noi.

logicSpace.x = 0;	// logic x
logicSpace.y = 0;	// logic y
logicSpace.width = 4;	// logic width
logicSpace.height = 4;	// logic height
 
glm::vec3 corner = glm::vec3(0.001, 0.001, 0);
length = 0.99f;
 
Mesh* square1 = Object2D::CreateSquare("square1", corner, length, glm::vec3(1, 0, 0));
AddMeshToList(square1);

In functia Update() se deseneaza acelasi patrat creat anterior, de 5 ori: patru patrate in cele patru colturi si un patrat in mijlocul spatiului logic. Se definesc 2 viewport-uri, ambele continand aceleasi obiecte. Primul viewport este definit in jumatatea din stanga a ferestrei de afisare, iar al doilea, in jumatatea din dreapta. Pentru primul viewport se defineste transformarea fereastra poarta default si pentru al doilea viewport, cea uniforma. Observati ca in al doilea viewport patratele raman intotdeauna patrate, pe cand in primul viewport se vad ca dreptunghiuri (adica sunt deformate), daca spatiul logic si spatiul de vizualizare nu sunt reprezentate prin dreptunghiuri asemenea.

Utilizare

Unde se poate folosi aceasta transformare fereastra poarta? De exemplu, intr-un joc 2D cu masini de curse, se doreste in dreapta-jos a ecranului vizualizarea masinii proprii, intr-un minimap. Acest lucru se face prin desenarea scenei de doua ori.

Daca de exemplu toata scena (traseul si toate masinile) este gandita in spatiul logic (-10,-10) - (10,10) (care are dimensiunea 20×20) si spatiul de afisare este (0,0) - (1280, 720), prima data se deseneaza toata scena cu parametrii functiei fereastra-poarta anterior mentionati:

LogicSpace logic_space = LogicSpace(-10, -10, 20, 20);
ViewportSpace view_space = ViewportSpace(0, 0, 1280, 720);
vis_matrix *= VisualizationTransf2D(logic_space, view_space);

Daca la un moment dat masina proprie este in spatiul (2,2) - (5,5), adica de dimensiune 3×3 si vreau sa creez un minimap in coltul din dreapta jos al ecranului de rezolutie 280×220, pot desena din nou aceeasi scena, dar cu urmatoarea transformare fereastra-poarta:

LogicSpace logic_space = LogicSpace(2, 2, 3, 3);
ViewportSpace view_space = ViewportSpace(1000, 500, 280, 220);
vis_matrix *= VisualizationTransf2D(logic_space, view_space);

Laboratorul 3

Descriere laborator

In cadrul acestui laborator aveti de programat in doua clase:

  • Laborator3.cpp, pentru familiarizarea cu transformarile 2D de translatie, rotatie si scalare
  • Laborator3_Vis2D.cpp, pentru familiarizarea cu transformarea fereastra-poarta

Din clasa Main puteti sa alegeti ce laborator rulati:

World *world = new Laborator3();

sau

World *world = new Laborator3_Vis2D();

OpenGL este un API 3D. Desenarea obiectelor 2D si aplicarea transformarilor 2D sunt simulate prin faptul ca facem abstractie de coordonata z.

Transformarea fereastra-poarta este si ea simulata pentru acest framework, dar veti invata pe parcurs ca ea este de fapt inclusa in lantul de transformari OpenGL si ca nu trebuie definita explicit.

Cerinte laborator

  1. Completati functiile de translatie, rotatie, scalare din /Laborator3/Transform2D.h
  2. Sa modifice pasii de translatie si rotatie si scalare pentru cele trei patrate ca sa creeze animatie.
  3. Cu tastele W, A, S, D sa se translateze fereastra logica Laborator3_Vis2D. Cu tastele Z si X sa se faca zoom in si zoom out pe fereastra logica.
egc/laboratoare/fr/03.1540280628.txt.gz · Last modified: 2018/10/23 10:43 by alexandru.gradinaru
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0