8.2.3 Écrire camera.cpp

Maintenant le fichier camera.cpp, qui commence, lui aussi, comme d'habitude :

1
2
3
#include "camera.h"

using namespace std;

Constructeurs et destructeur :

1
2
3
4
5
6
7
8
9
10
11
12
13
Camera::Camera(){
	this->initialisation(VECT_NULL, 0, M_PI/2, 0);
}

Camera::Camera(const Vecteur & position, double theta, double phi, double rouli){
	this->initialisation(position, theta, phi, rouli);
}

Camera::Camera(const Camera & camera){
	copyCamera(camera);
}

Camera::~Camera(){}

C'est sur il ne fallait pas s'attendre à quelque chose de compliqué.

Les deux fonctions d'observation :

1
2
3
4
5
6
7
8
void Camera::see(){
	Vecteur obj = this->position + this->visee;
	gluLookAt(p_position.getx(), p_position.gety(), p_position.getz(), obj.getx(), obj.gety(), obj.getz(), p_up.getx(), p_up.gety(), p_up.getz());
}

void Camera::see(const Vecteur & object){
	gluLookAt(p_position.getx(), p_position.gety(), p_position.getz(), object.getx(), object.gety(), object.getz(), p_up.getx(), p_up.gety(),p_up.getz());
}

Là encore, nous avons déjà vue la fonction gluLookAt.

L'ensemble des seteurs :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void Camera::setAll(const Vecteur & position, double theta, double phi, double rouli){
	this->initialisation(position, theta, phi, rouli);
}

void Camera::setPosition(const Vecteur & position){p_position = position;}

void Camera::setAngles(double theta, double phi,double rouli){
	this->theta = theta;
	this->phi = phi;
	this->rouli = rouli;
	this->update();
}

void Camera::setTheta(double theta){p_theta = theta;update();}
void Camera::setPhi(double phi){p_phi = phi;update();}
void Camera::setRouli(double rouli){p_rouli = rouli;update();}

La fonction pour déplacer la Camera de manière quelconque :

1
void Camera::move(const Vecteur & dm){p_position += dm;}

Vous voyez que c'est utile de redéfinir les opérateurs.

Les fonction qui déplacent la Camera le long de ses axes :

1
2
3
4
5
6
7
8
9
10
11
void Camera::moveVisee(double dl){
	p_position += p_visee.getUnit()*dl;
}

void Camera::moveUp(double dl){
	p_position += p_up.getUnit()*dl;
}

void Camera::moveLeft(double dl){
	p_position += p_planGauche.getUnit()*dl;
}

Fonction qui permet à la caméra de faire une rotation :

1
2
3
4
5
6
void Camera::rotation(double dTheta, double dPhi,double dRouli){
	p_theta += dTheta;
	p_phi += dPhi;
	p_rouli += dRouli;
	update();
}

Les fonction qui permettent de faire tourner la Camera sur elle-même :

1
2
3
4
5
6
7
8
9
10
11
void Camera::rotationLeft(double dTheta){
	if(p_up.getz() >= 0) p_theta += dTheta;
	else p_theta -= dTheta;
	update();
}

void Camera::rotationRight(double dTheta){
	if(p_up.getz() >= 0) p_theta -= dTheta;
	else p_theta += dTheta;
	update();
}

Les geteurs :

1
2
3
4
5
6
7
8
9
10
11
Vecteur Camera::getPosition() const{return p_position;}

Vecteur Camera::getVisee() const{return p_visee;}

Vecteur Camera::getUp() const{return p_up;}

double Camera::getTheta() const{return p_theta;}

double Camera::getPhi() const{return p_phi;}

double Camera::getRouli() const{return p_rouli;}

L'opérateur = :

1
2
3
4
Camera & Camera::operator = (const Camera & camera){
	copyCamera(camera);
	return *this;
}

La fonction d'initialisation :

1
2
3
4
5
6
7
void Camera::initialisation(const Vecteur & position, double theta, double phi, double rouli){ ///initialise la caméra
	p_position = position;
	p_theta = theta;
	p_phi = phi;
	p_rouli = rouli;
	update();
}

La fonction de copie :

1
2
3
4
5
6
7
8
void Camera::copyCamera(const Camera & camera){                //copie la caméra
	p_position = camera.p_position;               //position de la caméra
	p_up = camera.p_up;                          //verticale
	p_theta = camera.p_theta;                   //angle d'orientation de la caméra
	p_phi = camera.p_phi;                      //angle d'orientation de la caméra
	p_rouli = camera.p_rouli;                 //angle d'orientation de la caméra
	p_planGauche = camera.p_planGauche;
}

La fonction qui met à jour les Vecteurs de la classe :

1
2
3
4
5
void Camera::update(){
	p_visee.setXYZ(cos(p_theta)*sin(p_phi),sin(p_theta)*sin(p_phi), cos(p_phi)); //le Vecteur de visée est bon
	p_planGauche.setXYZ(cos(p_theta + M_PI/2.0)*sin(p_rouli), sin(p_theta + M_PI/2.0)*sin(p_rouli), cos(p_rouli)); //Vecteur unit bon
	p_up = (p_visee^p_planGauche).getUnit();
}

Au secours il y a plein de fonctions de trigo, je n'y comprend plus rien.

On utilise se que l'on appelle des coordonnées sphérique. Imaginez un point M(x, y, z) dans un repère cartésien (normal), et O(0, 0, 0) le centre de ce repère (on dit aussi l'origine). Le problème dans notre cas c'est que nous n'avons pas ces informations (x, y, z) mais que deux angles theta (angle MOx, angle que fait la projection du Vecteur OM dans le plan xOy avec Ox) et phi (l'angle MOz) et une longueur que l'on prendra égale à 1, dans ces conditions les mathématiciens nous disent que l'on peut écrire les coordonnées du Vecteur OM dans un autre repère que le repère cartésien, le repère sphérique. On à donc les égalités suivantes :

  • x = cos(theta)*sin(phi)
  • y = sin(theta)*sin(phi)
  • z = cos(phi)

C'est de loin la seule fonction recherchée de cette classe (il faut reconnaître que les autres sont affligeantes de simplicité).

Décomposons cette fonction :

  • On créé un Vecteur unitaire p_planGauche, qui représente le rouli de la Camera dans le plan perpendiculaire à visee
  • On initialise visee en coordonnées sphériques
  • On fait le produit vectoriel entre p_planGauche et p_visee et on obtient le Vecteur p_up (c'est un truc de mathématiciens).

Pourquoi M_PI/2 ?

Alors, déjà M_PI est une constante de math.h c'est le nombre pi (arrondit bien sur), et comme les fonction de trigo de math.h fonctionnent avec des angles en gradient, on est obligé d’utiliser pi (enfin M_PI).

Maintenant essayez de réécrire ça sans les opérateurs sur les Vecteurs (non le faites pas c'est une blague). En tout cas ici vous avez l'illustration de l'utilité des opérateurs.

Pour illustrer le calcul que l'on vient de faire :

  • pointez quelque chose, devant vous, avec l'index de votre main droite
  • levez votre pouce
  • mettez votre majeur perpendiculairement à votre index

Dans ce cas :

  • votre pouce est le Vecteur p_up
  • votre index est le Vecteur p_visee
  • votre majeur est le Vecteur p_planGauche

Un petit résumé :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
#include "camera.h"

using namespace std;

///constructeur par défaut de la caméra
Camera::Camera(){
	this->initialisation(VECT_NULL, 0, M_PI/2, 0);
}

///constructeur de la caméra avec des angles
/**	@param position : position de la caméra
	@param theta : angle polaire avec l'axe des abscisses (en polaire si phi = M_PI/2)
	@param phi : angle de la composante verticale en coordonnées sphériques
	@param rouli : représente le rouli de la caméra, si elle est penchée sur la droite ou la gauche
	
*/
Camera::Camera(const Vecteur & position, double theta, double phi, double rouli){
	this->initialisation(position, theta, phi, rouli);
}

///constructeur de copie de la caméra
/**	@param camera : caméra à copier
*/
Camera::Camera(const Camera & camera){
	copyCamera(camera);
}

///destructeur de la Caméra
Camera::~Camera(){}

///fonction qui met en route la caméra et dit a OpenGl où il faut regarder
void Camera::see(){
	Vecteur obj = p_position + p_visee;
	gluLookAt(p_position.getx(), p_position.gety(), p_position.getz(), obj.getx(), obj.gety(), obj.getz(), p_up.getx(), p_up.gety(), p_up.getz());
}

///fonction qui pointe la caméra vers un objet
/**	@param object : objet à regarder
*/
void Camera::see(const Vecteur & object){
	gluLookAt(p_position.getx(), p_position.gety(), p_position.getz(), object.getx(), object.gety(), object.getz(), p_up.getx(), p_up.gety(), p_up.getz());
}

///initialise toutes les variables de la caméra
/**	@param position : position de la caméra
	@param theta : angle polaire avec l'axe des abscisses (en polaire si phi = M_PI/2)
	@param phi : angle de la composante verticale en coordonnées sphériques
	@param rouli : représente le rouli de la caméra, si elle est penchée sur la droite ou la gauche
*/
void Camera::setAll(const Vecteur & position, double theta, double phi, double rouli){
	this->initialisation(position, theta, phi, rouli);
}

///initialise la position de la caméra
/**	@param position : Vecteur position de la caméra
*/
void Camera::setPosition(const Vecteur & position){p_position = position;}

///initialise tout les angles de la caméra
/**	@param theta : angle polaire avec l'axe des abscisses (en polaire si phi = M_PI/2)
	@param phi : angle de la composante verticale en coordonnées sphériques
	@param rouli : représente le rouli de la caméra, si elle est penchée sur la droite ou la gauche
*/
void Camera::setAngles(double theta, double phi,double rouli){
	p_theta = theta;
	p_phi = phi;
	p_rouli = rouli;
	update();
}

///initialise l'angle théta
/**	@param theta : angle polaire avec l'axe des abscisses (en polaire si phi = M_PI/2)
*/
void Camera::setTheta(double theta){p_theta = theta;update();}

///initialise l'angle phi
/**	@param phi : angle de la composante verticale en coordonnées sphériques
*/
void Camera::setPhi(double phi){p_phi = phi;update();}

///initialise l'angle de rouli
/**	@param rouli : représente le rouli de la caméra, si elle est penchée sur la droite ou la gauche
*/
void Camera::setRouli(double rouli){p_rouli = rouli;update();}

///change la position de la caméra de dm
/**	@param dm : variation de la position de la caméra
*/
void Camera::move(const Vecteur & dm){p_position += dm;}

///bouge la caméra le long de sa ligne de visée
/**	@param dl : distance à parcourir
*/
void Camera::moveVisee(double dl){
	p_position += p_visee.getUnit()*dl;
}

///bouge la caméra le long de son axe vertical
/**	@param dl : distance à parcourir
*/
void Camera::moveUp(double dl){
	p_position += p_up.getUnit()*dl;
}

///bouge la caméra vers la gauche
/**	@param dl : distance à parcourir
*/
void Camera::moveLeft(double dl){
	p_position += p_planGauche.getUnit()*dl;
}

///fonction qui fait tourner la caméra à gauche
/**	@param dTheta : angle de rotation
*/
void Camera::rotationLeft(double dTheta){
	if(p_up.getz() >= 0) p_theta += dTheta;
	else p_theta -= dTheta;
	update();
}

///fonction qui fait tourner la caméra à droite
/**	@param dTheta : angle de rotation
*/
void Camera::rotationRight(double dTheta){
	if(p_up.getz() >= 0) p_theta -= dTheta;
	else p_theta += dTheta;
	update();
}

///Fonction qui modifie l'orientation de la caméra
/**	@param dTheta : modification de l'angle théta
	@param dPhi : modification de l'angle phi
	@param dRouli : modification de l'angle de rouli
*/
void Camera::rotation(double dTheta, double dPhi,double dRouli){
	p_theta += dTheta;
	p_phi += dPhi;
	p_rouli += dRouli;
	update();
}

///renvoie la position de la caméra
/**	@return Vecteur position de la caméra
*/
Vecteur Camera::getPosition() const{return p_position;}

///renvoie le @a Vecteur visée de la caméra
/**	@return @a Vecteur visée de la caméra
*/
Vecteur Camera::getVisee() const{return p_visee;}

///renvoie le @a Vecteur verticale de la caméra
/**	@return @a Vecteur verticale de la caméra
*/
Vecteur Camera::getUp() const{return p_up;}

///renvoie le @a Vecteur planGauche de la caméra
/**	@return @a Vecteur planGauche de la caméra
*/
Vecteur Camera::getGauche() const{return p_planGauche;}

///renvoie l'angle théta de la caméra
/**	@return l'angle théta de la caméra
*/
double Camera::getTheta() const{return p_theta;}

///renvoie l'angle phi de la caméra
/**	@return l'angle phi de la caméra
*/
double Camera::getPhi() const{return p_phi;}

///renvoie l'angle de rouli de la caméra
/**	@return l'angle de rouli de la caméra
*/
double Camera::getRouli() const{return p_rouli;}

///Définition de l'opérateur = pour la caméra
/**	@param camera : caméra passée par référence
	@return caméra (*this) 
*/
Camera & Camera::operator = (const Camera & camera){
	copyCamera(camera);
	return *this;
}

///Fonction qui copie tout les paramètres de la caméra
/**	@param camera : caméra passée par référence
*/
void Camera::copyCamera(const Camera & camera){                //copie la caméra
	p_position = camera.p_position;               //position de la caméra
	p_up = camera.p_up;                          //verticale
	p_theta = camera.p_theta;                   //angle d'orientation de la caméra
	p_phi = camera.p_phi;                      //angle d'orientation de la caméra
	p_rouli = camera.p_rouli;                 //angle d'orientation de la caméra
	p_planGauche = camera.p_planGauche;
}

///Fonction qui initialise la caméra
/**	@param position : position de la caméra
	@param theta : angle polaire avec l'axe des abscisses (en polaire si phi = M_PI/2)
	@param phi : angle de la composante verticale en coordonnées sphériques
	@param rouli : représente le rouli de la caméra, si elle est penchée sur la droite ou la gauche
*/
void Camera::initialisation(const Vecteur & position, double theta, double phi, double rouli){ ///initialise la caméra
	p_position = position;
	p_theta = theta;
	p_phi = phi;
	p_rouli = rouli;
	update();
}

///Fonction qui recalcule les @a Vecteur de la caméra par rapport aux angles théta, phi et rouli
void Camera::update(){
	p_visee.setXYZ(cos(p_theta)*sin(p_phi),sin(p_theta)*sin(p_phi), cos(p_phi)); //le Vecteur de visée est bon
	p_planGauche.setXYZ(cos(p_theta + M_PI/2.0)*sin(p_rouli), sin(p_theta + M_PI/2.0)*sin(p_rouli), cos(p_rouli)); //Vecteur unit bon
	p_up = (p_visee^p_planGauche).getUnit();
}

Et voilà, une caméra prête à l'emploi.