Précédent   Forum du club des développeurs et IT Pro > Applications > Développement 2D, 3D et Jeux > Moteurs 3D
Moteurs 3D Forum d'entraide sur les moteurs 3D (conception d'un moteur, Ogre, Irrlicht...)
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse
 
Outils de la discussion
Publicité
'
Vieux 01/05/2012, 18h13   #1
wperrad
Invité régulier
 
Homme wladimir perrad
Inscription : octobre 2011
Messages : 15
Détails du profil
Informations personnelles :
Nom : Homme wladimir perrad
Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

Informations forums :
Inscription : octobre 2011
Messages : 15
Points : 8
Points : 8
Par défaut Problème de conversion de matrice en quaternion

Bonjour, je développe un moteur 3D depuis quelques temps et j'ai plusieurs fois été confronté à des problème de conversion matrice->quaternion (j'utilise les quaternions pour faire des interpolations sphériques linéaires). J'avais contourné le problème en passant tout en quaternion, ce qui m'évitait de devoir faire ce genre de conversion, mais il reste encore un endroit dans le moteur où je suis obligé de faire appel à cette conversion (dans l'exporteur 3dsmax plus exactement).

Donc j'ai une boite simple qui doit faire une rotation de 90 degrés et quand l'angle de rotation est légèrement inférieur à 90, ça ne pose pas de problème. Quand l'angle devient très proche de 90 degré ou légèrement supérieur, le quaternion calculé change de "signe"( il passe de (0.7, -0.7, 0, 0) à (-0.7, 0.7, 0, 0) ).

Voici le code de test que j'ai fais et qui reproduit l'erreur :

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 
	CQuaternion q, q2;
	CMatrix m( -2.3841858e-007f,	-1.0000000f,	5.8091246e-008f,	0.00000000f,
			-0.99999934f,	1.1920929e-007f,   -0.0011870498f,	-1.0773603e-007f,
	               0.0011870499f,	-5.8265869e-008f,	-0.99999940f,	2.4647131f,
		             0.f,		0.f,		   0.f,		1.f );
 
	m.GetQuaternion( q );
 
	CMatrix m2( -1.1920929e-007f,	      -0.99999994f,	                 5.9604645e-008f,	0.00000000f	, 
			-0.99930769f,		2.3841858e-007f,		0.037203975f,	    -1.0773603e-007f,
			-0.037203975f,		-5.4016709e-008f,		-0.99930763f,	    2.4647131f,	
			0.f,				0.f,		           0.f,	              1.f  );
 
	m2.GetQuaternion( q2 );
et voici la fonction de conversion de matrice en quaternion :

Code :
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
 
void CMatrix::GetQuaternion( CQuaternion& quat ) const
{
	float fTrace = m_00 + m_11 + m_22 + 1;
	if( fTrace > 3.9999 )
		quat.Fill( 0, 0, 0, 1 );
	else
	{
		if ( fTrace > 0.0001 )
		{
			float S = sqrt( fTrace ) * 2;
			quat.Fill( ( m_21 - m_12 ) / S, ( m_02 - m_20 ) / S, ( m_10 - m_01 ) / S, 0.25f * S );
		}
		else 
		{
			if( ( abs( m_00 ) > abs( m_11 ) ) && ( abs( m_00 ) > abs( m_22 ) ) )
			{
				if ( ( 1.0 + m_00 - m_11 - m_22 ) <= 0 )
					throw 1;
				float S = sqrt( 1.0 + m_00 - m_11 - m_22 ) * 2; // S=4*qx 
				quat.Fill( 0.25 * S, ( m_01 + m_10 ) / S, (m_02 + m_20 ) / S, ( m_21 - m_12 ) / S );
			} 
			else if ( abs( m_11 ) > abs( m_22 ) ) 
			{ 
				if ( ( 1.f + m_11 - m_00 - m_22 ) <= 0.f )
					throw 1;
				float S = sqrt( 1.f + m_11 - m_00 - m_22 ) * 2; // S=4*qy
				quat.Fill( ( m_01 + m_10 ) / S, 0.25f * S, ( m_12 + m_21 ) / S, ( m_02 - m_20 ) / S );
			}
			else
			{
				float S;
				if ( ( 1.f + m_22 - m_00 - m_11 ) <= 0.f )
				{
					throw 1;
				}
				else
				{
					S = sqrt( 1.f + m_22 - m_00 - m_11 ) * 2.f; // S=4*qz
					quat.Fill( ( m_02 + m_20 ) / S, ( m_12 + m_21 ) / S, 0.25f * S, ( m_10 - m_01 ) / S );
				}
			}
		}
	}
}
Voici les valeurs obtenues :
q = ( 0.70182616, -0.70182621, 0.00042286396, 0.00038762530 )
q2 = ( -0.70689392, 0.70689404, 0.013153042, 0.013157572 )

Ici, on voit que pour des valeurs de matrice très proches (elles représentent des positions extrêmement proches sous 3dsmax), les quaternions obtenus sont totalement différents, ce qui occasionne des problèmes lors de l'interpolation.

La position initiale et finale de mon objet sont bonnes, mais dans le 2eme cas, le changement de signe fait que l'objet tourne dans le sens contraire pour arriver à la position finale (en gros, au lieu d'aller de midi à 3h dans le sens des aiguilles d'une montre, il va de midi à 3h dans le sens contraire).

Donc je me dis qu'il y a 2 possibilités : soit la conversion de matrice en quaternion n'est pas correcte, soit c'est l'interpolation qui s’emmêle les pinceaux à cause du changement de signe (en interprétant ça comme une rotation dans l'autre sens...).

Pour info, voici le code pour l'interpolation de deux quaternions :

Code :
1
2
3
4
5
6
7
8
9
 
void CQuaternion::Slerp( const CQuaternion& q0, const CQuaternion& q1, float t, CQuaternion& qr )
{
	float fInitAngle = q0.GetAngle();
	float fFinalAngle = q1.GetAngle();
	float Omega = ( fFinalAngle - fInitAngle ) / 2.f;
	qr = ( q0 * sin( ( 1 - t ) * Omega ) + q1 * sin( t * Omega ) ) / sin( Omega );
	CVector::Lerp( q0.m_vPosition, q1.m_vPosition, t, qr.m_vPosition );
}
... ainsi que la conversion quaternion->matrice que j'utilise à la fin avant d'envoyer tout ça à opengl :

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 
void CQuaternion::GetMatrix( CMatrix& mat )
{
	mat.m_00 = 1 - 2 * m_y * m_y - 2 * m_z * m_z;
	mat.m_01 = 2 * m_x * m_y - 2 * m_z * m_w;
	mat.m_02 = 2 * m_x * m_z + 2 * m_y * m_w;
	mat.m_03 = m_vPosition.m_x;
 
	mat.m_10 = 2 * m_x * m_y + 2 * m_z * m_w;
	mat.m_11 = 1 - 2 * m_x * m_x - 2 * m_z * m_z;
	mat.m_12 = 2 * m_y * m_z - 2 * m_x * m_w;
	mat.m_13 = m_vPosition.m_y;
 
	mat.m_20 = 2 * m_x * m_z - 2 * m_y * m_w;
	mat.m_21 = 2 * m_y * m_z + 2 * m_x * m_w;
	mat.m_22 = 1 - 2 * m_x * m_x - 2 * m_y * m_y;
	mat.m_23 = m_vPosition.m_z;
 
	mat.m_30 = 0;
	mat.m_31 = 0;
	mat.m_32 = 0;
	mat.m_33 = 1;
}
Bref, ça fait depuis des jours que je suis sur ce problème et je bloque. Merci d'avance pour votre aide

EDIT : Si jamais c'est un problème de conversion matrice->quaternion, ça pourrait se résoudre d'une autre manière, en récupérant par exemple directement le quaternion d'un bone à partir de 3dsmax.
wperrad est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 02/05/2012, 13h55   #2
wperrad
Invité régulier
 
Homme wladimir perrad
Inscription : octobre 2011
Messages : 15
Détails du profil
Informations personnelles :
Nom : Homme wladimir perrad
Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

Informations forums :
Inscription : octobre 2011
Messages : 15
Points : 8
Points : 8
De plus en plus bizarre, je viens de vérifier, il existe effectivement une classe de quaternion sous 3dsmax et quand je l'utilise pour convertir la matrice renvoyée par max en quaternion, il me renvoie le même... De plus, j'ai fais d'autres tests suite à celui que j'ai posté plus haut et quand je re-converti mon quaternion "foireux" il me donne pourtant bien la bonne matrice.... J'en arrive à la conclusion que le problème ne vint pas de la conversion matrice->quaternion. et que les quaternions (0.7, -0.7, 0, 0) et (-0.7, 0.7, 0, 0) doivent probablement être équivalents.

Pourtant, le résultat de l'interpolation entre q0 (mon quaternion d'origine) et q1 (le quaternion foireux) ne fonctionne pas correctement. J'en déduis que le problème vient peut-être de mon interpolation qui doit être mauvaise pour certains cas particuliers, ce qui est bizarre étant donné que je me suis contenté de reprendre la formule donnée sur ce site.

Personne n'a d'idée pour me dépanner ?
wperrad est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 02/05/2012, 20h25   #3
plegat
Expert Confirmé Sénior
 
Jean-Michel BORLOT
Fabricant et casseur d'avions
Inscription : avril 2004
Messages : 3 215
Détails du profil
Informations personnelles :
Nom : Jean-Michel BORLOT
Localisation : France, Haute Garonne (Midi Pyrénées)

Informations professionnelles :
Activité : Fabricant et casseur d'avions
Secteur : Aéronautique - Marine - Espace - Armement

Informations forums :
Inscription : avril 2004
Messages : 3 215
Points : 5 378
Points : 5 378
Salut,

Citation:
Envoyé par wperrad Voir le message
J'en arrive à la conclusion que le problème ne vint pas de la conversion matrice->quaternion. et que les quaternions (0.7, -0.7, 0, 0) et (-0.7, 0.7, 0, 0) doivent probablement être équivalents.
Et oui... par contre c'est une rotation de 180° et pas de 90° comme tu écris dans ton premier post...


Citation:
Envoyé par wperrad Voir le message
Personne n'a d'idée pour me dépanner ?
Tu peux essayer d'inverser les composantes de ton quaternion cible, et faire l'interpolation. Ca devrait être plus mieux comme interpolation.

Le problème vient de la représentation physique du quaternion. Il y a deux manière de représenter une rotation autour d'un axe, soit par la rotation d'angle alpha autour de du vecteur (x,y,z), soit par la rotation d'angle -alpha et de vecteur (-x,-y,-z). Si tu veux que l'interpolation ne soit pas trop brutale, il faut que les vecteurs de départ et d'arrivée ne soit pas trop différents. Or avec tes deux quaternions, ils sont opposés, d'où le "grand tour" fait pendant l'interpolation. D'où l'idée d'inverser le second quaternion (ce qui au niveau matrice ne modifie rien), afin de le "rapprocher" du premier.

Au niveau du code, tu peux rajouter une condition qui calcule l'angle entre les vecteurs porteurs des deux quaternions, et si il est supérieur à 90° tu inverses le quaternion cible.
__________________
"Errare humanum est, sed perseverare diabolicum"

Ma page sur DVP.com
plegat est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 03/05/2012, 16h04   #4
wperrad
Invité régulier
 
Homme wladimir perrad
Inscription : octobre 2011
Messages : 15
Détails du profil
Informations personnelles :
Nom : Homme wladimir perrad
Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

Informations forums :
Inscription : octobre 2011
Messages : 15
Points : 8
Points : 8
Citation:
Envoyé par plegat Voir le message
Et oui... par contre c'est une rotation de 180° et pas de 90° comme tu écris dans ton premier post...
En fait je ne parlais pas du passage de q2=(0.7, -0.7, 0, 0) à q2'(-0.7, 0.7, 0, 0) mais de q à q2 ou q2' (q étant la position initiale, q2 et q2' étant les positions d'arrivée de 2 animations différentes, une bonne et l'autre foireuse). Mais bref, ce n'est pas important pour la suite.


Citation:
Envoyé par plegat Voir le message
Tu peux essayer d'inverser les composantes de ton quaternion cible, et faire l'interpolation. Ca devrait être plus mieux comme interpolation.

Le problème vient de la représentation physique du quaternion. Il y a deux manière de représenter une rotation autour d'un axe, soit par la rotation d'angle alpha autour de du vecteur (x,y,z), soit par la rotation d'angle -alpha et de vecteur (-x,-y,-z). Si tu veux que l'interpolation ne soit pas trop brutale, il faut que les vecteurs de départ et d'arrivée ne soit pas trop différents. Or avec tes deux quaternions, ils sont opposés, d'où le "grand tour" fait pendant l'interpolation. D'où l'idée d'inverser le second quaternion (ce qui au niveau matrice ne modifie rien), afin de le "rapprocher" du premier.

Au niveau du code, tu peux rajouter une condition qui calcule l'angle entre les vecteurs porteurs des deux quaternions, et si il est supérieur à 90° tu inverses le quaternion cible.
Ton idée est intéressante, je vais tester ça tout de suite. Merci !
wperrad est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 03/05/2012, 18h52   #5
plegat
Expert Confirmé Sénior
 
Jean-Michel BORLOT
Fabricant et casseur d'avions
Inscription : avril 2004
Messages : 3 215
Détails du profil
Informations personnelles :
Nom : Jean-Michel BORLOT
Localisation : France, Haute Garonne (Midi Pyrénées)

Informations professionnelles :
Activité : Fabricant et casseur d'avions
Secteur : Aéronautique - Marine - Espace - Armement

Informations forums :
Inscription : avril 2004
Messages : 3 215
Points : 5 378
Points : 5 378
Citation:
Envoyé par wperrad Voir le message
q2 et q2' étant les positions d'arrivée de 2 animations différentes, une bonne et l'autre foireuse
Euh... un quaternion ne donne pas une position... il représente une transformation. Et ici q2 et q2' représente la même transformation (à la petite différence près de quelques degrés), donc j'ai toujours un peu de mal à comprendre le côté "foireux"... D'ailleurs tu écris toi-même:

Citation:
Envoyé par wperrad Voir le message
La position initiale et finale de mon objet sont bonnes
Donc rien de "foireux", c'est juste l'interpolation qui doit être adaptée...
__________________
"Errare humanum est, sed perseverare diabolicum"

Ma page sur DVP.com
plegat est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 03/05/2012, 22h16   #6
wperrad
Invité régulier
 
Homme wladimir perrad
Inscription : octobre 2011
Messages : 15
Détails du profil
Informations personnelles :
Nom : Homme wladimir perrad
Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

Informations forums :
Inscription : octobre 2011
Messages : 15
Points : 8
Points : 8
Citation:
Envoyé par plegat Voir le message
Euh... un quaternion ne donne pas une position... il représente une transformation. Et ici q2 et q2' représente la même transformation (à la petite différence près de quelques degrés), donc j'ai toujours un peu de mal à comprendre le côté "foireux"...
Heu oui j'ai fais un lapsus, en fait j'ai 2 matrices m1 et m2 qui représentent chacune une orientation différente de mon bone dans l'espace (m1 étant l'orientation d'origine et m2 l'orientation d'arrivée) et je voudrais faire une interpolation entre ces deux orientations en fonction d'un paramètre t. Je converti donc chacune de mes 2 matrices en quaternion et je fais un slerp entre ces 2 quaternions. Une fois le quaternion intermédiaire obtenu, je le reconverti en matrice pour connaitre l'orientation intermédiaire de mon bone.


Citation:
Envoyé par plegat Voir le message
Donc rien de "foireux", c'est juste l'interpolation qui doit être adaptée...
Je viens de regarder la FAQ pour les jeux et je vois que la méthode employée pour obtenir la matrice interpolée MI entre deux matrices est apparemment différente de la mienne : calcul d'une matrice de rotation R à l'aide de la matrice de départ Ms et d'arrivée Mf (avec R=inverse(Ms) * Mf), conversion de R en quaternion qr pour récupérer son angle et son axe de rotation, interpolation de l'angle en fonction de t pour récupérer le quaternion interpolé qi et conversion de ce quaternion en matrice MI. Je vais tester ça de suite et je te tiens au courant. Merci encore !
wperrad est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 03/05/2012, 23h14   #7
wperrad
Invité régulier
 
Homme wladimir perrad
Inscription : octobre 2011
Messages : 15
Détails du profil
Informations personnelles :
Nom : Homme wladimir perrad
Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

Informations forums :
Inscription : octobre 2011
Messages : 15
Points : 8
Points : 8
Ca maaaaaaaaaaaaarche !

Bon là je n'ai testé que l'animation qui me posait problème, je vais faire d'autres tests plus poussés et je mettrais le sujet en résolu si c'est toujours bon.
Encore merci !
wperrad est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Cette discussion est résolue.
Outils de la discussion

Navigation rapide


Fuseau horaire GMT +2. Il est actuellement 22h38.


 
 
 
 
Partenaires

Hébergement Web