Bonjour,
Je met en place une camera quaternion. J'ai suivi le tutoriel Nehe et un autre site sur le net. La caméra qq soit el mvt de souris ne réagit pas correctement. diagonale droite vers le bas...
Voici mon Quaternionma camera
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 public class Quaternion { private float w; private float x; private float y; private float z; /** Constructeur */ public Quaternion() { w = 1.0f; x = 0.0f; y = 0.0f; z = 0.0f; } /** * Transforme un quaternion en un quaternion représentant une rotation quelconque dans l'espace */ public void createFromAxisAngle(float x, float y, float z, float degrees) { // First we want to convert the degrees to radians // since the angle is assumed to be in radians float angle = (degrees / 180.0f) * (float) Math.PI; // Here we calculate the sin( theta / 2) once for optimization float result = (float) Math.sin(angle / 2.0f); // Calcualte the w value by cos( theta / 2 ) this.w = (float) Math.cos(angle / 2.0f); // Calculate the x, y and z of the quaternion this.x = x * result; this.y = y * result; this.z = z * result; normaliser(); } /** * Normalise le quaternion courant */ public void normaliser() { float norme = norme(); // On ne normalise pas le vecteur nul if (norme != 0.0f) { w = w / norme; x = x / norme; y = y / norme; z = z / norme; } } /** * Renvoie la norme du quaternion courant */ public float norme() { return w * w + x * x + y * y + z * z; } /** * Pour créer à partir d'un quaternion une matrice qui peut être utilisée par OpenGL */ public void createMatrix(float[] matrix) { // float[] matrix = new float[16]; // First row matrix[0] = 1.0f - 2.0f * (y * y + z * z); matrix[1] = 2.0f * (x * y + z * w); matrix[2] = 2.0f * (x * z - y * w); matrix[3] = 0.0f; // Second row matrix[4] = 2.0f * (x * y - z * w); matrix[5] = 1.0f - 2.0f * (x * x + z * z); matrix[6] = 2.0f * (z * y + x * w); matrix[7] = 0.0f; // Third row matrix[8] = 2.0f * (x * z + y * w); matrix[9] = 2.0f * (y * z - x * w); matrix[10] = 1.0f - 2.0f * (x * x + y * y); matrix[11] = 0.0f; // Fourth row matrix[12] = 0.0f; matrix[13] = 0.0f; matrix[14] = 0.0f; matrix[15] = 1.0f; // Now pMatrix[] is a 4x4 homogeneous matrix that can be applied to an OpenGL Matrix // return matrix; } /** Pour multiplier 2 quaternions */ public Quaternion operator(Quaternion q) { Quaternion resultat = new Quaternion(); resultat.w = w * q.w - x * q.x - y * q.y - z * q.z; resultat.x = w * q.x + x * q.w + y * q.z - z * q.y; resultat.y = w * q.y + y * q.w + z * q.x - x * q.z; resultat.z = w * q.z + z * q.w + x * q.y - y * q.x; return resultat; }et mon mouseListener
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 public class CameraQuaternions extends AbstractCamera { // Coefficient maximum pour la variation du pitch public float maxPitchRate; // Coefficient maximum pour la variation du heading public float maxHeadingRate; // Coefficient maximum pour la variation de vitesse public float maxForwardVelocity; // Angle de rotation du heading public float headingDegrees; // Angle de rotation du pitch public float pitchDegrees; // Valeur de la vitesse public float forwardVelocity; // Quaternions pour effectuer les rotations Quaternion qHeading; Quaternion qPitch; // Le vecteur de la direction de la camera. Vector directionVector; /** Constructeur de la classe Camera */ public CameraQuaternions() { qHeading = new Quaternion(); qPitch = new Quaternion(); position = new Position(-3, 7, 15); directionVector = new Vector(); maxPitchRate = 1.0f; maxHeadingRate = 1.0f; maxForwardVelocity = 1.0f; headingDegrees = 0.0f; pitchDegrees = 0.0f; forwardVelocity = 0.0f; } /** * Pour définir la perspective, c'est à dire la façon dont on voit le monde C'est ainsi que l'on "déplace" * la caméra */ @Override public void setPerspective(GL2 gl) { // Quaternions float[] matrice = new float[16]; Quaternion q = new Quaternion(); // Make the Quaternions that will represent our rotations qPitch.createFromAxisAngle(1.0f, 0.0f, 0.0f, pitchDegrees); qHeading.createFromAxisAngle(0.0f, 1.0f, 0.0f, headingDegrees); // Combine the pitch and heading rotations and store the results in q q = qPitch.operator(qHeading); // matrice = q.createMatrix(matrice); // Let OpenGL set our new prespective on the world! // XXX : Cette opération est beaucoup plus couteuse que des appels à // glRotatef et glTranslatef gl.glMultMatrixf(matrice, 0); // Create a matrix from the pitch Quaternion and get the j vector // for our direction. // matrice = qPitch.createMatrix(matrice); directionVector.setJ(matrice[9]); // Combine the heading and pitch rotations and make a matrix to get // the i and j vectors for our direction. q = qHeading.operator(qPitch); // matrice = q.createMatrix(matrice); directionVector.setI(matrice[8]); directionVector.setK(matrice[10]); // Scale the direction by our speed. directionVector = directionVector.multiplierScalaire(forwardVelocity); // XXX // Remise à zéro de la vitesse : // - Cette classe représente à l'origine une caméra à la Wing Commander, // c'est à dire que l'on dirige la vue à la souris, et une impulsion // au clavier active les gazs, on avance alors tout seul (comme un // avion) // - Pour une caméra a la quake, ne pas appuyer sur le clavier // correspond à ne pas avancer // // Remettre cette variable à zéro en permanence est un pure bricolage // pour obtenir un comportement quake-like d'une caméra Wing Commander // De toute façon, elle reste "non straffante" forwardVelocity = 0.0f; // Increment our position by the vector position.setX(position.getX() + directionVector.getI()); position.setY(position.getY() + directionVector.getJ()); position.setZ(position.getZ() + directionVector.getK()); // Translate to our new position. gl.glTranslatef(-position.getX(), -position.getY(), position.getZ()); } /** Pour changer la direction */ private void changePitch(float degrees) { // Notre pitch vaut moins que le maximum rate // donc on peut l'incrémenter if (Math.abs(degrees) < Math.abs(maxPitchRate)) { pitchDegrees += degrees; } // Sinon notre pitch vaut plus que le maximum rate // donc on peut seulement incrémenter le pitch // de ce maximum rate else { if (degrees < 0.0f) { pitchDegrees -= maxPitchRate; } else { pitchDegrees += maxPitchRate; } } // On ne veut pas que notre pitch "explose" if (pitchDegrees > 360.0f) { pitchDegrees -= 360.0f; } else { if (pitchDegrees < -360.0f) { pitchDegrees += 360.0f; } } } /** Pour changer le cap */ private void changeHeading(float degrees) { // Notre heading vaut moins que le maximum rate // donc on peut l'incrémenter // MAIS on doit vérifier si nous sommes renversés if (Math.abs(degrees) < Math.abs(maxHeadingRate)) { if ((pitchDegrees > 90.0f && pitchDegrees < 270.0f) || (pitchDegrees < -90.0f && pitchDegrees > -270.0f)) { headingDegrees -= degrees; } else { headingDegrees += degrees; } } // Notre heading est plus grand que le maximum rate // donc on peut seulement incrémenter le heading // de ce maximum rate else { if (degrees < 0.0f) { if ((pitchDegrees > 90.0f && pitchDegrees < 270.0f) || (pitchDegrees < -90.0f && pitchDegrees > -270.0f)) { // Normalement ici on décremente, mais vu que nous sommes // renversés, on incrémente headingDegrees += maxHeadingRate; } else { headingDegrees -= maxHeadingRate; } } else { if ((pitchDegrees > 90.0f && pitchDegrees < 270.0f) || (pitchDegrees < -90.0f && pitchDegrees > -270.0f)) { headingDegrees -= maxHeadingRate; } else { headingDegrees += maxHeadingRate; } } } // On ne veut pas que notre heading "explose" if (headingDegrees > 360.0f) { headingDegrees -= 360.0f; } else { if (headingDegrees < -360.0f) { headingDegrees += 360.0f; } } } /** Pour changer la vitesse */ private void changeVelocity(float vel) { // Notre vitesse vaut moins que le maximum rate // donc on peut l'incrémenter if (Math.abs(vel) < Math.abs(maxForwardVelocity)) { forwardVelocity += vel; } // Notre vitesse est plus grande que le maximum rate // donc on peut seulement l'incrémenter de ce maximum rate else { if (vel < 0.0f) { forwardVelocity -= -maxForwardVelocity; } else { forwardVelocity += maxForwardVelocity; } } } public void moveForwards() { changeVelocity(0.5f); } public void moveBackwards() { changeVelocity(-0.5f); } public void moveRight() { changeHeading(5.0f); } public void strafeLeft() { changeHeading(-5.0f); } public void moveUpwards() { } public void moveDownwards() { } @Override public void setLook(float delta, boolean isPitch) { if (isPitch) { changePitch(delta); return; } changeHeading(delta); } }J'ai vérifier ligne à ligne sans succés. SI qq'un est en mesure de m'aider
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 public class Mouse implements MouseMoveListener { private static Logger logger = Logger.getLogger(Mouse.class.getName()); Robot robot; public Mouse() { try { robot = new Robot(); } catch (Exception e) { logger.error("Echec à l'initialisation du robot"); } } public void mouseMove(MouseEvent e) { // deltaMouse mesure de combien le curseur de souris s'éloigne du centre // de l'écran float deltaMouse = 0.0f; // On récupère le component qui communique avec le listener car on a // besoin de connaître les dimensions de la fenêtre Rectangle canvas = e.display.getActiveShell().getBounds(); // On cherche le centre de la zone opengl : // Coordonnée extérieure gauche de la frame + épaisseur de la bordure = on est // au bord gauche de la zone opengl // + la largeur de la zone opengl / 2 = le milieu de la zone opengl int centerX = canvas.width / 2; int centerY = canvas.height / 2; // XXX // Explication du +1.0f : un nombre empirique // Selon le gestionnaire de fenêtre : // // Pour Windows XP / KDE3 / Fvwm2 : // - si l'origine de la fenêtre est en (1,1) il y a une différence de 1 // pixel entre le calcul du centre et celui des coordonnées de la souris // Donc on ajoute 1 // - si la fenêtre est n'importe où ailleurs on ne touche à rien // // Pour Fluxbox : // On constate sur Fluxbox (un window manager de Linux) un comportement // particulier. // - si l'origine de la fenêtre est en (1,1) il ne faut rien rajouter // - si la fenêtre est n'importe où ailleurs : il y a une différence de 1 pixel // entre le calcul du centre et celui des coordonnées de la souris // Donc on ajoute 1 // CODE WINDOWS_XP KDE3 FVWM2 int mouseX = (canvas.x + e.x); int mouseY = (canvas.y + e.y); logger.info(String.format("canvas pos [%s, %s]", canvas.x, canvas.y)); logger.info(String.format("mouse pos [%s, %s]", e.x, e.y)); logger.info(String.format("mouseX,Y pos [%s, %s]", mouseX, mouseY)); if (canvas.x == 1 && canvas.y == 1) { mouseX += 1.0f; mouseY += 1.0f; } // FIN CODE WINDOWS_XP KDE3 FVWM2 if (mouseX < centerX) { deltaMouse = (centerX - mouseX); logger.info(String.format("mouseX < centerX [%s, %s]", mouseX, centerX)); logger.info(String.format("deltaMouse X [%s]", deltaMouse)); CameraManager.getInstance().getCamera().setLook(-0.2f * deltaMouse, false); } else if (mouseX > centerX) { deltaMouse = (mouseX - centerX); logger.info(String.format("mouseX > centerX [%s, %s]", mouseX, centerX)); logger.info(String.format("deltaMouse X [%s]", deltaMouse)); CameraManager.getInstance().getCamera().setLook(0.2f * deltaMouse, false); } if (mouseY < centerY) { deltaMouse = (centerY - mouseY); logger.info(String.format("mouseY < centerY [%s, %s]", mouseY, centerY)); logger.info(String.format("deltaMouse Y [%s]", deltaMouse)); CameraManager.getInstance().getCamera().setLook(-0.2f * deltaMouse, true); } else if (mouseY > centerY) { deltaMouse = (mouseY - centerY); logger.info(String.format("mouseY > centerY [%s, %s]", mouseY, centerY)); logger.info(String.format("deltaMouse Y [%s]", deltaMouse)); CameraManager.getInstance().getCamera().setLook(0.2f * deltaMouse, true); } mouseX = centerX + canvas.x; mouseY = centerY + canvas.y; // Le curseur de souris doit rester au centre de l'écran robot.mouseMove(mouseX, mouseY); } }
Thx
Partager