2016-08-02 3 views
1

Je développe un contrôleur dans WPF 3D (en utilisant C#) pour pouvoir facilement déplacer et faire tourner ProjectionCamera en utilisant Move() - et Pitch() -fonctions. Mon contrôleur deviendra un Behavior<ProjectionCamera> pouvant être connecté à un ProjectionCamera. Pour initialiser le contrôleur, je souhaite calculer la rotation actuelle de la caméra en regardant ses vecteurs Up et Forward actuels et les comparer à l'orientation de caméra par défaut (Up = [0 1 0], Forward = [0 0 -1]). En d'autres termes, je veux calculer une rotation qui va transformer l'orientation par défaut de l'appareil photo en son orientation actuelle.AxisAngleRotation3D à Quaternion donne un résultat inattendu

En fin de compte, je souhaite exprimer la rotation comme une seule Quaternion, mais comme une étape intermédiaire I première calculer les appropriées rotations Euler angle de la forme ZNZ exprimée en AxisAngleRotation3D -values, suivant la définition par défaut de Wikipedia :

var alphaRotation = CalculateRotation(z, x, N); 
var betaRotation = CalculateRotation(N, z, Z); 
var gammaRotation = CalculateRotation(Z, N, X); 

avec

CalculateRotation(Vector3D axisOfRotation, Vector3D from, Vector3D to) : AxisAngleRotation3D 

Euler angle rotations semblent être calculées correctement, sur la base de certains tests unitaires. Cependant, quand je convertis ces rotations en un seul Quaternion, le Quaternion résultant représente une rotation que diffère des rotations d'angle d'Euler, et je ne sais pas pourquoi.

Voici comment je convertir les angles d'Euler à un seul Quaternion:

var rotation = 
    new Quaternion(alphaRotation.Axis, alphaRotation.Angle) * 
    new Quaternion(betaRotation.Axis, betaRotation.Angle) * 
    new Quaternion(gammaRotation.Axis, gammaRotation.Angle); 

Par exemple, quand j'initialiser un ProjectionCamera avec un UpDirection de [1 0 0], ce qui signifie qu'il a été tourné de 90 degrés autour de son axe LookDirection ([0 0 -1]), la valeur calculée Euler Angle rotations sont comme suit:

alphaRotation --> 90 deg. around [0 1 0] 
betaRotation --> 90 deg. around [0 0 -1] 
gammaRotation --> -90 deg. around [1 0 0] 

Mon test vérifie que, lorsqu'il est appliqué dans l'ordre, ces rotations transformeront la valeur par défaut Up -vector ([0 1 0]) dans l'actuel Up -vector ([1 0 0]), en le tournant efficacement 90 deg. autour de l'axe [0 0 -1]. (Il est également facile raisonnable de vérifier cela à la main.)

Cependant, lorsque je demande la valeur calculée QuaternionRotation à la valeur par défaut Up -vector, il se transforme au vecteur [-1 0 0], ce qui est évidemment faux. J'ai codé en dur ces résultats dans un test unitaire et a obtenu les mêmes résultats:

[TestMethod] 
    public void ConversionTest() 
    { 
     var vector = new Vector3D(0, 1, 0); 

     var alphaRotation = new AxisAngleRotation3D(new Vector3D(0, 1, 0), 90); 
     var betaRotation = new AxisAngleRotation3D(new Vector3D(0, 0, -1), 90); 
     var gammaRotation = new AxisAngleRotation3D(new Vector3D(1, 0, 0), -90); 

     var a = new Quaternion(alphaRotation.Axis, alphaRotation.Angle); 
     var b = new Quaternion(betaRotation.Axis, betaRotation.Angle); 
     var c = new Quaternion(gammaRotation.Axis, gammaRotation.Angle); 
     var combinedRotation = a * b * c; 

     var x = Apply(vector, alphaRotation, betaRotation, gammaRotation); 
     var y = Apply(vector, combinedRotation); 
    } 

Lorsque vous exécutez le test ci-dessus, vous verrez que x vous donne le vecteur attendu ([1 0 0]) mais y sera différent, où il devrait être exactement la même rotation.

Qu'est-ce qui me manque?

+0

[Ordre des rotations importe] (https://www.princeton.edu/~naomi/ lecture3.pdf). – Sinatr

+0

@Sinatr: Oui, je connais l'ordre des rotations. Avez-vous détecté une erreur dans mon code? Parce que pour autant que je sache, les Angles d'Euler doivent s'appliquer dans l'ordre (alpha, bêta, gamma), et pour représenter cette séquence de rotations comme un seul Quaternion, vous devez multiplier les rotations dans cet ordre (alpha * beta * gamma). –

Répondre

0

J'ai résolu le problème. Apparemment, l'ordre de la multiplication de l'individu Quaternions devrait être inversé. Ainsi, pour convertir des angles d'Euler (ou n'importe quel ensemble de rotations) en un seul Quaterniondans.NET vous devez faire ce qui suit:

var rotation = gammaRotation * betaRotation * alphaRotation; 

rotation représente l'application géométriquement alphaRotation d'abord, puis betaRotation et enfin gammaRotation. Je souhaite juste qu'ils l'aient documenté, puisque le sens de la commande dépend de la bibliothèque spécifique avec laquelle vous travaillez.