Transformations d'objets 3D:
Les objets Transform3D représentent les transformations de la géométrie 3D. Ces objets sont typiquement utilisés dans la création d'objets TransformGroup. Un objet Transform3D peut représenter une translation, une rotation, un changement d'échelle, ou une combinaison de ces transformations. Les angles sont exprimés en radians.

Méthodes d'initialisation d'une transformation simple:
Ces méthodes règlent la transformation qui leur est associée dans la matrice du Transform3D (rotation selon X, selon Y, selon Z, translation, redimensionnement), et réinitialisent les autres composantes de la matrice selon l'identité matricielle.

/** règle la valeur de cette transformation autour de l'axe x en radians dans le sens des aiguilles d'une montre, et réinitialise les autres composantes à l'identité
*/
void rotX(double angle)

/** idem pour l'axe y
*/
void rotY(double angle)

/** idem pour l'axe z
*/
void rotZ(double angle)

/** règle la valeur de translation de la matrice, et réinitialise les autres composantes à l'identité
*/
void set(Vector3f translate)

/** règle le coefficient de zoom et réinitialise les autres composantes à l'identité
*/
void setScale()

Composition de transformations:
Il est possible de combiner plusieurs transformations, par la méthode mul(Transform3d).
Par exemple, on peut reprendre les 2 rotations du cube du 1er chapitre et les combiner pour n'en faire qu'une. Il suffit pour celà de modifier la méthode createSceneGraphe() comme suit:

Exemple 2.1

public BranchGroup createSceneGraph() {
// créer le point d'articulation du branchement
BranchGroup objRoot = new BranchGroup();

// l'objet en rotation a 2 matrices de transformation assemblées
Transform3D rotate = new Transform3D();
Transform3D tempRotate = new Transform3D();

rotate.rotX(Math.PI/4.0d);
tempRotate.rotY(Math.PI/5.0d);
rotate.mul(tempRotate);
TransformGroup objRotate = new TransformGroup(rotate);

objRotate.addChild(new ColorCube(0.4));
objRoot.addChild(objRotate);
return objRoot;
}


Déplacement dans le monde:
Jusqu'à présent nous déplacions le cube afin de le voir sous un meilleur angle. On aurait pu aussi déplacer l'oeil de l'utilisateur (ViewPlatform qui dans le monde est un objet comme un autre) en agissant sur le TransformGroup qui lui est associé par défaut dans SimpleUniverse.


 
Transformons:
Nous allons maintenant voir comment à l'aide des TransformGroup, on peut positionner 2 objets l'un par rapport à l'autre. Dans cet exemple, nous allons détailler les 3 utilisations principales de la classe Transform3D: translations, rotations, et retaillage.

Exemple 2.2


import java.awt.Frame;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.BorderLayout;
//Java 3d API
import com.sun.j3d.utils.universe.SimpleUniverse;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.TransformGroup;
import javax.media.j3d.Transform3D;
import javax.vecmath.Vector3f;
import com.sun.j3d.utils.geometry.ColorCube;

// attention vous ne pouvez pas utiliser un même objet (shape3d), comme notre cube, dans plusieurs Group de transformation
// il faut créer 2 entités distinctes comme nous l'avons fait

public class cube3d2 extends Applet 

   public cube3d2()
   { 

     super("- 2 TG pour placer 2 cubes -");
     this.addWindowListener(this);
     setLayout(new BorderLayout());
     // 1ere étape création du Canvas3d qui va afficher votre univers virtuel avec une config préetablie
     Canvas3D canvas3D = new Canvas3D(SimpleUniverse.getPreferredConfiguration());
     add("Center", canvas3D);
     // 2eme étape on crée notre scene (regroupement d'objets) 
     BranchGroup scene = createSceneGraph();
     // on les compile pour optimiser les calculs
     scene.compile();

     // 3eme étape on crée l'univers qui va contenir notre scène 3d 
     // utilise simpleUniverse qui simplifie le code (il crée un environnement minimal simple)
     SimpleUniverse simpleU = new SimpleUniverse(canvas3D); 
     // on met le plan de projection en arriere par rapport àl'origine 
     simpleU.getViewingPlatform().setNominalViewingTransform(); 
     // on place la scène dans l'univers simpleU simpleU.addBranchGraph(scene); 

   } 

   //crée un regroupement d'objets contenant un objet cube 
   public BranchGroup createSceneGraph() 
   { 

     //on crée le Bg principal
     BranchGroup objRoot=new BranchGroup(); 

     //------------ début de creation du premier cube ------------

        // on crée un vecteur de translation 30 cm suivant les Y
        Transform3D translate1 = new Transform3D(); 
        translate1.set(new Vector3f(0.4f, 0.4f, 0.0f)); 

        // on crée une matrice de tranformation pour faire tourner notre cube
        Transform3D rotate = new Transform3D(); 
        //(X represente la vericale orientée vers le bas,Y represente l' horizontale orientée vers la gauche,Z)
        rotate.rotX(Math.PI/3.0d);//rotation d'angle Pi/3 

        // on combine les deux transformations: translation puis rotation 
        translate1.mul(rotate);
        // on crée un groupe de transformation rotate suivant la matrice de transformation translate1
        TransformGroup TG1 = new TransformGroup(translate1);

        // on crée un cube qui herite de cette rotation
        TG1.addChild(new ColorCube(0.3));// de rayon 30 cm 
        objRoot.addChild(TG1);

     //------------ fin de creation du premier cube ------------
     //------------ début de creation du deuxieme cube ------------

        // on crée un vecteur de translation de 30 cm suivant les Y (dans l'autre sens) 
        Transform3D translate2 = new Transform3D();
        translate2.set(new Vector3f(-0.4f, -0.4f, 0.0f)); 

        // on crée une matrice de tranformation pour faire tourner notre cube 
        Transform3D rotate2 = new Transform3D();
        rotate2.rotZ(Math.PI/3.0d);//rotation d'angle Pi/3

        // on combine les deux transformations: translation puis rotation
        translate2.mul(rotate2);

        // on réduit la taille du cube par 2 (on la multiplie par 0.5)
        translate2.setScale(0.5f);

        // on crée un groupe de transformation rotate suivant la matrice de transformation translate1
        TransformGroup TG2 = new TransformGroup(translate2);

        // on crée un cube qui herite de cette rotation 
        TG2.addChild(new ColorCube(0.3));// de rayon 20 cm

        objRoot.addChild(TG2);

     //------------ fin de creation du deuxieme cube ------------

     return objRoot;

   }

   public void windowActivated(WindowEvent e){}
   public void windowClosed(WindowEvent e){}
   public void windowDeactivated(WindowEvent e){}
   public void windowDeiconified(WindowEvent e){}
   public void windowIconified(WindowEvent e){}
   public void windowOpened(WindowEvent e){}

   public void windowClosing(WindowEvent e) {  System.exit(1); } 

   public static void main(String[] args)
   { 

     cube3d2 myApp=new cube3d2();
     myApp.setSize(300,300);
     myApp.setVisible(true);

   } 

}

</COMMENT> <blockquote><img SRC="cube3d2.GIF" height=299 width=300 align=RIGHT></blockquote>


 
Exemple avancé:
Afin de terminer l'étude des bases de Java 3D, je vais maintenant vous montrer un exemple un peu plus complexe reprenant toutes les notions abordées précédemment. Il s'agit de représenter sous un angle de 45°, 12 cubes en cercle autour de l'axe z.

Exemple 2.3


import javax.media.j3d.*;
import javax.vecmath.Vector3f;
import com.sun.j3d.utils.geometry.ColorCube;
import com.sun.j3d.utils.applet.MainFrame;

public class MultiCubes extends Applet3D 
{
  // Méthode de la classe Applet3D outrepassée
  public BranchGroup createSceneTree ()
  {
    // Racine de l'arbre des objets représentés dans la scène 3D
    BranchGroup root = new BranchGroup ();

    // Création d'une rotation de -PI / 4 autour de l'axe x
    Transform3D rotationXAxis = new Transform3D ();
    rotationXAxis.rotX (-Math.PI / 4);
    TransformGroup rotationXAxisGroup = new TransformGroup (rotationXAxis);

    // Création d'un cercle construit avec 12 cubes
    Group cubeCircle = createCubeCircle (12);

    // Construction de l'arbre de la scène
    rotationXAxisGroup.addChild (cubeCircle); 
    root.addChild (rotationXAxisGroup);
    return root;
  }

  // Crée un cercle avec cubeCount cubes
  public Group createCubeCircle (int cubeCount)
  {
    Group cubeCircle = new Group ();

    // Boucle de création de douze cubes 
    for (int i = 0; i < cubeCount; i++)
    {
      // Création d'une translation de (0.7,0,0)
      Transform3D translation = new Transform3D ();
      translation.setTranslation (new Vector3f (0.7f, 0, 0));
      TransformGroup translationGroup = new TransformGroup (translation);

      // Création d'une rotation variable autour de l'axe z
      Transform3D rotationZAxis = new Transform3D ();
      rotationZAxis.rotZ (2 * Math.PI * i / cubeCount);
      TransformGroup rotationZAxisGroup = new TransformGroup (rotationZAxis);

      // Création d'un cube coloré
      ColorCube cube = new ColorCube (0.1);

      // Déplacement du cube de 0.7 unité sur l'axe x
      translationGroup.addChild (cube);
      // Rotation variable pour répartir l'ensemble des cubes
      // autour du centre du repère
      rotationZAxisGroup.addChild (translationGroup); 
      // Ajout d'une  branche à la racine de l'arbre 
      cubeCircle.addChild (rotationZAxisGroup);
    }

    return cubeCircle;
  }

  // Méthode main () pour permettre d'utiliser cette classe 
  // comme applet ou comme application
  public static void main (String [] args) 
  {
    new MainFrame (new MultiCubes (), arg, 150, 150);
  } 
}

</COMMENT> <blockquote><img SRC="cube/MultiCubes.gif" height=176 width=157 align=RIGHT></blockquote>

La figure précédente représente l'arbre de la scène crée par la méthode createSceneTree() de la classe MultiCubes (les 12 branches représentant 12 cubes ne sont pas toutes dessinées). Cet arbre est construit comme suit:

  • Les 12 cubes subissent tous le même type de transformation: une translation de 0.7 unité le long de l'axe x puis une rotation de i*PI/6 radian autour de l'axe z, i étant compris entre 0 et 11. Chaque feuille  qui correspond à un cube est onc liée à 2 groupes de transformation  : ce sous-ensemble forme une branche rattachée au groupe , racine de l'arbre qui rassemble les 12 cubes.
  • Le cercle de 12 cubes subit une rotation de -PI/4 radians autour de l'axe x. Pour appliquer cette transformation à chacun des cubes, l'opération la plus simple est de rattacher le groupe  représentant le cercle à un seul groupe de transformation  effectuant cette rotation.

  • La racine  de la scène 3D doit être une instance de la classe BranchGroup et ce groupe est donc relié au dernier groupe de transformation .