[jogl] systeme anti gimbal lock appliqué à un cube

Soyez le premier à donner votre avis sur cette source.

Vue 4 702 fois - Téléchargée 378 fois

Description

Montre comment on peut tourner un cube librement, sans souffrir du problème de Gimbal Lock (verrou de cardan). En effet, quand on souhaite tourner un cube en conservant separement les valeurs des 3 axes de rotation X, Y et Z ... on se heurte souvent au problème du verrou de cardan si l'on ne fait pas attention. Cette source utilise la solution des quaternions pour résoudre le problème.

On peut deplacer le cube avec la souris ou le clavier, "à l'envie".

gauche ou droite => selon l'axe y

haut ou bas => selon l'axe x

page up ou page down => selon l'axe z

L'extrait de code suivant n'est qu'un aperçu global : le zip contient toutes les classes necessaires.

Source / Exemple :


package com.gmail.bernabe.laurent.jogl.cube_anti_gimbal_lock;

import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;

import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.glu.GLU;

/**

  • @author laurent BERNABE
  • /
public class TheEventListener implements GLEventListener { @Override public void display(GLAutoDrawable drawable) { GL2 gl = drawable.getGL().getGL2(); gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); gl.glLoadIdentity(); glu.gluLookAt( 0, 0, 3, 0, 0, 0, 0, 1, 0); // SECTION -- La ou tout se joue // NOTER que cela fonctionne bien parce que le cube est a l'origine, il faudrait sinon // tenir compte, sans trop de travail supplementaire, de la translation courante du cube // 1) On construit le quaternion a partir des angles d'Euler et on le convertit en matrice // 2) On multiplie le resultat A GAUCHE du quaternion ou l'on a stocke les rotations du cube // 3) On change la matrice model-vue par le resultat Quaternion deltaQuaternion = Quaternion.buildFromEulerAngles(xAngleDegrees, yAngleDegrees, zAngleDegrees); cubeQuaternion = deltaQuaternion.mulInLeftOf(cubeQuaternion); xAngleDegrees = yAngleDegrees = zAngleDegrees = 0.0f; gl.glMultMatrixf(cubeQuaternion.toMatrix(), 0); // FIN DE SECTION Cube.draw(gl); } @Override public void init(GLAutoDrawable drawable) { GL2 gl = (GL2) drawable.getGL(); gl.glEnable(GL2.GL_DEPTH_TEST); gl.glClearDepth(1.0); gl.glDepthFunc(GL2.GL_LESS); } @Override public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { // Eviter la division par 0 if (height == 0) height = 1; double screenRatio = (double) width / height; GL2 gl = drawable.getGL().getGL2(); gl.glViewport(x, y, width, height); gl.glMatrixMode(GL2.GL_PROJECTION); gl.glLoadIdentity(); glu.gluPerspective(60, screenRatio, 1.1, 3.5); gl.glMatrixMode(GL2.GL_MODELVIEW); gl.glLoadIdentity(); } public void processKeyPressed(KeyEvent e){ final int UNIT_ANGLE = 5; switch(e.getKeyCode()){ case KeyEvent.VK_LEFT: yAngleDegrees += -UNIT_ANGLE; break; case KeyEvent.VK_RIGHT: yAngleDegrees += UNIT_ANGLE; break; case KeyEvent.VK_UP: xAngleDegrees += -UNIT_ANGLE; break; case KeyEvent.VK_DOWN: xAngleDegrees += UNIT_ANGLE; break; case KeyEvent.VK_PAGE_UP: zAngleDegrees += UNIT_ANGLE; break; case KeyEvent.VK_PAGE_DOWN: zAngleDegrees += -UNIT_ANGLE; break; } } public void processMousePressed(MouseEvent e) { mouseLastX = e.getX(); mouseLastY = e.getY(); } public void processMouseDragged(MouseEvent e) { int currentX = e.getX(); int currentY = e.getY(); int deltaX = currentX - mouseLastX; int deltaY = currentY - mouseLastY; mouseLastX = currentX; mouseLastY = currentY; xAngleDegrees = deltaY * MOUSE_SENSIBILITY; yAngleDegrees = deltaX * MOUSE_SENSIBILITY; } public void processMouseReleased(MouseEvent e) { } @Override public void dispose(GLAutoDrawable drawable) { // Rien a coder ici } /**
  • Derniere position x mise a jour par un dragging.
  • /
private int mouseLastX; /**
  • Derniere position y mise a jour par un dragging.
  • /
private int mouseLastY; /**
  • Angle x fixes par les derniers evenements non traites
  • /
private float xAngleDegrees; /**
  • Angle y fixes par les derniers evenements non traites
  • /
private float yAngleDegrees; /**
  • Angle z fixes par les derniers evenements non traites
  • /
private float zAngleDegrees; /**
  • Sensibilite de la souris
  • /
private final static float MOUSE_SENSIBILITY = 0.5f; private GLU glu = new GLU(); /**
  • Quaternion conservant les angles du cube
  • /
private Quaternion cubeQuaternion = Quaternion.buildIdentityQuaternion(); }

Conclusion :


Systeme utilise : Xubuntu 11.04
EDI : Eclipse 3.6

La solution respecte le système non eulérien proposé par gouessej.

Codes Sources

A voir également

Ajouter un commentaire

Commentaires

cs_loloof64
Messages postés
350
Date d'inscription
vendredi 1 septembre 2006
Statut
Membre
Dernière intervention
6 novembre 2012
-
Je confirme que le problème venait bien de là. Je te remercie beaucoup :).
Je vais uploader la source CubeAntiGimbalLock avec la nouvelle version du Quaternion :)
cs_loloof64
Messages postés
350
Date d'inscription
vendredi 1 septembre 2006
Statut
Membre
Dernière intervention
6 novembre 2012
-
Effectivement, je voulais que la fonction Quaternion.buildFromEulerAngles() se base sur des angles en degrés, je vais voir si c'est parce que j'ai oublié de reconvertir les angles en degrés.
Utilisateur anonyme -
A un endroit, tu as dû utiliser des radians à la place des degrés ou l'inverse d'où le ralentissement.
cs_loloof64
Messages postés
350
Date d'inscription
vendredi 1 septembre 2006
Statut
Membre
Dernière intervention
6 novembre 2012
-
Oui tu as raison, il arrive que sur certaines rotations j'éprouve encore des difficultés.
J'avais implémenté la formule que tu m'as passée, mais il semblerait que je l'ai mal codée : du coup les rotations se trouvent plus que ralenties.
Le code Quaternion que j'avais publié dans le forum "Exporter un programme JOGL en Jar executable" était en fait correct : c'est juste que la rotation est ultra-ralentie.
Utilisateur anonyme -
Cela ne permet pas de se débarrasser du verrou de Cardan comme tu n'utilises pas les 2 seules méthodes connues à cet effet (les singularités et les transformations non eulériennes).

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.