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 Quaternion
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;
    }
ma 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
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);
    }
}
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
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);
    }
}
J'ai vérifier ligne à ligne sans succés. SI qq'un est en mesure de m'aider
Thx