2010-09-28 5 views
13

Je sais que la rotation 3D est bien documentée sur SO et sur de nombreux autres sites, mais en dépit de la lecture d'innombrables explications, je n'ai toujours pas compris où je me trompe. Mes antécédents sont dans l'art et le design, pas dans les mathématiques et la programmation, et je ne suis jamais vraiment certain que mon angle d'attaque (sans jeu de mots) soit le bon. Plutôt que de coller un patchwork de mon code lugubre, j'inclus une image décrivant mon problème. Ce que j'aimerais vraiment, c'est une ventilation détaillée, étape par étape, de la façon de le résoudre. Pseudo code est utile, mais je vais apprendre plus si quelqu'un va me diriger dans la bonne direction ou de souligner les pièges communs.Rotation 3D avec Axis & Angle


alt text

= Red X-Axis, Vert = axe Y, Bleu = Z-Axis

vecteurs Magenta = origine -> certains X, Y, Z Point

Magenta cube = moyenne des extrémités des deux vecteurs magenta (y a-t-il un meilleur nom pour cela?)

Vecteur blanc = produit croisé des deux vecteurs magenta ay, vecteur est normalisée)

objet cube cyan = rotation échoue


Je l'ai déjà utilisé Away3D et Papervision; dans ces bibliothèques, l'application d'angles d'Euler aux propriétés rotationX, rotationY ou rotationZ d'un objet fera tourner l'objet localement, comme s'il était à l'origine quelle que soit sa position réelle. Avec Three.js, ce n'est pas le cas. La modification des propriétés rotation.x et rotation.y d'un objet produit un effet bizarre lorsque l'objet incline apparemment un bit sur l'axe Z. Encore plus déroutant est que cela se produit lorsque l'objet repose à l'origine. Je pensais que l'utilisation de fonctions Quaternion -> Matrix ou Axis/Angle -> Matrix résoudrait mon problème, mais pas de dés. Il semble qu'il y ait un concept de base que je ne reçois pas.

Quoi qu'il en soit, ce que je voudrais faire est d'orienter le cube vers le vecteur produit croisé (blanc), de sorte que le haut du cube soit orienté dans la direction de ce vecteur. Ensuite, j'aimerais faire tourner le cube sur le même axe. L'image que j'ai attachée montre le résultat de plus d'heures que je voudrais admettre essayant d'atteindre ce résultat. Mon code ressemble vaguement comme ceci:

axis = Vector3.cross(a, b) 
axis.normalize() 
angle = 45 * TO_RADIANS; 
quat = AxisAngle2Quaternion(axis, angle) 
rot = Quaternion2Matrix(quat) 
cube.matrix = rot 

Merci à l'avance,

Casey


Edit: Démarrage d'une prime

Peut-être que je comprends mal comment cela est censé travail. Voici une autre image:

alt text

Ai-je raison de penser que ce vecteur magenta est l'axe, et les flèches orange indiquent la rotation autour de cet axe en fonction de l'angle? D'une manière ou d'une autre, je veux orienter le cube cyan basé sur un vecteur directionnel et le faire tourner. Qu'est-ce que je fais mal!?

+0

Personne ne réagit, mais je pense en fait, que votre question est des meilleurs formulés que j'ai vus ici jusqu'à présent. Peut-être que personne ne le sait? Je serais également curieux de voir une réponse ici. – erikbwork

+0

Peut-être qu'ils sont loin de l'aspect Three.js ... Je m'attendais à ce que ce soit un problème assez basique – Casey

+0

J'ai pu me rapprocher avec la méthode "Utils3D.pointTowards()" dans Flash: http: // help. adobe.com/fr/US3LCR/Flash_10.0/flash/geom/Utils3D.html Mais je ne sais pas comment appliquer la rotation autour de l'axe et je ne trouve pas de fonctions OSS comparables – Casey

Répondre

4

Votre approche semble correcte mais vous ne montrez pas ce que sont les vecteurs a, b et l'angle constant est, je suppose, juste pour tester. Je l'ai fait avant, donc je déterré mon code et voici le calcul que j'ai trouvé ...

donné:
originalVec = vecteur unitaire pointant vers le haut axe Y (direction du haut du cube/normal)
targetVec = vecteur

Maintenant, vous voulez que l'axe et l'angle qui feront pivoter originalVec soient alignés avec targetVec. L'axe de rotation le plus direct est perpendiculaire aux deux vecteurs d'entrée, donc prenez leur produit croisé. Cet axe n'est pas un vecteur unitaire, donc normalisez-le. L'angle de rotation (en radians) est le cosinus inverse du produit scalaire.

axis = Vector3.cross(originalVec, targetVec) 
axis.normalise 
angle = inversecos(Vector3.dot(originalVec, targetVec)) 

quat = AxisAngle2Quaternion(axis, angle) 
rot = Quaternion2Matrix(quat) 
cube.matrix = rot 

Au lieu de remplacer la matrice du cube, je pense que vous voulez composer avec la nouvelle transformation ...

cube.matrix.multiplyBy(rot) 

... mais je ne suis pas 100% sûr. En outre, j'ai vu des implémentations où AxisAngle2Quaternion prend un angle en degrés. Lorsque les vecteurs d'entrée sont parallèles ou opposés, l'axe < 0,0,0> doit être testé. Si le cube tourne dans le mauvais sens, alors les paramètres du vecteur inter-produit sont dans le mauvais ordre, je ne me souviens plus lequel et je les essaie tous les deux. hth.

Modifier
J'ai eu la chance de jouer avec Three.js et piraté un des exemples pour orienter un cube. Les commentaires montrent où j'ai ajouté des choses et tout le calcul orienté se passe dans alignCube(). Mousser vers le haut/bas déplace la ligne cible.
Align and Spin example

Mousing gauche/droite tourne sur la ligne.

Les objets de scène dans Three.js semblent tous hériter de Object3D qui a une propriété autoUpdateMatrix définie par défaut. Cela doit être défini sur false sinon la fonction updateMatrix est appelée, ce qui recalcule la matrice à partir des propriétés de position, d'échelle et de rotation des objets. Vous pouvez également affecter une autre fonction updateMatrix.

Ce serait bien si trois.js avait une certaine documentation :)

+0

Merci - c'est bon d'entendre que je suis sur la bonne voie. Malheureusement, je ne l'ai pas fait fonctionner. Je remplace la matrice du cube parce que j'essaie de simplifier les choses pour l'instant et que cela fonctionne à l'origine. Est-ce que ça va, ou est-ce que cela ne fait que créer des problèmes? – Casey

+0

Cet exemple est génial! Je n'ai pas le temps d'y aller en ce moment, mais je pense que vous obtiendrez la prime :) Merci! – Casey

+0

Ça marche, doux. J'ai mal compris comment fonctionnent les matrices d'axes/d'angles. J'essayais de tout faire avec une seule matrice. Je poste la fonction d'alignement ci-dessous pour tous ceux qui sont intéressés. – Casey

0

Parce que personne n'a une très bonne solution, je peux au moins vous conseiller sur la façon de vous rapprocher.

Il y a 3 problèmes possibles et vous avez l'un d'eux:

  1. Le calcul est pas juste, ou vous ne comprenez pas. (Cela ne devrait pas poser de problème ici)
  2. Les arithmétiques à virgule flottante sont toujours un problème pour les ordinateurs (cela ne devrait pas non plus poser de problème, car c'est un problème de base.) Si votre framework ne peut pas fournir de solution, n'a pas de valeur du tout pour la programmation 3d)
  3. Vous n'utilisez pas le cadre approprié

Parce qu'il est assez probable que le numéro 3 est le cas, essayez de trouver une liste de diffusion ou un forum de soutien ou que ce soit pour le cadre et parler aux gens là-bas. Ils devraient être en mesure de vous expliquer, ce que vous faites mal avec leur cadre. Puis revenez et postez la solution ici!

+0

Merci pour la suggestion - J'ai contacté l'auteur du cadre et je vais voir si un code similaire donne un résultat similaire dans Away3D – Casey

+0

Je fais clairement quelque chose de mal - je ne peux pas le faire fonctionner dans Flash non plus . – Casey

+0

Regardez le lien d'exemple de Trochoid, ça marche bien! – Casey

3

De l'exemple de trochoïde, voici la fonction que j'utiliser pour obtenir l'alignement et la rotation de la seconde image:

//object, normalized direction vector, rotation in radians 
function align(target, dir, rot) { 
    //Three.js uses a Y up coordinate system, so the cube inits with this vector 
    var up = new THREE.Vector3(0, 1, 0); 

    //euler angle between direction vector and up vector 
    var angle = Math.acos(up.dot(dir)); 

    //cross product of the up vector and direction vector 
    var axis = new THREE.Vector3(); 
    axis.cross(up, dir); 
    axis.normalize(); 

    //rotation to aligns the target with the direction vector 
    var rotate = THREE.Matrix4.rotationAxisAngleMatrix(axis, angle); 

    //rotation around direction vector 
    var revolve = THREE.Matrix4.rotationAxisAngleMatrix(dir, rot); 

    //compose the rotations (order matters, can be done other ways) 
    revolve.multiplySelf(rotate); 

    //assign matrix (autoUpdateMatrix = false) 
    target.matrix = revolve; 
} 
+0

Je suis content que vous ayez finalement trouvé un moyen de le faire fonctionner! – erikbwork

Questions connexes