Voilà, une petite source sur comment créer une petite scène avec un sol et plusieurs cubes tombant, grâce au moteur Newton Game Dynamics. Je pense que ça peut servir aux débutants, je trouve que la doc officielle est assez dur à utiliser (dans le sens ou elle fait appel à pleins d'autres classes,...). Je dois aller me coucher, je reviendrai demain corriger quelques trucs, en tout cas voici les sources (si quelqu'un veut que je fasse quelque chose de plus consistant pour mettre sur le site, avec des commentaires et tout, ya pas de problème, je peux faire ça ).
NB : j'ai volontairement créer une classe CVector simpliste plutôt qu'une structure, la seule méthode que j'ai trouvé pour passer une structure en paramètre est vraiment crado.
NB 2 : La génération des nombres aléatoires ne semblent pas marcher, je verrais ça demain.
NB 3 : J'utilise la SDL ainsi que le SDL_framerate (la lib sdl_gfx, merci fearyourself, j'ai connu ça grâce à ton tuto, c'est bien pratique !) :
MISE A JOUR 1 : la génération de chiffres aléatoires marche correctement. On a donc à chaque lancement un résultat différent.
MISE A JOUR 2 : création d'une classe virtuelle pure Objet (fait à la va vite, désolé si c'est pas très propre !), puis une classe Boite et Sphere qui en hérite. Ainsi on a des boites ET des sphères, ca fait vraiment très joli ^^
MISE A JOUR 3 : ajout des couleurs comme demandé !
main.cpp :
Boite.h :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260 #include <iostream> #include <ctime> #include <SDL/SDL.h> #include <GL/glew.h> #include <SDL/SDL_framerate.h> #include "Boite.h" void Render (); void Prepare (); void InitSDL (); void InitOGL (); void InitScene (); void Shutdown (); void DessinerCube (); void GetFPS (); int main (int argc, char *argv []) { InitSDL(); InitOGL(); SDL_Event event; bool bQuit = false; FPSmanager manager; SDL_initFramerate (&manager); SDL_setFramerate (&manager, 80); // On limite le fps à 60 img/s while (!bQuit) { Prepare (); Render (); SDL_framerateDelay (&manager); GetFPS (); if (SDL_PollEvent (&event)) { switch (event.type) { case SDL_QUIT: Shutdown (); bQuit = true; break; default: break; } } } return EXIT_SUCCESS; } void GetFPS () { static char titleBar[25] = {0}; static int FPS = 0; float nextSecond = 0.0f; static float prevSecond = 0.0f; FPS++; nextSecond = SDL_GetTicks() * 0.001f; if (nextSecond - prevSecond > 1.0f) { prevSecond = nextSecond; sprintf(titleBar, "%d FPS", FPS); SDL_WM_SetCaption (titleBar, NULL); FPS = 0; } } void InitSDL () { // Initialisation de SDL SDL_Init (SDL_INIT_VIDEO); SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1); // On active le double buffering SDL_Surface * pEcran = SDL_SetVideoMode (640, 480, 32, SDL_OPENGL); if (pEcran == NULL) { std::cerr << "Erreur au paramètrage vidéo : " << SDL_GetError (); } atexit (SDL_Quit); } // PARTIE OPENGL const GLint NOMBRE_BOITES = 30; const GLint NOMBRE_SPHERES = 30; // Variables globales pour Newton NewtonWorld * nWorld = NULL; // Monde Sphere * spheres [NOMBRE_SPHERES]; Boite * sol = NULL; // Pointeur vers un objet sol représentant,... le sol ! Boite * boites [NOMBRE_BOITES]; // Pointeur vers un objet boite1 représentant,... une boîte ! void InitNewton (); void InitOGL () { glClearColor(0.0, 0.0, 0.3, 0.0); glClearDepth(1.0); GLenum err = glewInit(); if (GLEW_OK != err) std::cerr << "Erreur dans GLEW."; glViewport (0, 0, 640, 480); // On règle le Viewport glMatrixMode (GL_PROJECTION); glLoadIdentity (); gluPerspective (60.0, 640.0 / 480.0, 0.1, 1000.0); glMatrixMode (GL_MODELVIEW); glLoadIdentity (); // On rétablit la matrice identité glEnable (GL_DEPTH_TEST); glEnable (GL_COLOR_MATERIAL); glEnable (GL_LIGHTING); glEnable (GL_LIGHT0); GLfloat LampeDiffuse [] = {1.0f, 1.0f, 1.0f}; GLfloat LampeAmbient [] = {0.75f, 0.75f, 0.75f}; GLfloat LampePosition [] = {6.0f, 10.0f, 5.0f, 1.0f}; glLightfv (GL_LIGHT0, GL_DIFFUSE, LampeDiffuse); glLightfv (GL_LIGHT0, GL_SPECULAR, LampeDiffuse); glLightfv (GL_LIGHT0, GL_AMBIENT, LampeAmbient); glLightfv (GL_LIGHT0, GL_POSITION, LampePosition); // On initialise Newton InitNewton (); } void Prepare () { static GLfloat tempsPrecedent = 0.0f; GLfloat tempsActuel = 0.0f; tempsPrecedent = SDL_GetTicks () - tempsPrecedent; tempsActuel = SDL_GetTicks (); NewtonUpdate (nWorld, (tempsActuel - tempsPrecedent)); } void Render () { glClearColor(0.0f, 0.0, 0.3, 0.0); glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity (); gluLookAt (0.0f, 0.0f, 20.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f); // Puis quelques rotations afin de bien voir le sol glRotatef(15, 1, 0, 0); glRotatef(45, 0, 1, 0); // On va d'abord dessiner le sol glColor3f (1.0f, 0.0f, 0.0f); sol->Dessiner (); // Puis la boîte for (int i = 0 ; i < NOMBRE_BOITES ; i++) { glColor3f (0.0f, 0.0f, 1.0f); boites [i]->Dessiner (); } for (int i = 0 ; i < NOMBRE_SPHERES ; i++) { spheres [i]->Dessiner (); } SDL_GL_SwapBuffers(); } void Shutdown () { delete sol, sol = NULL; for (int i = 0 ; i < NOMBRE_BOITES ; i++) delete boites [i], boites [i] = NULL; for (int i = 0 ; i < NOMBRE_SPHERES ; i++) delete spheres [i], spheres [i] = NULL; NewtonDestroy (nWorld); } void InitNewton () { nWorld = NewtonCreate (NULL, NULL); // On initialise nWorld // On définit le sol CVector taille (10.0f, 0.5f, 10.0f); CVector position (-5.0f, 0.0f, 0.0f); CVector couleur (100, 100, 100); // On alloue la mémoire. Le troisième argument est false pour signifier qu'il sera // immobile et donc ne bougera pas sol = new Boite (); sol->SetColor (couleur); sol->Initialiser (nWorld, taille, position, false, 0.0f); srand (time (NULL)); // A présent le cube for (int i = 0 ; i < NOMBRE_SPHERES ; i++) { GLfloat x, y, z; x = -10 + rand()%15; y = 1 + rand()%10; z = -10 + rand()%15; position.ReglerCoordonnees (x, y, z); // On sélectionne les trois couleurs couleur.x = rand() % 256; couleur.y = rand() % 256; couleur.z = rand() % 256; spheres [i] = new Sphere (); spheres [i]->Initialiser (nWorld, 1.0f, position, true, 15.0f); spheres [i]->SetColor (couleur); } // A présent le cube for (int i = 0 ; i < NOMBRE_BOITES ; i++) { GLfloat x, y, z; x = -10 + rand()%15; y = 1 + rand()%10; z = -10 + rand()%15; taille.ReglerCoordonnees (1.0f, 1.0f, 1.0f); position.ReglerCoordonnees (x, y, z); // On sélectionne les trois couleurs couleur.x = rand() % 256; couleur.y = rand() % 256; couleur.z = rand() % 256; boites [i] = new Boite (); boites [i]->Initialiser (nWorld, taille, position, true, 10.0f); boites [i]->SetColor (couleur); } }
Boite.cpp :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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 #ifndef BOITE_H #define BOITE_H #include <GL/glew.h> #include <Newton/Newton.h> // Fichier d'include pour utiliser le Newton Engine #include "CVector.h" // Structure matrix typedef struct { GLfloat matrice [4][4]; } matrix; class Objet { // Fonction amie qui se chargera d'appliquer les forces à l'objet. // Elle sera utilisée en fonction Callback par le Newton Engine friend void ApplyForceAndTorqueCallback (const NewtonBody * nBody); public: Objet (); // Constructeur virtual ~Objet (); // Destructeur virtual void Initialiser () {}; // Classe pure virtual void Dessiner () = 0; virtual void SetColor (const CVector &) = 0; protected: NewtonBody * m_pBody; // Pointeur vers un NewtonBody matrix m_matrice; // Matrice de l'objet (pour sa position) GLfloat m_masse; // Masse de l'objet CVector m_couleur; // Couleur de l'objet }; class Boite : public Objet { public: Boite (); // Constructeur virtual ~Boite (); // Destructeur // Fonction se chargeant de l'initialisation de la boîte virtual void Initialiser (NewtonWorld * nWorld, const CVector, const CVector, GLboolean mobile = false, GLfloat masse = 1.0f); virtual void Dessiner (); // Dessine l'objet virtual void SetColor (const CVector &); // Règle les couleurs private: CVector * m_taille; // Dimensions de la boîte }; class Sphere : public Objet { public: Sphere (); // Constructeur virtual ~Sphere (); // Destructeur // Fonction se chargeant de l'initialisation de la boîte virtual void Initialiser (NewtonWorld * nWorld, GLfloat, const CVector, GLboolean mobile = false, GLfloat masse = 1.0f); virtual void Dessiner (); // Dessine l'objet virtual void SetColor (const CVector &); // Règle les couleurs private: GLfloat m_rayon; GLUquadric * m_sphere; }; #endif // BOITE_H
CVector.h :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259 #include "Boite.h" void ApplyForceAndTorqueCallback (const NewtonBody * nBody) { // Cette fonction est une fonction Callback. Elle sera appelée à chaque fois // qu'une modification aura lieu sur le corps // On récupère en premier lieu la masse ainsi que l'inertie GLfloat masse; // Contiendra la masse de l'objet pris en paramètre par la fonction CVector inertie; // Contiendra l'inertie du corps CVector force; // Spécifiera la force appliquée sur le corps NewtonBodyGetMassMatrix (nBody, &masse, &inertie.x, &inertie.y, &inertie.z); force.x = 0.0f; force.y = -masse * 9.81; // 9.81 est l'attraction gravitationnelle de la Terre force.z = 0.0f; NewtonBodyAddForce (nBody, &force.x); // On ajoute la force au corps } Objet::Objet () : m_pBody (NULL) { // Ne fait rien } Objet::~Objet () { NewtonDestroyBody (NewtonBodyGetWorld (m_pBody), m_pBody); } Boite::Boite () : Objet (), m_taille (NULL) { // Ne fais rien } Boite::~Boite() { // Ne fait rien, l'objet est détruit par la classe de base } void Boite::Initialiser (NewtonWorld * nWorld, const CVector taille, const CVector position, GLboolean mobile, GLfloat masse) { // On initialise le vecteur de dimensions m_taille = new CVector (taille.x, taille.y, taille.z); m_taille->x *= 0.5f; m_taille->y *= 0.5f; m_taille->z *= 0.5f; // On définit la masse de l'objet m_masse = masse; // On initialise la matrice, qu'on définit comme matrice identité m_matrice.matrice [0][0] = m_matrice.matrice [1][1] = m_matrice.matrice [2][2] = m_matrice.matrice [3][3] = 1.0f; // On définit la matrice de manière à ce que l'objet soit placé aux positions // spécifiées en utilisant la dernière colonne de la matrice m_matrice.matrice [3][0] = position.x; m_matrice.matrice [3][1] = position.y; m_matrice.matrice [3][2] = position.z; // On initialise la collision box NewtonCollision * collision = NULL; // On créé la collision box aux dimensions de l'objet collision = NewtonCreateBox (nWorld, m_taille->x * 2, m_taille->y * 2, m_taille->z * 2, NULL); // On initialise le corps avec la collision box m_pBody = NewtonCreateBody (nWorld, collision); // On détruit la collision box, on n'en a plus besoin NewtonReleaseCollision (nWorld, collision); // Enfin, on assigne notre matrix (qui représente donc sa position dans l'espace) // à notre corps grâce à la fonction NewtonBodySetMatrix NewtonBodySetMatrix (m_pBody, &m_matrice.matrice [0][0]); // On initialise à présent les propriétés physiques de l'objet. Toutefois, donner // à un objet qui ne bougera pas une masse, lui associer un callback,... n'a aucun // intêret, on vérifie donc si l'objet sera mobile ou immobile if (mobile == true) { // On calcul l'inertie du corps, en passant par une petite formule CVector inertie; inertie.x = 0.7f * m_masse * (m_taille->y * m_taille->y + m_taille->z * m_taille->z) / 12; inertie.y = 0.7f * m_masse * (m_taille->x * m_taille->x + m_taille->z * m_taille->z) / 12; inertie.z = 0.7f * m_masse * (m_taille->x * m_taille->x + m_taille->y * m_taille->y) / 12; // On définit ensuite la masse et l'inertie pour ce corps NewtonBodySetMassMatrix (m_pBody, m_masse, inertie.x, inertie.y, inertie.z); // On règle enfin le Callback, qui sera nécessaire pour que le corps bouge NewtonBodySetForceAndTorqueCallback (m_pBody, ApplyForceAndTorqueCallback); } } void Boite::SetColor (const CVector & couleur) { m_couleur.x = couleur.x / 255; m_couleur.y = couleur.y / 255; m_couleur.z = couleur.z / 255; } void Boite::Dessiner () { // Toutes les modifications effectuées dans le Callback modifient la matrice de // l'objet, ce qui permet à l'objet de "bouger" NewtonBodyGetMatrix (m_pBody, &m_matrice.matrice [0][0]); glPushMatrix (); // On sauvegarde la matrice actuelle glMultMatrixf (&m_matrice.matrice [0][0]); // On multiplie la matrice actuelle // par la matrice du corps, ainsi // le corps sera dessiné au bon endroit glColorMaterial (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); glColor3f (m_couleur.x, m_couleur.y, m_couleur.z); glColorMaterial (GL_FRONT_AND_BACK, GL_SPECULAR); glColor3f (1.0f, 1.0f, 1.0f); glColorMaterial (GL_FRONT_AND_BACK, GL_EMISSION); glColor3f (0.0f, 0.0f, 0.0f); glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, 128); glBegin(GL_QUADS); // Devant glNormal3f (0.0f, 0.0f, 1.0f); glVertex3f (-m_taille->x, -m_taille->y, m_taille->z); glVertex3f (m_taille->x, -m_taille->y, m_taille->z); glVertex3f (m_taille->x, m_taille->y, m_taille->z); glVertex3f (-m_taille->x, m_taille->y, m_taille->z); // Derrière glNormal3f (0.0f, 0.0f, -1.0f); glVertex3f (-m_taille->x, -m_taille->y, -m_taille->z); glVertex3f (-m_taille->x, m_taille->y, -m_taille->z); glVertex3f (m_taille->x, m_taille->y, -m_taille->z); glVertex3f (m_taille->x, -m_taille->y, -m_taille->z); // Haut glNormal3f (0.0f, 1.0f, 0.0f); glVertex3f (-m_taille->x, m_taille->y, -m_taille->z); glVertex3f (-m_taille->x, m_taille->y, m_taille->z); glVertex3f (m_taille->x, m_taille->y, m_taille->z); glVertex3f (m_taille->x, m_taille->y, -m_taille->z); // Bas glNormal3f (0.0f, -1.0f, 0.0f); glVertex3f (-m_taille->x, -m_taille->y, -m_taille->z); glVertex3f (m_taille->x, -m_taille->y, -m_taille->z); glVertex3f (m_taille->x, -m_taille->y, m_taille->z); glVertex3f (-m_taille->x, -m_taille->y, m_taille->z); // Droite glNormal3f (1.0f, 0.0f, 0.0f); glVertex3f (m_taille->x, -m_taille->y, -m_taille->z); glVertex3f (m_taille->x, m_taille->y, -m_taille->z); glVertex3f (m_taille->x, m_taille->y, m_taille->z); glVertex3f (m_taille->x, -m_taille->y, m_taille->z); // Gauche glNormal3f (-1.0f, 0.0f, 0.0f); glVertex3f (-m_taille->x, -m_taille->y, -m_taille->z); glVertex3f (-m_taille->x, -m_taille->y, m_taille->z); glVertex3f (-m_taille->x, m_taille->y, m_taille->z); glVertex3f (-m_taille->x, m_taille->y, -m_taille->z); glEnd (); glPopMatrix (); // On rétablit la matrice } Sphere::Sphere () : Objet (), m_sphere (NULL) { // Ne fais rien } Sphere::~Sphere() { gluDeleteQuadric (m_sphere); } void Sphere::Initialiser (NewtonWorld * nWorld, const GLfloat rayon, const CVector position, GLboolean mobile, GLfloat masse) { // On initialise la sphere m_sphere = gluNewQuadric (); m_rayon = rayon; // On définit la masse de l'objet m_masse = masse; // On initialise la matrice, qu'on définit comme matrice identité m_matrice.matrice [0][0] = m_matrice.matrice [1][1] = m_matrice.matrice [2][2] = m_matrice.matrice [3][3] = 1.0f; // On définit la matrice de manière à ce que l'objet soit placé aux positions // spécifiées en utilisant la dernière colonne de la matrice m_matrice.matrice [3][0] = position.x; m_matrice.matrice [3][1] = position.y; m_matrice.matrice [3][2] = position.z; // On initialise la collision box NewtonCollision * collision = NULL; // On créé la collision box aux dimensions de l'objet collision = NewtonCreateSphere (nWorld, m_rayon, m_rayon, m_rayon, NULL); // On initialise le corps avec la collision box m_pBody = NewtonCreateBody (nWorld, collision); // On détruit la collision box, on n'en a plus besoin NewtonReleaseCollision (nWorld, collision); // Enfin, on assigne notre matrix (qui représente donc sa position dans l'espace) // à notre corps grâce à la fonction NewtonBodySetMatrix NewtonBodySetMatrix (m_pBody, &m_matrice.matrice [0][0]); // On initialise à présent les propriétés physiques de l'objet. Toutefois, donner // à un objet qui ne bougera pas une masse, lui associer un callback,... n'a aucun // intêret, on vérifie donc si l'objet sera mobile ou immobile if (mobile == true) { // On calcul l'inertie du corps, en passant par une petite formule CVector inertie; inertie.x = inertie.y = inertie.z = 0.f * m_masse * rayon * rayon; // On définit ensuite la masse et l'inertie pour ce corps NewtonBodySetMassMatrix (m_pBody, m_masse, inertie.x, inertie.y, inertie.z); // On règle enfin le Callback, qui sera nécessaire pour que le corps bouge NewtonBodySetForceAndTorqueCallback (m_pBody, ApplyForceAndTorqueCallback); } } void Sphere::SetColor (const CVector & couleur) { m_couleur.x = couleur.x / 255; m_couleur.y = couleur.y / 255; m_couleur.z = couleur.z / 255; } void Sphere::Dessiner () { // Toutes les modifications effectuées dans le Callback modifient la matrice de // l'objet, ce qui permet à l'objet de "bouger" NewtonBodyGetMatrix (m_pBody, &m_matrice.matrice [0][0]); glPushMatrix (); // On sauvegarde la matrice actuelle glMultMatrixf (&m_matrice.matrice [0][0]); // On multiplie la matrice actuelle // par la matrice du corps, ainsi // le corps sera dessiné au bon endroit glColorMaterial (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); glColor3f (m_couleur.x, m_couleur.y, m_couleur.z); gluSphere (m_sphere, m_rayon, 50, 50); glPopMatrix (); // On rétablit la matrice }
CVector.cpp :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 #ifndef CVECTOR_H #define CVECTOR_H #include <GL/glew.h> class CVector { public: CVector (); CVector (const GLfloat iX, const GLfloat iY, const GLfloat iZ); virtual ~CVector(); void ReglerCoordonnees (const GLfloat iX, const GLfloat iY, const GLfloat iZ); GLfloat x, y, z; }; #endif // CVECTOR_H
Screenshots :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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 #include "CVector.h" CVector::CVector () : x (0.0f), y (0.0f), z (0.0f) { // Ne fait rien } CVector::CVector (const GLfloat iX, const GLfloat iY, const GLfloat iZ) : x (iX), y (iY), z (iZ) { // Ne fait rien } CVector::~CVector() { // Ne fait rien } void CVector::ReglerCoordonnees (const GLfloat iX, const GLfloat iY, const GLfloat iZ) { x = iX; y = iY; z = iZ; }
Couleurs :
NB : ca tourne bien à 80 fps comme précisé avec la lib SDL_framerate, mais il faut quelques secondes à la fenetre pour se mettre à 80 fps...
Partager