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

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

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.