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.

Transformari compuse

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$.

In cadrul laboratorului, in fisierul Laborator3.cpp, exista o serie de obiecte (patrate) pentru care, in functia Update(), inainte de desenare, se definesc matricile de transformari. Comanda de desenare se da prin functia RenderMesh2D().

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

Pentru exemplul anterior, matricea de translatie creata va avea ca efect translatarea patratului curent cu (150, 250). Pentru efecte de animatie continua, pasii de translatie ar trebui sa se modifice in timp.

Exemplu:

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

Retineti: daca la animatie nu tineti cont de timpul de rulare al unui frame (deltaTimeSeconds), veti crea animatii dependente de platforma.

Exemplu: daca la fiecare frame cresteti pe tx cu un pas constant (ex: tx += 0.01), atunci animatia se va comporta diferit pe un calculator care merge mai repede fata de unul care merge mai incet. Pe un calculator care ruleaza la 50 FPS, obiectul se va deplasa 0.01 * 50 = 0.5 unitati in dreapta intr-o secunda. In schimb, pe un calculator mai incet, care ruleaza la 10 FPS, obiectul se va deplasa 0.01 * 10 = 0.1 unitati in dreapta intr-o secunda, deci animatia va fi de 5 ori mai lenta.

Din acest motiv este bine sa tineti cont de viteza de rulare a fiecarui calculator (data prin deltaTimeSeconds, care reprezinta timpul de rulare al frame-ului anterior) si sa modificati pasii de translatie, unghiurile de rotatie si factorii de scalare in functie de aceasta variabila.

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.

Definitia matematica:

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

Transformarea este definita prin 2 dreptunghiuri, in cele doua sisteme de coordonate, numite fereastra sau spatiul logic si poarta, sau spatiul de afisare. De aici numele de transformarea fereastra-poarta sau transformarea de vizualizare 2D.

F: un punct din fereastra

P: punctul in care se transforma F prin transformarea de vizualizare

Pozitia relativa a lui P in poarta de afisare trebuie sa fie aceeasi cu pozitia relativa a lui F in fereastra.

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

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

  • sx, sy depind de dimensiunile celor doua ferestre
  • tx, ty depind de pozitiile celor doua ferestre fata de originea sistemului de coordonate in care sunt definite.

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

In final, transformarea fereastra poarta are urmatoarele ecuatii:

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

Consideram o aceeasi orientare a axelor celor doua sisteme de coordonate. Daca acestea au orientari diferite (ca in prima imagine), trebuie aplicata o transformare suplimentara de corectie a coordonatei y.

Efectele transformarii

  • marire/micsorare, in functie de dimensiunile ferestrei si ale portii
  • deformare daca fereastra si poarta nu sunt dreptunghiuri asemenea
  • pentru scalare uniforma, $s=min(sx,sy)$, afisarea centrata in poarta presupune o translatie suplimentara pe axa Ox sau pe axa Oy:

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

  • decuparea primitivelor aflate in afara ferestrei vizuale

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.1540279922.txt.gz · Last modified: 2018/10/23 10:32 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