Faisant suite à ce sujet que plus grand monde ne doit regarder vu qu'il a été résolu, je me permet de recréer un topic.
J'applique la méthode qui a permie de resoudre le probleme de jmb462, à savoir utiliser les quaternions, mais rien à faire, celà ne veux pas fonctionner chez moi.
Je me suis basé sur le code du tuto de NeHe et de la FAQ puis du code de jmb462 pour faire le mien, pas grand chose ne change, et pourtant ....
Berf le voici :
Code de ma classe Quaternion, il ne devrait pas poser de souci, étant purement et simplement implenté à partir de la FAQ ou de NeHe. Aucunes difficultées particulières a priori : 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 #include "Quaternion.h" Quaternion::Quaternion(){ x = y = z = 0; w = 1; }; void Quaternion::createFromAxisAngle(float _x, float _y, float _z, float angle) { // Convert degrees to radians angle = float((angle / 180.0) * M_PI); // Here we calculate the sin( theta / 2) once for optimization float result = (float)sin( angle / 2.0 ); // Calcualte the w value by cos( theta / 2 ) w = (float)cos( angle / 2.0 ); // Calculate the x, y and z of the quaternion x = float(_x * result); y = float(_y * result); z = float(_z * result); normalise(); }; void Quaternion::createFromMatrix(float* m){ float t = m[0] + m[5] + m[10]; float s; if(t>0){ s = 1/(2*sqrt(t)); x = (m[9]-m[6])*s; y = (m[2]-m[8])*s; z = (m[4]-m[1])*s; w = 1/(4*s); }else if(m[0]>m[5] && m[0]>m[10]){ s = sqrt(1+m[0]-m[5]-m[10])*2; x = 1/(2*s); y = (m[1]-m[4])/s; z = (m[2]-m[8])/s; w = (m[6]-m[9])/s; }else if(m[5]>m[0] && m[5]>m[10]){ s = sqrt(1-m[0]+m[5]-m[10])*2; x = (m[1]-m[4])/s; y = 1/(2*s); z = (m[6]-m[9])/s; w = (m[2]-m[8])/s; }else { s = sqrt(1-m[0]-m[5]+m[10])*2; x = (m[2]-m[8])/s; y = (m[6]-m[9])/s; z = 1/(2*s); w = (m[1]-m[4])/s; } normalise(); }; void Quaternion::createFromEuler(float ax, float ay, float az){ double eulerX, eulerY, eulerZ; eulerX = ax/180*M_PI/ 2.0; eulerY = ay/180*M_PI/ 2.0; eulerZ = az/180*M_PI/ 2.0; //on calcule les 4 valeurs du quaternion : w = float(cos(eulerX) * cos(eulerY)*cos(eulerZ) + sin(eulerX) * sin(eulerY)*sin(eulerZ)); x = float(sin(eulerX) * cos(eulerY)*cos(eulerZ) - cos(eulerX) * sin(eulerY)*sin(eulerZ)); y = float(cos(eulerX) * sin(eulerY) * cos(eulerZ) + sin(eulerX) * cos(eulerY) * sin(eulerZ)); z = float(cos(eulerX) * cos(eulerY) * sin(eulerZ) - sin(eulerX) * sin(eulerY) * cos(eulerZ)); normalise(); // ici tu appelles la fonction membre qui normalise ton quaternion (Normalize() ?) return; }; Quaternion Quaternion::operator *(Quaternion q){ Quaternion r; r.w = w*q.w - x*q.x - y*q.y - z*q.z; r.x = w*q.x + x*q.w + y*q.z - z*q.y; r.y = w*q.y + y*q.w + z*q.x - x*q.z; r.z = w*q.z + z*q.w + x*q.y - y*q.x; r.normalise(); return r; }; Quaternion Quaternion::conjugate(Quaternion q){ Quaternion r; r.x = -q.x; r.y = -q.y; r.z = -q.z; r.w = q.w; return r; }; float Quaternion:: magnitude(){ return sqrt(w * w + x * x + y * y + z * z); }; void Quaternion::normalise(){ float m = magnitude(); if(m>0){ x /= m; y /= m; z /= m; w /= m; } }; void Quaternion::createMatrix(float* matrix){ // Make sure the matrix has allocated memory to store the rotation data if(!matrix) return; // First row matrix[0] = 1.0 - 2.0 * ( y * y + z * z ); matrix[1] = 2.0 * (x * y + z * w); matrix[2] = 2.0 * (x * z - y * w); matrix[3] = 0.0; // Second row matrix[4] = 2.0 * ( x * y - z * w ); matrix[5] = 1.0 - 2.0 * ( x * x + z * z ); matrix[6] = 2.0 * (z * y + x * w ); matrix[7] = 0.0; // Third row matrix[8] = 2.0 * ( x * z + y * w ); matrix[9] = 2.0 * ( y * z - x * w ); matrix[10] = 1.0 - 2.0 * ( x * x + y * y ); matrix[11] = 0.0; // Fourth row matrix[12] = 0.0; matrix[13] = 0.0; matrix[14] = 0.0; matrix[15] = 1.0; // Now matrix[] is a 4x4 homogeneous matrix that can be applied to an OpenGL Matrix }; void Quaternion::createAxisAngle(float &_x, float &_y, float &_z, float &angle){ float scale = sqrt(x*x + y*y + z*z); ; if(scale == 0) scale = 1; normalise(); angle = acos(w) * 2 * 180 / M_PI; _x = x/scale; _y = y/scale; _z = z/scale; };
J'ai essaye les différentes fonctions pour créer les quaternions et pour les retransfomer en matrices ou angle/axe, cela donne à chaque fois le même résultats
Code perso, la ou doit se trouver l'erreur ... Il est appelé à chaque fois que la scène doit être redessinée : 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 void MaClasse::draw(){ float matrix[16]; Quaternion q0, qrotx, qroty; // Initialisation if (!valid()) { glMatrixMode( GL_PROJECTION ); glLoadIdentity(); glViewport(0,0,w(),h()); gluPerspective(70,(double)w()/h(),1,1000); glEnable(GL_DEPTH_TEST); glEnable(GL_BLEND); // Activate transparency glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Activate transparency glMatrixMode( GL_MODELVIEW ); } glClearColor(1,1,1,1); glClearDepth(1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); gluLookAt(0,0,10,0,0,0,0,1,0); // Place the camera if(size < 0) size = 0; glScalef((float)(size),(float)(size),(float)(size)); // Change size (zoom) glTranslatef(hshift, vshift, 0); // Translate (user's movements) //Make the Quaternions that will represent our rotations qrotx.createFromEuler(vAng,0,0); qroty.createFromEuler(0,hAng,0); q0 = qroty * qrotx; // Combine the both rotation and store the result in q0 q0.createMatrix(matrix); glMultMatrixf(matrix); // dessiner le repere glBegin(GL_LINES); glColor3f(1,0,0); glVertex3f(0,0,0); glVertex3f(1,0,0); glColor3f(0,1,0); glVertex3f(0,0,0); glVertex3f(0,1,0); glColor3f(0,0,1); glVertex3f(0,0,0); glVertex3f(0,0,1); glEnd(); };
J'utilise fltk, d'où la syntaxe d'initialisation.
Le probleme est donc ici que la rotation suivant y (donc la deuxième) se fait autour de l'axe x local, celui-là meme qui a tourné correctement autour de l'axe y global avec la première rotation. Bien entendu si j'inverse l'ordre des rotations, c'est le contraire qui se passe.
Je ne comprend vraiment pas pourquoi j'obtient cela, et n'arrive absolument pas à trouver le problème.
Partager