Java3D - Les objets 3D

Alain Mari

Dans cette partie, nous allons voir en particulier quels sont les outils dont nous disposons plus créer des objets 3D plus ou moins complexes. ♪

- Titre : Java3D - Les objets 3D

- Auteur : Alain Mari

- Parution : 4 octobre 2005

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2005 Alain Mari. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- Introduction

- I. Arrière-plans

- I-A. Création d'arrière-plans avec une couleur unie

- I-B. Création d'arrière-plans avec une image de fond

- I-B-1. Lecture et chargement d'une image en mémoire

- I-B-2. Création d'un objet de type ImageComponent2D

- I-B-3. On initialise l'arrière-plan avec l'image de fond :

- II. Formes de base

- II-A. La classe Box

- II-A-1. Champs

- II-A-2. Principaux constructeurs

- II-A-3. Principales méthodes

- II-A-4. Exemple

- II-B. La classe Sphere

- II-B-1. Champs

- II-B-2. Principaux constructeurs

- II-B-3. Principales méthodes

- II-B-4. Exemple

- II-C. La classe Cylinder

- II-C-1. Champs

- II-C-2. Principaux constructeurs

- II-C-3. Principales méthodes

- II-C-4. Exemple

- II-D. La classe Cone

- II-D-1. Champs

- II-D-2. Principaux constructeurs

- II-D-3. Principales méthodes

- II-D-4. Exemple

- II-E. La classe Text2D

- II-E-1. Constructeur

- II-E-2. Principales méthodes

- II-E-3. Exemple

- III. Objets à géométrie complexe

- III-A. La classe PointArray

- III-A-1. Principal constructeur

- III-A-2. Principales méthodes

- III-A-3. Exemple

- III-B. La classe LineArray

- III-B-1. Principal constructeur

- III-B-2. Principales méthodes

- III-B-3. Exemple

- III-C. La classe TriangleArray

- III-C-1. Principal constructeur

- III-C-2. Principales méthodes

- III-C-3. Exemple

- III-D. La classe QuadArray

- III-D-1. Principal constructeur

- III-D-2. Principales méthodes

- III-D-3. Exemple

- III-E. La classe LineStripArray

- III-E-1. Principal constructeur

- III-E-2. Principales méthodes

- III-E-3. Exemple

- III-F. La classe TriangleStripArray

- III-F-1. Principal constructeur

- III-F-2. Principales méthodes

- III-F-3. Exemple

- III-G. La classe TriangleFanArray

- III-G-1. Principal constructeur

- III-G-2. Principales méthodes

- III-G-3. Exemple

- IV. Les objets à géométrie indicée

- IV-A. Construction de la pyramide multicolore à l'aide de la classe IndexedTriangleFanArray

- IV-B. Construction de la pyramide multicolore à l'aide de la classe GeometryInfo

- IV-B-1. Principal constructeur

- IV-B-2. Principales méthodes

- IV-B-3. Exemple

- V. Texte 3D

- V-A. Principaux champs

- V-B. Principal constructeur

- V-C. Principales méthodes

- V-D. Exemple

- VI. En préparation

- VII. Applets exemples

- VIII. Téléchargements

Introduction

Dans cette partie, nous allons voir en particulier quels sont les outils dont nous disposons plus créer des objets 3D plus ou moins complexes.

- Arrière-plans

- Formes de base

- Objets à géométrie complexe

- Texte 3D

I - Arrière-plans

Par défaut, l'arrière-plan d'une scène en Java 3D est toujours en noir opaque. Mais, pour diverses raisons, il se peut que l'utilisateur de Java 3D ait besoin d'un arrière-plan de couleur différente pour une scène 3D.
Il est possible de créer des arrière-plans avec une couleur de son choix, une image, ou même une géométrie. Nous étudierons dans ce chapitre la création d'arrière-plans à partir d'une couleur ou d'une image.

I-A - Création d'arrière-plans avec une couleur unie

Il existe deux constructeurs de la classe Background permettant de construire des arrière-plans avec une couleur personnalisée :

public Background(Color3f color)
//color étant la couleur de son choix pour l'arrière-plan

public Background(float r, float g, float b)
//les paramètres r, g et b étant les composantes couleurs dans la base RGB
//(ces paramètres variant de 0 à 1 inclus)

Les principales méthodes associées à ce type d'objet Background sont :

public void setColor(Color3f color)
// Mets à jour la couleur de l'arrière-plan avec la couleur color

public void setColor(float r, float g, float b)
//Mets à jour la couleur de l'arrière-plan avec la couleur définie par
//les paramètres r, g, b (base RGB).

public void setApplicationBounds(Bounds region)
//Définit le rayon d'action de l'arrière-plan d'après le paramètre region

Nous avons écrit un exemple d'application Java 3D avec un arrière-plan possédant une couleur bleue unie. Le fichier BackgroundColor.java présente le code source complet de cet exemple

// Étape 1 :
// Importation des packages Java 2
import java.applet.Applet;
import java.awt.*;

// Étape 2 :
// Importation des packages Java 3D
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.universe.*;
import javax.media.j3d.*;
import javax.vecmath.*;

public class BackgroundColor extends Applet {
public BackgroundColor() {
this.setLayout(new BorderLayout());

// Étape 3 :
// Creation du Canvas 3D
Canvas3D canvas3D = new Canvas3D(SimpleUniverse.getPreferredConfiguration());

this.add(canvas3D, BorderLayout.CENTER);

// Étape 4 :
// Creation d'un objet SimpleUniverse
SimpleUniverse simpleU = new SimpleUniverse(canvas3D);

// Étape 5 :
// Positionnement du point d'observation pour avoir une vue correcte de la
// scene 3D
simpleU.getViewingPlatform().setNominalViewingTransform();

// Étape 6 :
// Creation de la scene 3D qui contient tous les objets 3D que l'on veut
// visualiser
BranchGroup scene = createSceneGraph();

// Étape 7 :
// Compilation de la scene 3D
scene.compile();

// Étape 8:
// Attachement de la scene 3D a l'objet SimpleUniverse
simpleU.addBranchGraph(scene);
}

/**
* Creation de la scene 3D qui contient l'arriere-plan de couleur bleue
* @return scene 3D
*/
public BranchGroup createSceneGraph() {
// Creation de l'objet parent qui contiendra tous les autres objets 3D
BranchGroup parent = new BranchGroup();

// Construction de l'arriere-plan de couleur bleue unie et definition de
// son rayon d'action
Background background = new Background(new Color3f(Color.blue));
background.setApplicationBounds(new BoundingBox());

// On ajoute l'instance de Background a la scene 3D
parent.addChild(background);

return parent;
}

/**
* Étape 9 :
* Methode main() nous permettant d'utiliser cette classe comme une applet
* ou une application.
* @param args
*/

public static void main(String[] args) {
Frame frame = new MainFrame(new BackgroundColor(), 256, 256);
}
}

Exécutez l'applet BackgroundColor.html pour voir le résultat

Rayon d'action de l'arrière-plan.

Il ne faut surtout pas oublier de définir le rayon d'action de l'arrière-plan. Le cas échéant, celui-ci n'apparaîtrait pas. C'est la méthode setApplicationBounds() qui est utilisée pour définir ce rayon d'action.

I-B - Création d'arrière-plans avec une image de fond

Le constructeur de la classe Background permettant de créer des arrière-plans avec une image est le suivant :

public Background(ImageComponent2D image)
//Construit un arrière-plan avec le paramètre image comme image de fond

La principale méthode associée est :

public void setImage(ImageComponent2D image)
//Permet de mettre à jour l'image de fond de l'arrière-plan

Ce type d'arrière-plan est un peu plus difficile à créer que les arrière-plans à couleur unie. Voici les principales étapes à suivre :

I-B-1 - Lecture et chargement d'une image en mémoire

Il faut créer un objet de type ImageComponent2D à partir de l'image lue à l'étape précédente en n'oubliant pas de préciser le format RGB :

BufferedImage image = ImageIO.read(new File("image.jpg"));

I-B-2 - Création d'un objet de type ImageComponent2D

Il faut créer un objet de type ImageComponent2D à partir de l'image lue à l'étape précédente en n'oubliant pas de préciser le format RGB :

ImageComponent2D imageComponent2D =
new ImageComponent2D(ImageComponent2D.FORMAT_RGB, image);

I-B-3 - On initialise l'arrière-plan avec l'image de fond :

background.setImage(imageComponent2D);

L'exemple dont le code source complet se trouve dans le fichier BackgroundImage.java présente la création d'un arrière-plan à partir d'une image earth.jpg fournie avec les exemples Java 3D de Sun. Nous en avons extrait le listing de la méthode createSceneGraph() dont le rôle est la création de cet arrière-plan :

/**
* Creation de la scene 3D qui contient l'arriere-plan avec une image
* de fond.
* @return scene 3D
*/
public BranchGroup createSceneGraph() {
// Creation de l'objet parent qui contiendra tous les autres objets 3D
BranchGroup parent = new BranchGroup();

// Creation d'un arriere-plan par defaut (couleur noire unie)
Background background = new Background();

try {
// Lecture et chargement de l'image en memoire
BufferedImage image = ImageIO.read(new File("earth.jpg"));

// Creation d'un objet de type ImageComponent2D
ImageComponent2D imageComponent2D
new ImageComponent2D(ImageComponent2D.FORMAT_RGB, image);

// On place l'image de fond dans l'arriere-plan
background.setImage(imageComponent2D);

// On definit le rayon d'action de l'arriere-plan
background.setApplicationBounds(new BoundingBox());
}
catch (IOException ex) {
System.out.println("Impossible de charger le fichier image \"earth.jpg\"");
}

// On ajoute l'instance de Background a la scene 3D
parent.addChild(background);

return parent;
}

Exécutez l'applet BackgroundImage.html pour voir le résultat.

Il est possible que l'applet ne se lance pas correctement au sein du navigateur Internet Explorer si le service pack 2 de Windows XP est installé, car les applets Java sont bloquées par défaut.

Pour débloquer le lancement des applets dans Internet Explorer, il faut aller dans le menu Outils -> Options Internet puis choisir l'onglet Avancé et cocher la case « Autoriser le contenu actif à s'exécuter dans les fichiers de la zone Ordinateur local » dans les paramètres de sécurité.

II - Formes de base

Les formes de bases dérivent toutes de la classe Primitive. La bibliothèque Java 3D fournit quatre objets 3D de base :

- Le parallélépipède (classe Box)

- La sphère (classe Sphere)

- Le cylindre (classe Cylinder)

- Le cône (classe Cone)

Il existe également une autre forme de base, mais qui ne dérive pas de la classe Primitive, il s'agit de l'objet Text2D. La classe Text2D dérive de Shape3D que nous étudierons en détail dans le paragraphe dédié aux formes géométriques complexes. Il est nécessaire de distinguer l'objet Text2D qui est en fait un rectangle plat dans lequel on affiche une chaine de caractères, de l'objet Text3D qui est plutôt considéré comme un objet à géométrie complexe représentant un texte en relief. Dans ce chapitre, nous dédions un paragraphe spécial pour les objets de type Text3D.

II-A - La classe Box

Cette classe dérive de la classe Primitive. Elle représente un parallélépipède centré sur l'origine du repère. Chaque face est considérée comme un objet de type Shape3D.

II-A-1 - Champs

public static final int BACK
//Désigne la face arrière du parallélépipède.

public static final int BOTTOM
//Désigne la face du bas de parallélépipède

public static final int FRONT
//Désigne la face avant du parallélépipède.

public static final int LEFT
//Désigne la face gauche du parallélépipède

public static final int RIGHT
//Désigne la face droite du parallélépipède

public static final int TOP
//Désigne la face de dessus du parallélépipède

II-A-2 - Principaux constructeurs

public Box()
//Construit un parallélépipède par défaut de deux mètres de hauteur, largeur et
//profondeur centré sur l'origine du repère.

public Box(float xdim, float ydim, float zdim, Appearance appearance)
//Construit un parallélépipède avec une apparence donnée et dont les coins opposés
// ont pour coordonnées :
//[-xdim, -ydim, -zdim], et [xdim, ydim, zdim]

II-A-3 - Principales méthodes

public Appearance getAppearance(int partId)
//Récupère l'apparence de la face du parallélépipède désignée par partId
//(partId peut prendre une des six valeurs de champs
//BACK, BOTTOM, FRONT, LEFT, RIGHT, TOP)

public Shape3D getShape(int partId)
//Récupère une des faces de la boîte (désignée par partId).
//L'objet Shape3D récupéré contient la géométrie et l'apparence de la boîte.

public float getXDimension()
//Récupère la dimension en X de la boîte

public float getYDimension()
//Récupère la dimension en Y de la boîte

public float getZDimension()
//Récupère la dimension en Z de la boîte

public void setAppearance(Appearance appearance)
//Mets à jour l'apparence de la boîte avec le paramètre appearance.
//Cette apparence sera appliquée à toutes les faces de la boîte

II-A-4 - Exemple

L'exemple Box3D.java très simple décrit l'utilisation de la classe Box.
Il suffit de reprendre le code source ColorCube3D.java et de remplacer la création du cube 3D couleurs par un objet de type Box. Toutefois, contrairement à la classe utilitaire ColorCube, la classe Box va créer un objet de couleur noire par défaut si on ne met pas d'éclairage (sous éclairage, la couleur de l'objet créé sera blanche par défaut). Comme l'arrière-plan de la scène 3D est toujours noir par défaut, il est nécessaire de changer la couleur de cet arrière-plan afin que notre boîte noire soit visible :

* Création d'un arrière-plan de couleur blanche

Tout d'abord on définit la couleur blanche pour l'arrière-plan :

Background background = new Background(1, 1, 1);

On définit la taille de l'arrière-plan :

background.setApplicationBounds(new BoundingBox());

Enfin, on ajoute l'arrière-plan à l'objet parent

parent.addChild(background);

* Création du parallélépipède

parent.addChild(new Box(0.5f, 0.5f, 0.2f, null));

Le fichier Box3D.java présente le code source complet de cet exemple :

// Étape 1 :
// Importation des packages Java 2
import java.applet.Applet;
import java.awt.*;

// Étape 2 :
// Importation des packages Java 3D
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.geometry.*;
import com.sun.j3d.utils.universe.*;
import javax.media.j3d.*;

public class Box3D extends Applet {

public Box3D() {
this.setLayout(new BorderLayout());

// Étape 3 :
// Creation du Canvas 3D
Canvas3D canvas3D = new Canvas3D(SimpleUniverse.getPreferredConfiguration());
this.add(canvas3D, BorderLayout.CENTER);

// Étape 4 :
// Creation d'un objet SimpleUniverse
SimpleUniverse simpleU = new SimpleUniverse(canvas3D);

// Étape 5 :
// Positionnement du point d'observation pour avoir une vue correcte de la
// scene 3D
simpleU.getViewingPlatform().setNominalViewingTransform();

// Étape 6 :
// Creation de la scene 3D qui contient tous les objets 3D que l'on veut visualiser
BranchGroup scene = createSceneGraph();

// Étape 7 :
// Compilation de la scene 3D
scene.compile();

// Étape 8:
// Attachement de la scene 3D a l'objet SimpleUniverse
simpleU.addBranchGraph(scene);
}

/**
* Creation de la scene 3D qui contient tous les objets 3D
* @return scene 3D
*/
public BranchGroup createSceneGraph() {
// Creation de l'objet parent qui contiendra tous les autres objets 3D
BranchGroup parent = new BranchGroup();

/************ Partie de code concernant l'animation du cube *************/
/* Elle sera expliquee en detail dans les chapitres relatifs aux
transformations geometriques et aux animations */
TransformGroup objSpin = new TransformGroup();
objSpin.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
Alpha rotationAlpha = new Alpha(-1, 4000);
RotationInterpolator rotator =
new RotationInterpolator(rotationAlpha, objSpin);
BoundingSphere bounds = new BoundingSphere();
rotator.setSchedulingBounds(bounds);
objSpin.addChild(rotator);
/*************** Fin de la partie relative a l'animation ***************/

// arriere-plan en blanc
Background background = new Background(1, 1, 1);
background.setApplicationBounds(new BoundingBox());
parent.addChild(background);

// Construction du parallelepipede
objSpin.addChild(new Box(0.5f, 0.5f, 0.2f, null));
parent.addChild(objSpin);

return parent;
}

/**
* Étape 9 :
* Methode main() nous permettant d'utiliser cette classe comme une applet
* ou une application.
* @param args
*/
public static void main(String[] args) {
Frame frame = new MainFrame(new Box3D(), 256, 256);
}
}

Exécutez l'applet Box3D.html pour voir le résultat.

II-B - La classe Sphere

Cette classe dérive de la classe Primitive. Elle représente une sphère de rayon 1 centrée sur l'origine du repère.

II-B-1 - Champs

public static final int BODY
//Ce champ sert d'identificateur pour pouvoir utiliser les méthodes :
//getShape() et getAppearance().

II-B-2 - Principaux constructeurs

public Sphere()
//Construit une sphère de rayon 1 et centrée sur l'origine du repère par défaut.

public Sphere(float radius)
//Construit une sphère centrée sur l'origine et de rayon radius.

public Sphere(float radius, Appearance appearance)
//Construit une sphère centrée sur l'origine, de rayon radius et d'apparence appearance.

public Sphere(float radius, int primflags, int divisions)
//Construit une sphère centrée sur l'origine, de rayon radius.
//primflags est un paramètre additionnel pouvant être égal à une constante de
//la classe Primitive et divisions représente le nombre de divisions
//pour chaque axe du repère servant a construire les facettes constituant la sphère.

II-B-3 - Principales méthodes

public Appearance getAppearance(int partId)
//Renvoie l'apparence de la sphère.
//Ici, partId représente l'identificateur de la sphère, c'est-à-dire la constante BODY.

public float getRadius()
//Renvoie le rayon de la sphère.

public Shape3D getShape()
//Récupère un objet de type Shape3D contenant la géométrie et l'apparence de la sphère

public void setAppearance(Appearance appearance)
//Mets à jour l'apparence de la sphère avec le paramètre appearance.

II-B-4 - Exemple

L'exemple Sphere3D.java très simple décrit l'utilisation de la classe Sphere.
Il suffit de reprendre le code source Box3D.java et de remplacer la création du parallélépipède par un objet de type Sphere. Tout comme l'objet Box, la sphère sera de couleur noire par défaut si aucun éclairage n'est défini, d'où la nécessité d'avoir un arrière-plan blanc afin de pouvoir la visualiser.
Nous modifions donc la ligne :

parent.addChild(new Box(0.5f, 0.5f, 0.2f, null));

du fichier Box3D.java pour la remplacer par :

parent.addChild(new Sphere( 0.5f));

Exécutez l'applet Sphere3D.html pour voir le résultat.

II-C - La classe Cylinder

Cette classe dérive de la classe Primitive. Elle représente un cylindre fermé, centré sur l'origine du repère et dont l'axe central est confondu avec l'axe Y. Le cylindre est donc formé de trois parties distinctes : le corps du cylindre, le disque du bas et le disque du haut. Chacune de ces trois parties est considérée comme un objet 3D de type Shape3D.

II-C-1 - Champs

public static final int BODY
//Désigne le corps du cylindre.

public static final int BOTTOM
//Désigne le disque du bas du cylindre

public static final int TOP
//Désigne le disque du haut du cylindre.

II-C-2 - Principaux constructeurs

public Cylinder()
//Construit un cylindre centré sur l'origine, de rayon 1 et de hauteur 2

public Cylinder(float radius, float height)
//Construit un cylindre centré sur l'origine, de rayon radius et de hauteur height.

public Cylinder(float radius, float height, Appearance appearance)
//Construit un cylindre centré sur l'origine, de rayon radius, de hauteur height
//, et d'apparence appearance.

II-C-3 - Principales méthodes

public Appearance getAppearance(int partId)
//Renvoie l'apparence du cylindre. Ici, partId représente la partie du cylindre
//dont on réclame l'apparence, c'est à dire : BODY, BOTTOM ou TOP.

public float getHeight()
//Renvoie la hauteur du cylindre.

public float getRadius()
//Renvoie le rayon du cylindre.

public Shape3D getShape(int partId)
//Récupère un objet de type Shape3D contenant la géométrie et l'apparence de
//la partie du cylindre désignée par partId.

public void setAppearance(Appearance appearance)
//Mets à jour l'apparence du cylindre avec le paramètre appearance.

II-C-4 - Exemple

L'exemple Cynlindre3D.java très simple décrit l'utilisation de la classe Cylinder.
Il suffit de reprendre le code source Box3D.java et de remplacer la création du parallélépipède par un objet de type Cylinder. Tout comme l'objet Box, le cylindre sera de couleur noire par défaut si aucun éclairage n'est défini, d'où la nécessité d'avoir un arrière-plan blanc afin de pouvoir le visualiser.
Nous modifions donc la ligne :

parent.addChild(new Box(0.5f, 0.5f, 0.2f, null));

du fichier Box3D.java pour la remplacer par :

parent.addChild(new Cylinder(0.5f, 1.0f));

Exécutez l'applet Cylindre3D.html pour voir le résultat.

II-D - La classe Cone

Cette classe dérive de la classe Primitive. Elle représente un cône fermé à la base, centré sur l'origine du repère et dont l'axe central est confondu avec l'axe Y. Le cône est donc formé de deux parties distinctes : le corps et le disque qui constitue sa base. Chacune de ces deux parties est considérée comme un objet 3D de type Shape3D.

II-D-1 - Champs

public static final int BODY
//Désigne le corps du cône.

public static final int CAP
//Désigne la base du cylindre.

II-D-2 - Principaux constructeurs

public Cone()
//Construit un cône centré sur l'origine, de rayon 1 et de hauteur 2.

public Cone(float radius, float height)
//Construit un cône centré sur l'origine, de rayon radius et de hauteur height.

public Cone(float radius, float height, Appearance appearance)
//Construit un cône centré sur l'origine, de rayon radius, de hauteur height,
//et d'apparence appearance.

II-D-3 - Principales méthodes

public Appearance getAppearance(int partId)
//Renvoie l'apparence du cône.
//Ici, partId représente la partie du cylindre dont on réclame l'apparence,
//c'est à dire : BODY ou CAP.

public float getHeight()
//Renvoie la hauteur du cône.

public float getRadius()
//Renvoie le rayon du cône.

public Shape3D getShape(int partId)
//Récupère un objet de type Shape3D contenant la géométrie et l'apparence de
//la partie du cône désignée par partId.

public void setAppearance(Appearance appearance)
//Mets à jour l'apparence du cône avec le paramètre appearance.

II-D-4 - Exemple

L'exemple Cone3D.java très simple décrit l'utilisation de la classe Cone.
Il suffit de reprendre le code source Box3D.java et de remplacer la création du parallélépipède par un objet de type Cone. Tout comme l'objet Box, le cylindre sera de couleur noire par défaut si aucun éclairage n'est défini, d'où la nécessité d'avoir un arrière-plan blanc afin de pouvoir le visualiser.
Nous modifions donc la ligne :

parent.addChild(new Box(0.5f, 0.5f, 0.2f, null));

du fichier Box3D.java pour la remplacer par :

parent.addChild(new Cone(0.5f, 1.0f));

Exécutez l'applet Cone3D.html pour voir le résultat.

II-E - La classe Text2D

Cette classe dérive de la classe Shape3D et non pas de la classe Primitive comme les trois objets que nous venons d'étudier. Elle permet d'afficher du texte sans relief dans une scène 3D.

II-E-1 - Constructeur

public Text2D(String text, Color3f color, String fontName, int fontSize, int fontStyle)

Construit un objet texte comme une image dont l'arrière-plan est transparent et dans laquelle on écrit une chaine de caractères spécifiée par le paramètre text. La couleur, la police, la taille et le style de la police sont respectivement spécifiés par color, fontName, fontSize et fontStyle.

En fait, cet objet texte pourrait être assimilé à un rectangle transparent sur lequel on plaque une texture qui représente le texte à afficher.

II-E-2 - Principales méthodes

public Color3f getColor()
//Récupère la couleur du texte.

public String getFontName()
//Renvoie le nom de la police

public int getFontSize()
//Renvoie la taille de la police.

public int getFontStyle()
//Renvoie le style de la police.

public String getString()
//Renvoie le texte affiché sous forme de String.

public String setString(String text)
//Mets à jour l'objet Text2D avec un nouveau texte à afficher.

II-E-3 - Exemple

L'exemple HelloWorld2D.java très simple décrit l'utilisation de la classe Text2D. Si nous décidons de créer un texte de couleur verte, il n'est plus nécessaire d'avoir un arrière-plan blanc. Dans notre exemple, nous construisons l'objet Text2D comme suit :

parent.addChild(new Text2D("Hello world", new Color3f(Color.green), "Lucida sans", 36,
Font.BOLD));

Exécutez l'applet HelloWorld2D.html pour voir le résultat.

III - Objets à géométrie complexe

Les objets 3D de base que nous venons d'étudier permettent déjà de construire des applications intéressantes, mais le concepteur du programme se trouvera vite limité dès qu'il s'agira de représenter à l'écran des objets plus réalistes et par conséquent plus complexes.
Ces objets plus complexes sont appelés objets géométriques, ils dérivent tous de la classe GeometryArray. Nous vous proposons de les étudier dans ce paragraphe.

III-A - La classe PointArray

Cette classe permet de construire un objet constitué d'un ensemble de points isolés. Nous ne décrirons pas tous les champs et méthodes associés à cette classe, car il faudrait plusieurs dizaines de pages, ce qui n'est pas notre but ici. La description complète de la classe PointArray se trouve dans la documentation de Java 3D fournie pas Sun. Nous nous contenterons d'en expliquer le fonctionnement de base par un exemple concret.

III-A-1 - Principal constructeur

public PointArray(int vertexCount, int vertexFormat)

vertexCount indique le nombre de points ou de sommets ( vertex en anglais) que possède l'objet.
vertexFormat permet de définir les propriétés associées aux sommets, les valeurs possibles de ce paramètre sont les constantes de la classe GeometryArray dont PointArray hérite.

Ce constructeur définit un objet vide, mais dont on a déjà décidé du nombre de sommets et de leur format. Les coordonnées de ces sommets sont définies à l'aide de la méthode setCoordinates() qui est héritée de GeometryArray.

III-A-2 - Principales méthodes

public void setCoordinates (int index, Point3f[] coordinates)

Mets à jour les coordonnées des points de l'objet.
index représente l'indice désignant le numéro du point à partir duquel les coordonnées vont être mises à jour par les valeurs provenant du tableau coordinates.

public void setColors (int index, Color3f[] colors)

Mets à jour les couleurs des points de l'objet.
index représente l'indice désignant le numéro du point à partir duquel les couleurs vont être mises à jour par les valeurs provenant du tableau colors.

III-A-3 - Exemple

Le fichier PointArray3D.java est un exemple d'utilisation de la classe PointArray. Il s'agit de représenter un cercle constitué de points qui est en rotation autour de l'axe vertical Y du repère 3D.
L'idée consiste d'abord à créer une classe EnsemblePoints qui permet de construire un objet géométrique de type PointArray, il est indispensable que cette classe étende la classe Shape3D afin de pouvoir l'ajouter à la scène 3D de notre application :

class EnsemblePoints extends Shape3D

L'objet de type PointArray est créé par les lignes suivantes :

PointArray pointArray = new PointArray(nbPoints, PointArray.COORDINATES |
PointArray.COLOR_3);
pointArray.setCoordinates(0, points);
pointArray.setColors(0, colors);

Le paramètre vertexFormat du constructeur de PointArray est une combinaison (masque) des champs PointArray.COORDINATES et PointArray.COLOR_3. Le champ PointArray.COORDINATES est obligatoire, tandis que le champ PointArray.COLOR_3 indique que notre objet PointArray sera créé avec des sommets en couleurs (le suffixe _3 correspond à une couleur sans transparence, _4 correspond à une couleur avec transparence).

Enfin, il ne reste plus qu'à mettre à jour la géométrie de notre objet EnsemblePoints avec l'objet géométrique de type PointArray :

this.setGeometry(pointArray);

Le fichier PointArray3D.java présente le code source complet de cet exemple :

// Étape 1 :
// Importation des packages Java 2
import java.applet.Applet;
import java.awt.*;

// Étape 2 :
// Importation des packages Java 3D
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.geometry.*;
import com.sun.j3d.utils.universe.*;
import javax.media.j3d.*;
import javax.vecmath.*;

public class PointArray3D extends Applet {

public PointArray3D() {
this.setLayout(new BorderLayout());

// Étape 3 :
// Creation du Canvas 3D
Canvas3D canvas3D = new Canvas3D(SimpleUniverse.getPreferredConfiguration());
this.add(canvas3D, BorderLayout.CENTER);

// Étape 4 :
// Creation d'un objet SimpleUniverse
SimpleUniverse simpleU = new SimpleUniverse(canvas3D);

// Étape 5 :
// Positionnement du point d'observation pour avoir une vue correcte de la scene 3D
simpleU.getViewingPlatform().setNominalViewingTransform();

// Étape 6 :
// Creation de la scene 3D qui contient tous les objets 3D que l'on veut visualiser
BranchGroup scene = createSceneGraph();

// Étape 7 :
// Compilation de la scene 3D
scene.compile();

// Étape 8:
// Attachement de la scene 3D a l'objet SimpleUniverse
simpleU.addBranchGraph(scene);
}

/**
* Creation de la scene 3D qui contient tous les objets 3D
* @return scene 3D
*/
public BranchGroup createSceneGraph() {
// Creation de l'objet parent qui contiendra tous les autres objets 3D
BranchGroup parent = new BranchGroup();

/************ Partie de code concernant l'animation *************/
/* Elle sera expliquee en détails dans les chapitres relatifs aux
transformations geometriques et aux animations */
TransformGroup objSpin = new TransformGroup();
objSpin.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
Alpha rotationAlpha = new Alpha(-1, 4000);
RotationInterpolator rotator =
new RotationInterpolator(rotationAlpha, objSpin);
BoundingSphere bounds = new BoundingSphere();
rotator.setSchedulingBounds(bounds);
objSpin.addChild(rotator);
/*************** Fin de la partie relative a l'animation ***************/

// On ajoute l'objet geometrique a la scene 3D, les points sont de couleur
// jaune
objSpin.addChild(new EnsemblePoints(50, Color.yellow));
parent.addChild(objSpin);

return parent;
}

/**
* Objet geometrique qui represente un ensemble de points isoles en forme de
* cercle
*/
class EnsemblePoints extends Shape3D {

/**
* Constructeur
* @param nbPoints nombre de points
*/
public EnsemblePoints(int nbPoints, Color color) {
Point3f points[] = new Point3f[nbPoints];
Color3f colors[] = new Color3f[nbPoints];

for (int i = 0 ; i < nbPoints ; i++) {
points[i] = new Point3f(0.5f*(float)Math.cos(2*i*Math.PI/nbPoints),
0.5f*(float)Math.sin(2*i*Math.PI/nbPoints),
0f);

colors[i] = new Color3f(color);
} // fin for (int i = 0 ; i < nbPoints ; i++)

// Construction de l'objet geometrique PointArray
PointArray pointArray = new PointArray(nbPoints,
PointArray.COORDINATES |
PointArray.COLOR_3);
pointArray.setCoordinates(0, points);
pointArray.setColors(0, colors);

this.setGeometry(pointArray);
} // fin constructeur
} // fin class EnsemblePoints extends Shape3D

/**
* Étape 9 :
* Methode main() nous permettant d'utiliser cette classe comme une applet
* ou une application.
* @param args
*/
public static void main(String[] args) {
Frame frame = new MainFrame(new PointArray3D(), 256, 256);
}
}

Exécutez l'applet PointArray3D.html pour voir le résultat.

III-B - La classe LineArray

Cette classe permet de construire un ensemble de lignes constituées de points reliés deux à deux. Dans ce paragraphe, nous allons expliquer les fonctionnalités de base de cette classe.

III-B-1 - Principal constructeur

public LineArray(int vertexCount, int vertexFormat)

vertexCount indique le nombre de points qui vont constituer l'ensemble des lignes.
vertexFormat permet de définir les propriétés associées aux points, les valeurs possibles de ce paramètre sont les constantes de la classe GeometryArray dont LineArray hérite.

Ce constructeur définit un objet vide, mais dont on a déjà décidé du nombre de points constituant l'ensemble des lignes et de leur format. Les coordonnées de ces points sont définies à l'aide de la méthode setCoordinates() qui est héritée de GeometryArray.

III-B-2 - Principales méthodes

public void setCoordinates (int index, Point3f[] coordinates)

Mets à jour les coordonnées des points de l'objet.
index représente l'indice désignant le numéro du point à partir duquel les coordonnées vont être mises à jour par les valeurs provenant du tableau coordinates.

public void setColors (int index, Color3f[] colors)

Mets à jour les couleurs des points de l'objet.
index représente l'indice désignant le numéro du point à partir duquel les couleurs vont être mises à jour par les valeurs provenant du tableau colors.

III-B-3 - Exemple

Le fichier LineArray3D.java est un exemple d'utilisation de la classe LineArray. Il s'agit de représenter un ensemble de lignes en forme de cercle qui est en rotation autour de l'axe vertical Y du repère 3D.
L'idée consiste d'abord à créer une classe EnsembleLignes qui permet de construire un objet géométrique de type LineArray, il est indispensable que cette classe étende la classe Shape3D afin de pouvoir l'ajouter à la scène 3D de notre application :

class EnsemblePoints extends Shape3D

L'objet de type LineArray est créé par les lignes suivantes :

LineArray lineArray = new LineArray(nbLignes*2, LineArray.COORDINATES |
LineArray.COLOR_3);
lineArray.setCoordinates(0, points);
lineArray.setColors(0, colors);

Le paramètre vertexFormat du constructeur de LineArray est une combinaison (masque) des champs LineArray.COORDINATES et LineArray.COLOR_3. Le champ LineArray.COORDINATES est obligatoire, tandis que le champ LineArray.COLOR_3 indique que notre objet LineArray sera créé avec des points en couleurs (le suffixe _3 correspond à une couleur sans transparence, _4 correspond à une couleur avec transparence).

Enfin, il ne reste plus qu'à mettre à jour la géométrie de notre objet EnsembleLignes avec l'objet géométrique de type LineArray.:

this.setGeometry(lineArray);

Le fichier LineArray3D.java présente le code source complet de cet exemple. Nous en avons extrait le listing de la classe EnsembleLignes qui prend en charge la construction d'un objet LineArray :

/**
* Objet geometrique qui represente un ensemble de lignes en forme de
* cercle
*/
class EnsembleLignes extends Shape3D {

/**
* Constructeur
* @param nbLignes nombre de lignes (chacune constituee de 2 points)
*/
public EnsembleLignes(int nbLignes, Color color) {
Point3f points[] = new Point3f[nbLignes*2];
Color3f colors[] = new Color3f[nbLignes*2];

for (int i = 0 ; i < nbLignes ; i++) {

// Premier point de la ligne i
points[2*i] = new Point3f(0f, 0f, 0f);
colors[2*i] = new Color3f(color);

// Deuxieme point de la ligne i
points[2*i+1] = new Point3f(0.5f*(float)Math.cos(2*i*Math.PI/nbLignes),
0.5f*(float)Math.sin(2*i*Math.PI/nbLignes),
0f);
colors[2*i+1] = new Color3f(color);
} // fin for (int i = 0 ; i < nbLignes ; i++)

// Construction de l'objet geometrique PointArray
LineArray lineArray = new LineArray(nbLignes*2, LineArray.COORDINATES |
LineArray.COLOR_3);
lineArray.setCoordinates(0, points);
lineArray.setColors(0, colors);

this.setGeometry(lineArray);
} // fin constructeur
} // fin class EnsembleLignes extends Shape3D

Exécutez l'applet LineArray3D.html pour voir le résultat.

III-C - La classe TriangleArray

Cette classe permet de construire un ensemble de triangles indépendants qui vont former les facettes d'une surface 3D. Ces triangles sont construits en utilisant les points de l'objet TriangleArray trois par trois. Dans ce paragraphe, nous allons expliquer les fonctionnalités de base de cette classe.

III-C-1 - Principal constructeur

public TriangleArray(int vertexCount, int vertexFormat)

vertexCount indique le nombre de points qui vont constituer l'ensemble des triangles.
vertexFormat permet de définir les propriétés associées aux points, les valeurs possibles de ce paramètre sont les constantes de la classe GeometryArray dont TriangleArray hérite.

Ce constructeur définit un objet vide, mais dont on a déjà décidé du nombre de points constituant l'ensemble des triangles et de leur format. Les coordonnées de ces points sont définies à l'aide de la méthode setCoordinates() qui est héritée de GeometryArray.

III-C-2 - Principales méthodes

public void setCoordinates (int index, Point3f[] coordinates)

Mets à jour les coordonnées des points de l'objet.
index représente l'indice désignant le numéro du point à partir duquel les coordonnées vont être mises à jour par les valeurs provenant du tableau coordinates.

public void setColors (int index, Color3f[] colors)

Mets à jour les couleurs des points de l'objet.
index représente l'indice désignant le numéro du point à partir duquel les couleurs vont être mises à jour par les valeurs provenant du tableau colors.

III-C-3 - Exemple

Le fichier TriangleArray3D.java est un exemple d'utilisation de la classe TriangleArray. Il s'agit de représenter une pyramide à base carrée qui est en rotation autour de l'axe vertical Y du repère 3D. La facette constituant la base de notre pyramide ne sera pas visible dans la scène 3D, nous ne la construirons donc pas.
L'idée consiste d'abord à créer une classe Pyramide qui permet de construire un objet géométrique de type TriangleArray, il est indispensable que cette classe étende la classe Shape3D afin de pouvoir l'ajouter à la scène 3D de notre application :

class Pyramide extends Shape3D

L'objet de type TriangleArray est créé par les lignes suivantes :

TriangleArray triangleArray = new TriangleArray(12,
TriangleArray.COORDINATES |
TriangleArray.COLOR_3);

Le paramètre vertexFormat du constructeur de TriangleArray est une combinaison (masque) des champs TriangleArray.COORDINATES et TriangleArray.COLOR_3. Le champ TriangleArray.COORDINATES est obligatoire, tandis que le champ TriangleArray.COLOR_3 indique que notre objet TriangleArray sera créé avec des sommets en couleurs (le suffixe _3 correspond à une couleur sans transparence, _4 correspond à une couleur avec transparence).

La pyramide possède 5 sommets, mais en réalité notre objet TriangleArray possède 12 points, car les sommets sont communs à plusieurs facettes :

triangleArray.setCoordinates(0, new Point3f[] {
/* face 1 */                 sommet, base1, base2,
/* face 2 */                 sommet, base2, base3,
/* face 3 */                 sommet, base3, base4,
/* face 4 */                 sommet, base4, base1
});

L'ordre des points pour chaque facette est très important. Pour qu'une facette soit visible quand elle est dirigée vers l'observateur, il faut que ses sommets soient énumérés dans le sens direct (sens inverse des aiguilles d'une montre).

Essayez, dans le fichier TriangleArray3D.java d'inverser les sommets de la facette 1 [sommet, base2, base1] par exemple, et vous verrez que la pyramide aura une facette noire !

Ensuite, si nous voulons attribuer une couleur uniforme à chaque face, il faut que les 3 sommets de chaque face aient la même couleur :

triangleArray.setColors(0, new Color3f[] {
/* couleur face 1 */    colorface1, colorface1, colorface1,
/* couleur face 1 */    colorface2, colorface2, colorface2,
/* couleur face 1 */    colorface3, colorface3, colorface3,
/* couleur face 1 */    colorface4, colorface4, colorface4
});

Si chacun des trois sommets de la facette possède une couleur différente ( [colorface1, colorface2, colorface3] pour la face 1 par exemple), nous aurons un très bel effet de dégradé obtenu par interpolation des couleurs.

Enfin, il ne reste plus qu'à mettre à jour la géométrie de notre objet Pyramide avec l'objet géométrique de type TriangleArray :

this.setGeometry(triangleArray);

Le fichier TriangleArray3D.java présente le code source complet de cet exemple. Nous en avons extrait le listing de la classe Pyramide qui prend en charge la construction d'un objet TriangleArray :

/**
* Objet geometrique qui represente une pyramide a base carree
*/
class Pyramide extends Shape3D {

/**
* Constructeur
*/
public Pyramide() {
// Les coordonnees des 5 sommets de la pyramide
Point3f sommet = new Point3f( 0f, 0.5f, 0f);
Point3f base1 = new Point3f (-0.5f, -0.5f, -0.5f);
Point3f base2 = new Point3f (-0.5f, -0.5f, 0.5f);
Point3f base3 = new Point3f ( 0.5f, -0.5f, 0.5f);
Point3f base4 = new Point3f ( 0.5f, -0.5f, -0.5f);

// Les couleurs des 4 faces de la pyramide
Color3f colorface1 = new Color3f(Color.red);
Color3f colorface2 = new Color3f(Color.cyan);
Color3f colorface3 = new Color3f(Color.yellow);
Color3f colorface4 = new Color3f(Color.green);

// Construction de l'objet geometrique TriangleArray constitue de 12
// points
TriangleArray triangleArray = new TriangleArray(12,
TriangleArray.COORDINATES |
TriangleArray.COLOR_3);

// Tableau des points constituant les 4 faces (triangles)
triangleArray.setCoordinates(0, new Point3f[] {
/* face 1 */                 sommet, base1, base2,
/* face 2 */                 sommet, base2, base3,
/* face 3 */                 sommet, base3, base4,
/* face 4 */                 sommet, base4, base1
});

// Tableau des couleurs des 3 sommets de chaque faces
triangleArray.setColors(0, new Color3f[] {
/* couleur face 1 */    colorface1, colorface1, colorface1,
/* couleur face 1 */    colorface2, colorface2, colorface2,
/* couleur face 1 */    colorface3, colorface3, colorface3,
/* couleur face 1 */    colorface4, colorface4, colorface4
});

this.setGeometry(triangleArray);
} // fin constructeur
} // fin class Pyramide extends Shape3D

Exécutez l'applet TriangleArray3D.html pour voir le résultat.

III-D - La classe QuadArray

Cette classe permet de construire un ensemble de quadrilatères indépendants qui vont former les facettes d'une surface 3D. Ces quadrilatères sont construits en utilisant les points de l'objet QuadArray par groupe de quatre. Dans ce paragraphe, nous allons expliquer les fonctionnalités de base de cette classe.

III-D-1 - Principal constructeur

public QuadArray(int vertexCount, int vertexFormat)

vertexCount indique le nombre de points qui vont constituer l'ensemble des quadrilatères.
vertexFormat permet de définir les propriétés associées aux points, les valeurs possibles de ce paramètre sont les constantes de la classe GeometryArray dont QuadArray hérite.

Ce constructeur définit un objet vide, mais dont on a déjà décidé du nombre de points constituant l'ensemble des quadrilatères et de leur format. Les coordonnées de ces points sont définies à l'aide de la méthode setCoordinates() qui est héritée de GeometryArray.

III-D-2 - Principales méthodes

public void setCoordinates(int index, Point3f[] coordinates)

Mets à jour les coordonnées des points de l'objet.
index représente l'indice désignant le numéro du point à partir duquel les coordonnées vont être mises à jour par les valeurs provenant du tableau coordinates

public void setColors(int index, Color3f[] colors)

Mets à jour les couleurs des points de l'objet.
index représente l'indice désignant le numéro du point à partir duquel les couleurs vont être mises à jour par les valeurs provenant du tableau colors.

III-D-3 - Exemple

Le fichier QuadArray3D.java est un exemple d'utilisation de la classe QuadArray. Il s'agit de représenter un cube dont les faces possèdent une couleur différente et qui est en rotation autour de l'axe vertical Y du repère 3D. En fait, nous allons construire un objet dont l'aspect sera en tout point identique à la classe utilitaire ColorCube, à l'exception près que nous ne construirons pas les faces du haut et du bas de cube, car elles ne seront pas visibles dans la scène 3D.

L'idée consiste d'abord à créer une classe Cube qui permet de construire un objet géométrique de type QuadArray, il est indispensable que cette classe étende la classe Shape3D afin de pouvoir l'ajouter à la scène 3D de notre application :

class Cube extends Shape3D

L'objet de type QuadArray est créé par les lignes suivantes :

QuadArray quadArray = new QuadArray(16,
QuadArray.COORDINATES | QuadArray.COLOR_3);

Le paramètre vertexFormat du constructeur de QuadArray est une combinaison (masque) des champs QuadArray.COORDINATES et QuadArray.COLOR_3. Le champ QuadArray.COORDINATES est obligatoire, tandis que le champ QuadArray.COLOR_3 indique que notre objet QuadArray sera créé avec des sommets en couleurs (le suffixe _3 correspond à une couleur sans transparence, _4 correspond à une couleur avec transparence).

Le cube possède 8 sommets, mais en réalité notre objet QuadArray possède 16 points, car les sommets sont communs à plusieurs facettes :

quadArray.setCoordinates(0, new Point3f[] {
/* face 1 */             face1_s1, face1_s2, face1_s3, face1_s4,
/* face 2 */             face2_s1, face2_s2, face2_s3, face2_s4,
/* face 3 */             face3_s1, face3_s2, face3_s3, face3_s4,
/* face 4 */             face4_s1, face4_s2, face4_s3, face4_s4
});

Comme pour l'objet TriangleArray, il faut bien veiller à ce que les sommets des faces soient énumérés dans le sens direct (inverse des aiguilles d'une montre).

Ensuite, nous attribuons une couleur uniforme à chaque face du cube :

quadArray.setColors(0, new Color3f[] {
/* couleur face 1 */ color1, color1, color1, color1,
/* couleur face 2 */ color2, color2, color2, color2,
/* couleur face 3 */ color3, color3, color3, color3,
/* couleur face 4 */ color4, color4, color4, color4
});

Enfin, il ne reste plus qu'à mettre à jour la géométrie de notre objet Cube avec l'objet géométrique de type QuadArray.:

this.setGeometry(quadArray);

Le fichier QuadArray3D.java présente le code source complet de cet exemple. Nous en avons extrait le listing de la classe Cube qui prend en charge la construction d'un objet QuadArray :

/**
* Objet geometrique qui represente un cube dont les faces visibles
* sont colorees
*/
class Cube extends Shape3D {

/**
* Constructeur
*/
public Cube() {
// Les coordonnees des 16 sommets des 4 faces visibles du cube
// Face 1
Point3f face1_s1 = new Point3f(-0.5f, 0.5f, 0.5f);
Point3f face1_s2 = new Point3f(-0.5f, -0.5f, 0.5f);
Point3f face1_s3 = new Point3f( 0.5f, -0.5f, 0.5f);
Point3f face1_s4 = new Point3f( 0.5f, 0.5f, 0.5f);

// Face 2
Point3f face2_s1 = new Point3f( 0.5f, 0.5f, 0.5f);
Point3f face2_s2 = new Point3f( 0.5f, -0.5f, 0.5f);
Point3f face2_s3 = new Point3f( 0.5f, -0.5f, -0.5f);
Point3f face2_s4 = new Point3f( 0.5f, 0.5f, -0.5f);

// Face 3
Point3f face3_s1 = new Point3f( 0.5f, 0.5f, -0.5f);
Point3f face3_s2 = new Point3f( 0.5f, -0.5f, -0.5f);
Point3f face3_s3 = new Point3f(-0.5f, -0.5f, -0.5f);
Point3f face3_s4 = new Point3f(-0.5f, 0.5f, -0.5f);

// Face 4
Point3f face4_s1 = new Point3f(-0.5f, 0.5f, -0.5f);
Point3f face4_s2 = new Point3f(-0.5f, -0.5f, -0.5f);
Point3f face4_s3 = new Point3f(-0.5f, -0.5f, 0.5f);
Point3f face4_s4 = new Point3f(-0.5f, 0.5f, 0.5f);

// Les couleurs des 4 faces visibles du cube
Color3f color1 = new Color3f(Color.red);
Color3f color2 = new Color3f(Color.green);
Color3f color3 = new Color3f(Color.blue);
Color3f color4 = new Color3f(Color.yellow);

// Construction de l'objet geometrique QuadArray constitue de 16
// points
QuadArray quadArray = new QuadArray(16,
QuadArray.COORDINATES | QuadArray.COLOR_3);

// Tableau des points constituant les 4 faces (quadrilateres) qui
// sont visibles
quadArray.setCoordinates(0, new Point3f[] {
/* face 1 */             face1_s1, face1_s2, face1_s3, face1_s4,
/* face 2 */             face2_s1, face2_s2, face2_s3, face2_s4,
/* face 3 */             face3_s1, face3_s2, face3_s3, face3_s4,
/* face 4 */             face4_s1, face4_s2, face4_s3, face4_s4
});

// Tableau des couleurs des 4 sommets de chaque face
quadArray.setColors(0, new Color3f[] {
/* couleur face 1 */ color1, color1, color1, color1,
/* couleur face 2 */ color2, color2, color2, color2,
/* couleur face 3 */ color3, color3, color3, color3,
/* couleur face 4 */ color4, color4, color4, color4
});

this.setGeometry(quadArray);
} // fin constructeur
} // fin class Cube extends Shape3D

Exécutez l'applet QuadArray3D.html pour voir le résultat.
Les trois objets géométriques que nous allons étudier dans les paragraphes suivants, LineStripArray, TriangleStripArray et TriangleFanArray sont un petit peu plus difficiles à appréhender, mais ce sont en général les classes les plus pratiques et par conséquent les plus utilisées pour construire des objets 3D complexes.

III-E - La classe LineStripArray

Cette classe permet de construire un ensemble de lignes, elles-mêmes constituées d'un ensemble de plusieurs points reliés entre eux. Ces lignes sont également appelées « bandes » (strip en anglais). Il ne faut pas confondre cette classe avec LineArray qui permet de construire un ensemble de lignes constituées de deux points seulement reliés entre eux. Dans ce paragraphe, nous allons expliquer les fonctionnalités de base de cette classe.

III-E-1 - Principal constructeur

public LineStripArray(int vertexCount, int vertexFormat, int[] stripVertexCounts)

vertexCount indique le nombre de points qui vont constituer l'ensemble des lignes.

vertexFormat permet de définir les propriétés associées aux points, les valeurs possibles de ce paramètre sont les constantes de la classe GeometryArray dont LineStripArray hérite.

stripVertexCount est un tableau qui spécifie le nombre de points pour chaque ligne ou bande constituant l'objet LineStripArray.

Ce constructeur définit un objet vide, mais dont on a déjà décidé du nombre de points constituant l'ensemble des lignes et de leur format. Les coordonnées de ces points sont définies à l'aide de la méthode setCoordinates() qui est héritée de GeometryArray.

III-E-2 - Principales méthodes

public void setCoordinates(int index, Point3f[] coordinates)

Mets à jour les coordonnées des points de l'objet.
index représente l'indice désignant le numéro du point à partir duquel les coordonnées vont être mises à jour par les valeurs provenant du tableau coordinates.

public void setColors(int index, Color3f[] colors)

Mets à jour les couleurs des points de l'objet.
index représente l'indice désignant le numéro du point à partir duquel les couleurs vont être mises à jour par les valeurs provenant du tableau colors.

III-E-3 - Exemple

Le fichier LineStripArray3D.java est un exemple d'utilisation de la classe LineStripArray. Il s'agit de représenter une sphère constituée de lignes et qui est en rotation autour de l'axe vertical Y du repère 3D.
L'idée consiste d'abord à créer une classe SphereWithLines qui permet de construire un objet géométrique de type LineStripArray, il est indispensable que cette classe étende la classe Shape3D afin de pouvoir l'ajouter à la scène 3D de notre application :

class SphereWithLines extends Shape3D

Ensuite, notre objet LineStripArray sera constitué de 36 lignes de 19 points chacune :

int nbBandesVert = 36; // nombre de lignes (bandes)
int nbPtsParBandes = 19; // nombre de points par ligne

Pour définir les coordonnées des points qui vont former la sphère, nous utilisons un système de coordonnées sphériques (ou angulaires) dont la correspondance avec le repère 3D cartésien utilisé par Java 3D est la suivante :

X = rayon * cos(site) * cos(azimut)
Y = rayon * cos(site) * sin(azimut)
Z = rayon * sin(site)

Un schéma étant souvent plus parlant qu'un long discours mathématique sur la trigonométrie, voici la représentation d'un point dans le repère cartésien utilisé par Java 3D en fonction de ses coordonnées sphériques (rayon, angle azimut, angle site) :

Je tiens à rassurer les allergiques à la trigonométrie sur le fait que tous les objets 3D ne se décrivent pas en coordonnées sphériques. Cependant, on comprendra aisément en regardant le listing du programme LineStripArray3D.java que ce système de coordonnées est particulièrement adapté à notre exemple.

L'objet de type LineStripArray est créé par les lignes suivantes :

LineStripArray lineStripArray =
new LineStripArray(nbBandesVert*nbPtsParBandes,
LineStripArray.COORDINATES,
stripVertexCount);

Le paramètre vertexFormat du constructeur de LineStripArray est égal à LineStripArray.COORDINATES uniquement, car nous allons dessiner la sphère en blanc uniquement sans utiliser d'autres couleurs.

Le tableau stripVertexCount est construit de façon simplifiée en attribuant le même nombre de points pour chaque ligne :

int[] stripVertexCount = new int[nbBandesVert];
for (int i = 0 ; i < nbBandesVert ; i++) {
stripVertexCount[i] = nbPtsParBandes;
}

Pour terminer, nous mettons à jour les coordonnées des points de l'objet LineStripArray ainsi que la géométrie de l'objet SphereWithLines :

lineStripArray.setCoordinates(0, points);
this.setGeometry(lineStripArray);

Le fichier LineStripArray3D.java présente le code source complet de cet exemple. Nous en avons extrait le listing de la classe SphereWithLines qui prend en charge la construction d'un objet LineStripArray :

/**
* Objet geometrique qui represente une sphere constituee de lignes et
* construite grace a l'objet LineStripArray
*/
class SphereWithLines extends Shape3D {

/**
* Constructeur
*/
public SphereWithLines() {
// conversion degres -> radians
final float DEG_RAD = (float)Math.PI/180;

int nbBandesVert = 36; // nombre de lignes (bandes)
int nbPtsParBandes = 19; // nombre de points par ligne

// Tableau definissant le nombre de points pour chaque bande :
// pour simplifier, toutes les bandes ont le meme nombre de points
int[] stripVertexCount = new int[nbBandesVert];
for (int i = 0 ; i < nbBandesVert ; i++) {
stripVertexCount[i] = nbPtsParBandes;
}

// Construction de tous les points constituant l'objet LineStripArray
// et par consequent la sphere. Pour plus de simplicite, on utilise
// des coordonnees spheriques
Point3f[] points = new Point3f[nbBandesVert*nbPtsParBandes];
for (int iVertBde = 0 ; iVertBde < nbBandesVert ; iVertBde++) {
float azim = iVertBde*(360f/nbBandesVert)*DEG_RAD;

for (int iPtsBde = 0 ; iPtsBde < nbPtsParBandes ; iPtsBde++) {
float site = (-90 + iPtsBde*(180f/(nbPtsParBandes-1)))*DEG_RAD;

points[iPtsBde + iVertBde*nbPtsParBandes] =
new Point3f(0.6f*(float)(Math.cos(site)*Math.cos(azim)),
0.6f*(float)(Math.sin(site)),
0.6f*(float)(Math.cos(site)*Math.sin(azim)));
} // fin for (int iPtsBde = 0 ; iPtsBde < nbPtsParBandes ; iPtsBde++)
} // fin for (int iVertBde = 0 ; iVertBde < nbBandesVert ; iVertBde++)

// Construction de l'objet geometrique LineStripArray constitue de 36
// lignes de 19 points chacune
LineStripArray lineStripArray =
new LineStripArray(nbBandesVert*nbPtsParBandes,
LineStripArray.COORDINATES,
stripVertexCount);

// On rentre le tableau des points dans l'objet lineStripArray
lineStripArray.setCoordinates(0, points);

// Mise a jour de la geometrie de l'objet SphereWithLines
this.setGeometry(lineStripArray);

} // fin constructeur
} // fin class SphereWithLines extends Shape3D

Exécutez l'applet LineStripArray3D.html pour voir le résultat.

III-F - La classe TriangleStripArray

La classe TriangleStripArray est sans doute celle qui est la plus utilisée pour construire des objets complexes. Contrairement à LineStripArray que nous venons d'étudier, elle permet notamment de rendre les facettes des objets 3D « solides », c'est-à-dire de les remplir avec une couleur par exemple au lieu de ne visualiser que leur contour.
Cette classe permet de construire des objets constitués par un ensemble de triangles, eux-mêmes organisés en plusieurs groupes formant des bandes.
Dans ce paragraphe, nous allons expliquer le fonctionnement de base de cette classe en utilisant comme exemple de démonstration une sphère multicolore.

III-F-1 - Principal constructeur

public TriangleStripArray(int vertexCount, int vertexFormat, int[] stripVertexCounts)

vertexCount indique le nombre de points qui vont constituer l'ensemble des triangles.

vertexFormat permet de définir les propriétés associées aux points, les valeurs possibles de ce paramètre sont les constantes de la classe GeometryArray dont TriangleStripArray hérite.

stripVertexCount est un tableau qui spécifie le nombre de points pour chaque bande constituant l'objet TriangleStripArray.

Ce constructeur définit un objet vide, mais dont on a déjà décidé du nombre de points constituant l'ensemble des triangles et de leur format. Les coordonnées de ces points sont définies à l'aide de la méthode setCoordinates() qui est héritée de GeometryArray.

III-F-2 - Principales méthodes

public void setCoordinates(int index, Point3f[] coordinates)

Mets à jour les coordonnées des points de l'objet.
index représente l'indice désignant le numéro du point à partir duquel les coordonnées vont être mises à jour par les valeurs provenant du tableau coordinates.

public void setColors (int index, Color3f[] colors)

Mets à jour les couleurs des points de l'objet.
index représente l'indice désignant le numéro du point à partir duquel les couleurs vont être mises à jour par les valeurs provenant du tableau colors.

III-F-3 - Exemple

Le fichier TriangleStripArray3D.java est un exemple d'utilisation de la classe TriangleStripArray. Il s'agit de représenter une sphère constituée de triangles ou facettes et qui est en rotation autour de l'axe vertical Y du repère 3D. Cette sphère sera formée de plusieurs bandes contiguës de triangles colorés et, pour simplifier notre exemple, chaque bande possèdera le même nombre de points.
Les bandes de triangles étant contiguës, chaque point de notre sphère sera donc commun à deux bandes et par conséquent utilisé deux fois.

Nous verrons dans le paragraphe sur les objets à géométrie indicée comment optimiser cette réutilisation de points afin de gagner de la place mémoire.
L'idée consiste d'abord à créer une classe SphereWithTriangles qui permet de construire un objet géométrique de type TriangleStripArray, il est indispensable que cette classe étende la classe Shape3D afin de pouvoir l'ajouter à la scène 3D de notre application :

class SphereWithTriangles extends Shape3D

Nous définissons ensuite le nombre de bandes ainsi que le nombre de points par bande :

int nbBandesVert = 36; // nombre de bandes
int nbPtsParBandes = 19*2; // nombre de points par bande

Après avoir défini les coordonnées des points et leur couleur, l'objet de type TriangleStripArray est créé par les lignes suivantes :

// Construction de l'objet geometrique TriangleStripArray constitue de
// 36 bandes de 19*2 points chacune
TriangleStripArray triangleStripArray =
new TriangleStripArray(nbBandesVert*nbPtsParBandes,
TriangleStripArray.COORDINATES |
TriangleStripArray.COLOR_3,
stripVertexCount);

Le paramètre vertexFormat du constructeur de TriangleStripArray est égal à la combinaison TriangleStripArray.COORDINATES | TriangleStripArray.COLOR_3 afin que les facettes (triangles) de notre sphère puissent être colorées.

Le tableau stripVertexCount est construit de façon simplifiée en attribuant le même nombre de points pour chaque bande de triangles :

// Tableau definissant le nombre de points pour chaque bande :
// pour simplifier, toutes les bandes ont le meme nombre de points
int[] stripVertexCount = new int[nbBandesVert];
for (int i = 0 ; i < nbBandesVert ; i++) {
stripVertexCount[i] = nbPtsParBandes;
}

Pour terminer, nous mettons à jour les coordonnées et les couleurs des points de l'objet TriangleStripArray ainsi que la géométrie de l'objet SphereWithTriangles :

// On rentre le tableau des points et des couleurs dans l'objet
// TriangleStripArray
triangleStripArray.setCoordinates(0, points);
triangleStripArray.setColors(0, colors);

// Mise a jour de la geometrie de l'objet SphereWithTriangles
this.setGeometry(triangleStripArray);

Le fichier TriangleStripArray3D.java présente le code source complet de cet exemple. Nous en avons extrait le listing de la classe SphereWithTriangles qui prend en charge la construction d'un objet TriangleStripArray :

/**
* Objet geometrique qui represente une sphere constituee de triangles
* (facettes) et construite grace a l'objet TriangleStripArray
*/
class SphereWithTriangles extends Shape3D {

/**
* Constructeur
*/
public SphereWithTriangles() {
// conversion degres -> radians
final float DEG_RAD = (float)Math.PI/180;

int nbBandesVert = 36; // nombre de bandes
int nbPtsParBandes = 19*2; // nombre de points par bande

// Variables definissant les angles en azimut et site pour le systeme
// de coordonnees spheriques
float azim, site;

// Tableau definissant le nombre de points pour chaque bande :
// pour simplifier, toutes les bandes ont le meme nombre de points
int[] stripVertexCount = new int[nbBandesVert];
for (int i = 0 ; i < nbBandesVert ; i++) {
stripVertexCount[i] = nbPtsParBandes;
}

// Allocation des tableaux permettant de stocker en memoire les
// coordonnees et les couleurs de chaque point constituant notre
// sphere
Point3f[] points = new Point3f[nbBandesVert*nbPtsParBandes];
Color3f[] colors = new Color3f[nbBandesVert*nbPtsParBandes];

// Attribution de la couleur pour chaque bande verticale en fonction
// de son indice iVertBde
// On utilise 9 couleurs predefinies dans Java 2. Ainsi comme nous
// avons 36 bandes, une couleur sera attribuee a 4 bandes differentes
Color couleurBande = null;
for (int iVertBde = 0 ; iVertBde < nbBandesVert ; iVertBde++) {
switch(iVertBde) {
case 0:
case 9:
case 18:
case 27:
couleurBande = Color.blue;
break;

case 1:
case 10:
case 19:
case 28:
couleurBande = Color.cyan;
break;

case 2:
case 11:
case 20:
case 29:
couleurBande = Color.green;
break;

case 3:
case 12:
case 21:
case 30:
couleurBande = Color.magenta;
break;

case 4:
case 13:
case 22:
case 31:
couleurBande = Color.orange;
break;

case 5:
case 14:
case 23:
case 32:
couleurBande = Color.pink;
break;

case 6:
case 15:
case 24:
case 33:
couleurBande = Color.red;
break;

case 7:
case 16:
case 25:
case 34:
couleurBande = Color.white;
break;

case 8:
case 17:
case 26:
case 35:
couleurBande = Color.yellow;
break;
} // fin switch(iVertBde)

// Construction de tous les points et de leur couleur associee
// constituant l'objet TriangleStripArray et par consequent la sphere.
// Pour plus de simplicite, on utilise des coordonnees spheriques
for (int iPtsBde = 0 ; iPtsBde < nbPtsParBandes/2 ; iPtsBde++) {
site = (90 - iPtsBde*(180f/(nbPtsParBandes/2-1)))*DEG_RAD;
azim = iVertBde*(360f/nbBandesVert)*DEG_RAD;

points[2*iPtsBde + iVertBde*nbPtsParBandes] =
new Point3f(0.6f*(float)(Math.cos(site)*Math.cos(azim)),
0.6f*(float)(Math.sin(site)),
0.6f*(float)(Math.cos(site)*Math.sin(azim)));

colors[2*iPtsBde + iVertBde*nbPtsParBandes] = new Color3f(couleurBande);

if (iVertBde < nbBandesVert-1) {
azim = (iVertBde+1)*(360f/nbBandesVert)*DEG_RAD;
}
else {
azim = 0f;
}

points[2*iPtsBde+1 + iVertBde*nbPtsParBandes] =
new Point3f(0.6f*(float)(Math.cos(site)*Math.cos(azim)),
0.6f*(float)(Math.sin(site)),
0.6f*(float)(Math.cos(site)*Math.sin(azim)));

colors[2*iPtsBde+1 + iVertBde*nbPtsParBandes] = new Color3f(couleurBande);
} // fin for (int iPtsBde = 0 ; iPtsBde < nbPtsParBandes ; iPtsBde++)
} // fin for (int iVertBde = 0 ; iVertBde < nbBandesVert ; iVertBde++)

// Construction de l'objet geometrique TriangleStripArray constitue de
// 36 bandes de 19*2 points chacune
TriangleStripArray triangleStripArray =
new TriangleStripArray(nbBandesVert*nbPtsParBandes,
TriangleStripArray.COORDINATES |
TriangleStripArray.COLOR_3,
stripVertexCount);

// On rentre le tableau des points et des couleurs dans l'objet
// TriangleStripArray
triangleStripArray.setCoordinates(0, points);
triangleStripArray.setColors(0, colors);

// Mise a jour de la geometrie de l'objet SphereWithTriangles
this.setGeometry(triangleStripArray);
} // fin constructeur
} // fin class SphereWithTriangles extends Shape3D

Exécutez l'applet TriangleStripArray3D.html pour voir le résultat.

III-G - La classe TriangleFanArray

Cette classe un peu particulière permet de construire des objets 3D constitués par un ensemble de facettes ou triangles, eux-mêmes organisés en plusieurs groupes formant des éventails (fan en anglais).
Dans ce paragraphe, nous allons expliquer le fonctionnement de base de cette classe en utilisant comme exemple de démonstration un cône multicolore.

III-G-1 - Principal constructeur

public TriangleFanArray(int vertexCount, int vertexFormat, int[] stripVertexCounts)

vertexCount indique le nombre de points qui vont constituer l'ensemble des triangles.

vertexFormat permet de définir les propriétés associées aux points, les valeurs possibles de ce paramètre sont les constantes de la classe GeometryArray dont TriangleFanArray hérite.

stripVertexCount est un tableau qui spécifie le nombre de points pour chaque éventail constituant l'objet TriangleFanArray.

Ce constructeur définit un objet vide, mais dont on a déjà décidé du nombre de points constituant l'ensemble des triangles et de leur format. Les coordonnées de ces points sont définies à l'aide de la méthode setCoordinates() qui est héritée de GeometryArray.

III-G-2 - Principales méthodes

public void setCoordinates (int index, Point3f[] coordinates)

Mets à jour les coordonnées des points de l'objet.
index représente l'indice désignant le numéro du point à partir duquel les coordonnées vont être mises à jour par les valeurs provenant du tableau coordinates.

public void setColors (int index, Color3f[] colors)

Mets à jour les couleurs des points de l'objet.
index représente l'indice désignant le numéro du point à partir duquel les couleurs vont être mises à jour par les valeurs provenant du tableau colors.

III-G-3 - Exemple

Le fichier TriangleFanArray3D.java est un exemple d'utilisation de la classe TriangleFanArray. Il s'agit de représenter un cône constitué de triangles ou facettes et qui est en rotation autour de l'axe vertical Y du repère 3D. Ce cône sera formé de deux éventails de plusieurs triangles contigus. Le premier éventail constitue le corps du cône et le second la base. Pour simplifier notre exemple, les deux éventails possèderont le même nombre de points. Chaque point appartenant au corps du cône sera affecté d'une couleur différente, ce qui donnera un effet de dégradé dû à l'interpolation des couleurs. En revanche, les points de la base du cône seront affectés d'une couleur blanche uniforme. Tout comme notre exemple TriangleStripArray3D.java, certains points sont réutilisés deux fois.

Nous verrons dans le paragraphe sur les objets à géométrie indicée comment optimiser cette réutilisation de points afin de gagner de la place mémoire.
L'idée consiste d'abord à créer une classe ConeWithTriangles qui permet de construire un objet géométrique de type TriangleFanArray, il est indispensable que cette classe étende la classe Shape3D afin de pouvoir l'ajouter à la scène 3D de notre application :

class ConeWithTriangles extends Shape3D

Ensuite, nous définissons le nombre de points constituant chacune des parties de notre objet 3D :

int nbPtsCorps = 9; // nombre de points du corps du cone
int nbPtsBase = 9; // nombre de points de la base du cone
int nbEventails = 2; // nombre d'eventails (corps + base)

Après avoir défini les coordonnées de tous les points et leur couleur, l'objet de type TriangleFanArray est créé par les lignes suivantes :

// Construction de l'objet geometrique TriangleFanArray constitue de
// 2 eventails (corps + base)
TriangleFanArray triangleFanArray = new TriangleFanArray(nbPtsCorps+nbPtsBase,
TriangleFanArray.COORDINATES |
TriangleFanArray.COLOR_3,
stripVertexCount);

Le paramètre vertexFormat du constructeur de TriangleStripArray est égal à la combinaison TriangleStripArray.COORDINATES | TriangleStripArray.COLOR_3 afin que les facettes (triangles) de notre cône puissent être colorées.

Le tableau stripVertexCount est construit de façon à attribuer le nombre correct de points pour les deux parties du cône : le corps et la base :

// Tableau definissant le nombre de points pour chaque eventail
int[] stripVertexCount = new int[nbEventails];
stripVertexCount[0] = nbPtsCorps;
stripVertexCount[1] = nbPtsBase;

Pour terminer, nous mettons à jour les coordonnées et les couleurs des points de l'objet TriangleFanArray ainsi que la géométrie de l'objet ConeWithTriangles :

// On rentre le tableau des points dans l'objet TriangleFanArray
triangleFanArray.setCoordinates(0, points);
triangleFanArray.setColors(0, colors);

// Mise a jour de la geometrie de l'objet ConeWithTriangles
this.setGeometry(triangleFanArray);

Le fichier TriangleFanArray3D.java présente le code source complet de cet exemple. Nous en avons extrait le listing de la classe ConeWithTriangles qui prend en charge la construction d'un objet TriangleFanArray :

/**
* Objet geometrique qui represente un cone constitue de triangles
* (facettes) et construit grace a l'objet TriangleFanArray.
* Ce cone est ferme par une base en forme de disque plein.
*/
class ConeWithTriangles extends Shape3D {

/**
* Constructeur
*/
public ConeWithTriangles() {
// conversion degres -> radians
final float DEG_RAD = (float)Math.PI/180;

int nbPtsCorps = 9; // nombre de points du corps du cone
int nbPtsBase = 9; // nombre de points de la base du cone
int nbEventails = 2; // nombre d'eventails (corps + base)

// Tableau definissant le nombre de points pour chaque eventail
int[] stripVertexCount = new int[nbEventails];
stripVertexCount[0] = nbPtsCorps;
stripVertexCount[1] = nbPtsBase;

// Allocation des tableaux permettant de stocker en memoire les
// coordonnees de chaque point constituant notre cone 3D ainsi que
// des couleurs associees a ces points
Point3f[] points = new Point3f[nbPtsCorps+nbPtsBase];
Color3f[] colors = new Color3f[nbPtsCorps+nbPtsBase];

// Determination des coordonnees des points constituant notre cone 3D
// ainsi que de la couleur associee a chacun de ces points
// Corps :
points[0] = new Point3f(0f, 0.6f, 0f); // sommet du cone
colors[0] = new Color3f(Color.blue);
for (int iPt = 1 ; iPt < nbPtsCorps ; iPt++) {
float angle = ((iPt-1)*360f/(nbPtsCorps-2)) * DEG_RAD;

points[iPt] =
new Point3f(0.3f*(float)Math.cos(angle),
-0.6f,
0.3f*(float)Math.sin(angle));

switch(iPt) {
case 1:
colors[iPt] = new Color3f(Color.cyan);
break;

case 2:
colors[iPt] = new Color3f(Color.green);
break;

case 3:
colors[iPt] = new Color3f(Color.magenta);
break;

case 4:
colors[iPt] = new Color3f(Color.orange);
break;

case 5:
colors[iPt] = new Color3f(Color.pink);
break;

case 6:
colors[iPt] = new Color3f(Color.red);
break;

case 7:
colors[iPt] = new Color3f(Color.white);
break;

case 8:
colors[iPt] = new Color3f(Color.yellow);
break;
} // fin switch(iPt)
} // fin for (iPt = 1 ; iPt < nbPtsCorps ; iPt++)

// Base :
// On choisit une couleur blanche unique pour tous les points de la base
points[nbPtsCorps] = new Point3f(0f, -0.6f, 0f); // centre de la base
colors[nbPtsCorps] = new Color3f(Color.white);
for (int iPt = 1 ; iPt < nbPtsBase ; iPt++) {
float angle = ((iPt-1)*360f/(nbPtsBase-2)) * DEG_RAD;

// ATTENTION : on met un signe - devant l'argument "angle" des
// fonctions sin et cos, car il faut que les sommets de la base du
// cone soient enumeres dans le sens direct trigonometrique
// ( = sens inverse des aiguilles d'une montre) pour que les
// facettes (blanches) soient visibles.
points[nbPtsCorps+iPt] =
new Point3f(0.3f*(float)Math.cos(-angle),
-0.6f,
0.3f*(float)Math.sin(-angle));

colors[nbPtsCorps+iPt] = new Color3f(Color.white);
} // fin for (int iPt = 1 ; iPt < nbPtsBase ; iPt++)

// Construction de l'objet geometrique TriangleFanArray constitue de
// 2 eventails (corps + base)
TriangleFanArray triangleFanArray =
new TriangleFanArray(nbPtsCorps+nbPtsBase,
TriangleFanArray.COORDINATES |
TriangleFanArray.COLOR_3,
stripVertexCount);

// On rentre le tableau des points dans l'objet TriangleFanArray
triangleFanArray.setCoordinates(0, points);
triangleFanArray.setColors(0, colors);

// Mise a jour de la geometrie de l'objet ConeWithTriangles
this.setGeometry(triangleFanArray);
} // fin constructeur
} // fin class ConeWithTriangles extends Shape3D

Exécutez l'applet TriangleFanArray3D.html pour voir le résultat.

IV - Les objets à géométrie indicée

Comme nous venons de le voir dans les paragraphes consacrés à la géométrie de type TriangleStripArray ou TriangleFanArray par exemple, certains sommets de notre objet 3D sont réutilisés plusieurs fois, car ils peuvent être communs à plusieurs facettes, bandes ou éventails.
Les constructions géométriques indicées permettent d'optimiser la mémoire lorsque des sommets sont utilisés plusieurs fois pour un objet 3D. Mais ce gain de mémoire a un prix, car tout objet à géométrie indicée sollicite davantage le mécanisme de rendu 3D et cela pourra induire par conséquent une baisse de performances sur les petites configurations.

Nous ne conseillons d'utiliser les objets à géométrie indicée que lorsque le critère sur les performances du rendu 3D n'est pas un critère déterminant par rapport à celui de l'optimisation de la quantité de mémoire utilisée.

II est important de savoir que tous les objets géométriques étudiés dans ce chapitre possèdent une construction indicée qui leur est associée :

Géométrie simple

Géométrie indicée

PointArray

IndexedPointArray

LineArray

IndexedLineArray

TriangleArray

IndexedTriangleArray

QuadArray

IndexedQuadArray

LineStripArray

IndexedLineStripArray

TriangleStripArray

IndexedTriangleStripArray

TriangleFanArray

IndexedTriangleFanArray

Tous les objets à base de géométrie indicée dérivent de la classe IndexedGeometryArray. Dans ce paragraphe, nous allons étudier dans un premier temps un exemple dans lequel nous représenterons une pyramide multicolore en utilisant la classe IndexedTriangleFanArray. Les constructions géométriques indicées sont plus difficiles à appréhender que les constructions géométriques simples. Nous verrons donc, dans un deuxième temps, que la classe GeometryInfo permet de simplifier quelque peu le problème.

IV-A - Construction de la pyramide multicolore à l'aide de la classe IndexedTriangleFanArray

Tout comme un objet de type TriangleFanArray, l'instance de la classe IndexedTriangleFanArray a besoin d'un tableau avec les coordonnées des sommets de la pyramide.
Cependant, un objet de type IndexedTriangleFanArray aura besoin en plus d'un deuxième tableau contenant les indices pointant sur un numéro de sommet contenu dans le premier tableau. Un sommet pouvant alors être utilisé plusieurs fois grâce à ce système d'indexage.
Les choses sont strictement identiques en ce qui concerne les couleurs associées à chaque sommet de la pyramide.

Contrairement aux exemples précédents, il ne faut créer que des points distincts les uns des autres pour ce cas précis de géométrie indicée. C'est le système d'indexage qui permettra de réutiliser plusieurs fois le même point.

Le principal constructeur de la classe IndexedTriangleFanArray se présente de la façon suivante :

public IndexedTriangleFanArray(int vertexCount, int vertexFormat, int indexCount, int[] stripIndexCounts)

vertexCount indique le nombre de points (éventuellement réutilisables) qui vont constituer l'ensemble des triangles.

vertexFormat permet de définir les propriétés associées aux points, les valeurs possibles de ce paramètre sont les constantes de la classe GeometryArray dont IndexedTriangleFanArray hérite.

indexCount indique le nombre total d'indices pointant sur les sommets.

stripIndexCount est un tableau qui spécifie le nombre d'indices pour chaque éventail constituant l'objet IndexedTriangleFanArray.

Ce constructeur définit un objet vide, mais dont on a déjà décidé du nombre de points et d'indices constituant l'ensemble des triangles et de leur format. Les coordonnées de ces points sont définies à l'aide de la méthode setCoordinates() qui est héritée de GeometryArray. Les indices de ces points sont définis à l'aide de la méthode setCoordinateIndices() qui est héritée de IndexedGeometryArray.

Dans l'exemple qui nous préoccupe (fichier IndexedTriangleFanArray3D.java), l'objet IndexedTriangleFanArray possède deux éventails : le premier pour le corps de la pyramide et le second pour sa base :

On veillera toujours bien sûr à énumérer les sommets de chaque éventail dans le sens direct (sens inverse des aiguilles d'une montre) pour que toutes les facettes soient visibles.
On commence dans un premier temps par construire tous les sommets distincts (corps + base) de la pyramide ainsi que leur couleur associée.

// Creation des 5 points constituant la pyramide (corps + base)
Point3f[] points = new Point3f[5];
points[0] = new Point3f( 0f, 0.8f, 0f); // sommet
points[1] = new Point3f(-0.4f, 0.1f, -0.4f); // base 1
points[2] = new Point3f(-0.4f, 0.1f, 0.4f); // base 2
points[3] = new Point3f( 0.4f, 0.1f, 0.4f); // base 3
points[4] = new Point3f( 0.4f, 0.1f, -0.4f); // base 4

// Creation des couleurs associees a chaque sommet de la pyramide
Color3f[] colors = new Color3f[5];
colors[0] = new Color3f(Color.red);
colors[1] = new Color3f(Color.cyan);
colors[2] = new Color3f(Color.yellow);
colors[3] = new Color3f(Color.green);
colors[4] = new Color3f(Color.white);

On construit ensuite le tableau des indices pointant sur les numéros des sommets (il y a 6 indices pour le corps et 4 pour la base, soit un total de 10 indices pour la pyramide entière) :

// Construction du tableau contenant les indices pointant sur la table
// points[] des sommets constituant la pyramide
int[] indicesPoints = new int[6+4];

// Indices des points du premier eventail : corps
// ATTENTION : enumeration dans le sens direct (inverse des aiguilles
// d'une montre)
indicesPoints[0] = 0;
indicesPoints[1] = 1;
indicesPoints[2] = 2;
indicesPoints[3] = 3;
indicesPoints[4] = 4;
indicesPoints[5] = 1;

// Indices des points du second eventail : base
// ATTENTION : enumeration dans le sens direct (inverse des aiguilles
// d'une montre)
indicesPoints[6] = 1;
indicesPoints[7] = 4;
indicesPoints[8] = 3;
indicesPoints[9] = 2;

On fait de même pour les indices relatifs aux couleurs des sommets. On fait en sorte que la base de la pyramide soit d'une couleur blanche uniforme afin qu'elle soit bien visible :

// Construction du tableau contenant les indices pointant sur la table
// colors[] des couleurs des faces et de la base de la pyramide
int[] indicesColors = new int[6+4];

// Indices des couleurs du premier eventail : corps
// Les faces du corps de la pyramide auront une couleur resultant de
// l'interpolation de la couleur de chaque sommet
indicesColors[0] = 0;
indicesColors[1] = 1;
indicesColors[2] = 2;
indicesColors[3] = 3;
indicesColors[4] = 4;
indicesColors[5] = 1;

// Indices des couleurs du second eventail : base
// (couleur blanche uniforme)
indicesColors[6] = 4;
indicesColors[7] = 4;
indicesColors[8] = 4;
indicesColors[9] = 4;

Ensuite, après avoir défini les coordonnées, les couleurs et les indices de tous les points, l'objet de type IndexedTriangleFanArray est créé par les lignes suivantes :

// Construction de l'objet geometrique IndexedTriangleFanArray constitue
// de 5 points et 10 indices
IndexedTriangleFanArray indexedTriangleFanArray =
new IndexedTriangleFanArray(5,
IndexedTriangleFanArray.COORDINATES |
IndexedTriangleFanArray.COLOR_3,
6+4,
stripIndexCounts);

Le paramètre vertexFormat du constructeur de IndexedTriangleFanArray est égal à la combinaison IndexedTriangleFanArray.COORDINATES | IndexedTriangleFanArray.COLOR_3 afin que les facettes (triangles) de notre pyramide puissent être colorées.

Le tableau stripIndexCounts est construit de façon à attribuer le nombre correct d'indices pour les deux parties (éventails) de la pyramide : le corps et la base :

// Construction du tableau contenant le nombre d'indices par eventail :
// 6 indices pour le premier eventail (corps) et 4 indices pour le
// second (base)
int[] stripIndexCounts = new int[] {6, 4};

Pour terminer, nous mettons à jour les coordonnées, les couleurs ainsi que les indices des points de l'objet IndexedTriangleFanArray :

// Tableau des points, des couleurs et de leurs indices respectifs
indexedTriangleFanArray.setCoordinates(0, points);
indexedTriangleFanArray.setCoordinateIndices(0, indicesPoints);
indexedTriangleFanArray.setColors(0, colors);
indexedTriangleFanArray.setColorIndices(0, indicesColors);

Le fichier IndexedTriangleFanArray3D.java présente le code source complet de cet exemple. Nous en avons extrait le listing de la classe PyramideIndicee qui prend en charge la construction d'un objet IndexedTriangleFanArray :

/**
* Objet a geometrie indicee qui represente une pyramide a base carree
*/
class PyramideIndicee extends Shape3D {

/**
* Constructeur
*/
public PyramideIndicee() {
// Creation des 5 points constituant la pyramide (corps + base)
Point3f[] points = new Point3f[5];
points[0] = new Point3f( 0f, 0.8f, 0f); // sommet
points[1] = new Point3f(-0.4f, 0.1f, -0.4f); // base 1
points[2] = new Point3f(-0.4f, 0.1f, 0.4f); // base 2
points[3] = new Point3f( 0.4f, 0.1f, 0.4f); // base 3
points[4] = new Point3f( 0.4f, 0.1f, -0.4f); // base 4

// Creation des couleurs associees a chaque sommet de la pyramide
Color3f[] colors = new Color3f[5];
colors[0] = new Color3f(Color.red);
colors[1] = new Color3f(Color.cyan);
colors[2] = new Color3f(Color.yellow);
colors[3] = new Color3f(Color.green);
colors[4] = new Color3f(Color.white);

// Construction du tableau contenant les indices pointant sur la table
// points[] des sommets constituant la pyramide
int[] indicesPoints = new int[6+4];

// Indices des points du premier eventail : corps
// ATTENTION : enumeration dans le sens direct (inverse des aiguilles
// d'une montre)
indicesPoints[0] = 0;
indicesPoints[1] = 1;
indicesPoints[2] = 2;
indicesPoints[3] = 3;
indicesPoints[4] = 4;
indicesPoints[5] = 1;

// Indices des points du second eventail : base
// ATTENTION : enumeration dans le sens direct (inverse des aiguilles
// d'une montre)
indicesPoints[6] = 1;
indicesPoints[7] = 4;
indicesPoints[8] = 3;
indicesPoints[9] = 2;

// Construction du tableau contenant les indices pointant sur la table
// colors[] des couleurs des faces et de la base de la pyramide
int[] indicesColors = new int[6+4];

// Indices des couleurs du premier eventail : corps
// Les faces du corps de la pyramide auront une couleur resultant de
// l'interpolation de la couleur de chaque sommet
indicesColors[0] = 0;
indicesColors[1] = 1;
indicesColors[2] = 2;
indicesColors[3] = 3;
indicesColors[4] = 4;
indicesColors[5] = 1;

// Indices des couleurs du second eventail : base
// (couleur blanche uniforme)
indicesColors[6] = 4;
indicesColors[7] = 4;
indicesColors[8] = 4;
indicesColors[9] = 4;

// Construction du tableau contenant le nombre d'indices par eventail :
// 6 indices pour le premier eventail (corps) et 4 indices pour le
// second (base)
int[] stripIndexCounts = new int[] {6, 4};

// Construction de l'objet geometrique IndexedTriangleFanArray constitue
// de 5 points et 10 indices
IndexedTriangleFanArray indexedTriangleFanArray =
new IndexedTriangleFanArray(5,
IndexedTriangleFanArray.COORDINATES |
IndexedTriangleFanArray.COLOR_3,
6+4,
stripIndexCounts);

// Tableau des points, des couleurs et de leurs indices respectifs
indexedTriangleFanArray.setCoordinates(0, points);
indexedTriangleFanArray.setCoordinateIndices(0, indicesPoints);
indexedTriangleFanArray.setColors(0, colors);
indexedTriangleFanArray.setColorIndices(0, indicesColors);

this.setGeometry(indexedTriangleFanArray);
} // fin constructeur
} // fin class PyramideIndicee extends Shape3D

Exécutez l'applet IndexedTriangleFanArray3D.html pour voir le résultat.

Parmi les exemples de codes sources associés à ce chapitre, nous avons adapté le code source TriangleStripArray3D.java relatif à la construction d'une sphère multicolore afin de créer le même objet, mais en utilisant le concept de géométrie indicée cette fois. Le code source de cette adaptation se trouve dans le fichier IndexedTriangleStripArray3D.java.

IV-B - Construction de la pyramide multicolore à l'aide de la classe GeometryInfo

Comme nous venons de le voir, la constitution du tableau des indices pour les coordonnées et les couleurs n'est pas une chose aisée et oblige l'écriture de nombreuses lignes de code. Il existe une classe utilitaire nommée GeometryInfo qui permet entre autres de construire des objets à géométrie indicée ou pas.

IV-B-1 - Principal constructeur

public GeometryInfo (int primitive)

Le paramètre primitive peut prendre pour valeur un des champs statiques de la classe GeometryInfo, ce qui va déterminer le type de géométrie à utiliser pour construire l'objet 3D.

Valeurs possibles du paramètre primitive

Géométrie équivalente utilisée

Description

POLYGON_ARRAY

Pas d'équivalence

Permetsde construire un objet géométrique à base de polygones nonnécessairement coplanaires et possédant éventuellement des trous

QUAD_ARRAY

QuadArray

Les points sont regroupés par quatre pour former des quadrilatères indépendants

TRIANGLE_ARRAY

TriangleArray

Les points sont regroupés par trois pour former des triangles indépendants

TRIANGLE_FAN_ARRAY

TriangleFanArray

Les points sont regroupés en triangles pour former des groupes d'éventails

TRIANGLE_STRIP_ARRAY

TriangleStripArray

Les points sont regroupés en triangles pour former des bandes

IV-B-2 - Principales méthodes

public void setCoordinates(Point3f[] coordinates)

Mets à jour les coordonnées des points de l'objet.

public void setColors(Color3f[] colors)

Mets à jour les couleurs des points de l'objet.

public void setStripCounts(int[] stripCounts)

Si l'instance de GeometryInfo a été créée avec le paramètre TRIANGLE_FAN_ARRAY, la méthode setStripCounts() permet de définir le nombre de points constituant chaque éventail de l'objet 3D.
Si l'instance de GeometryInfo a été créée avec le paramètre TRIANGLE_STRIP_ARRAY, la méthode setStripCounts() permet de définir le nombre de points constituant chaque bande de triangles de l'objet 3D.
Pour les autres géométries que ne sont ni à base de bandes ni d'éventails, l'appel à cette méthode n'est pas obligatoire.
Pour les géométries indicées, cette méthode agit de la même façon que la méthode setStripIndexCounts() et pour les géométries non indicées, cette méthode agit de la même façon que la méthode setStripVertexCounts().

public GeometryArray getGeometryArray()

Crée et retourne un objet à géométrie non indicée. C'est cet objet que l'on pourra attacher à une instance de la classe Shape3D.

public IndexedGeometryArray getIndexedGeometryArray()

Crée et retourne un objet à géométrie indicée. C'est cet objet que l'on pourra attacher à une instance de la classe Shape3D.

IV-B-3 - Exemple

Nous allons commencer par créer la liste des points et de leur couleur associée constituant notre pyramide multicolore (fichier exemple : GeometryInfo3D.java) :

// Creation des points constituant la pyramide (corps + base) sans
// oublier les points qui vont etre reutilises
Point3f[] points = new Point3f[10];
points[0] = new Point3f( 0f, 0.8f, 0f); // sommet
points[1] = new Point3f(-0.4f, 0.1f, -0.4f); // base 1
points[2] = new Point3f(-0.4f, 0.1f, 0.4f); // base 2
points[3] = new Point3f( 0.4f, 0.1f, 0.4f); // base 3
points[4] = new Point3f( 0.4f, 0.1f, -0.4f); // base 4
points[5] = points[1]; // base 1
points[6] = points[1]; // base 1
points[7] = points[4]; // base 4
points[8] = points[3]; // base 3
points[9] = points[2]; // base 2

// Creation des couleurs associees a chaque sommet de la pyramide
Color3f[] colors = new Color3f[10];
colors[0] = new Color3f(Color.red);
colors[1] = new Color3f(Color.cyan);
colors[2] = new Color3f(Color.yellow);
colors[3] = new Color3f(Color.green);
colors[4] = new Color3f(Color.white);
colors[5] = colors[1];
colors[6] = colors[4];
colors[7] = colors[4];
colors[8] = colors[4];
colors[9] = colors[4];

Dans ce cas précis de géométrie indicée et contrairement à notre précédent exemple, il faut bien veiller à créer tous les points en comptant également ceux qui vont être éventuellement réutilisés.

Instanciation de notre objet de type GeometryInfo :

// Construction de l'objet de type GeometryInfo avec une geometrie
// a base de TriangleFanArray
GeometryInfo geometryInfo = new GeometryInfo(GeometryInfo.TRIANGLE_FAN_ARRAY);

Mise à jour des points et des couleurs de notre objet GeometryInfo :

// On met a jour les tableaux des points et des couleurs de l'objet geometryInfo
geometryInfo.setCoordinates(points);
geometryInfo.setColors(colors);

On définit le nombre de points constituant chaque éventail de notre pyramide :

// Construction du tableau contenant le nombre de points par eventail :
// 6 points pour le premier eventail (corps) et 4 points pour le second (base)
geometryInfo.setStripCounts(new int[] {6, 4});

Enfin, on récupère un objet de type IndexedGeometryArray avec lequel on va mettre à jour la géométrie de notre objet Shape3D qui représente notre pyramide multicolore :

// On recupere une instance de IndexedGeometryArray (ici equivalente
// a IndexedTriangleFanArray) que l'on ajoute a la geometrie de notre Shape3D
this.setGeometry(geometryInfo.getIndexedGeometryArray());

Le fichier GeometryInfo3D.java présente le code source complet de cet exemple. Nous en avons extrait le listing de la classe PyramideGeomIndicee qui prend en charge la construction d'un objet à géométrie indicée grâce à la classe utilitaire GeometryInfo :

/**
* Objet a geometrie indicee qui represente une pyramide a base carree
*/
class PyramideGeomIndicee extends Shape3D {

/**
* Constructeur
*/
public PyramideGeomIndicee() {
// Creation des points constituant la pyramide (corps + base) sans
// oublier les points qui vont etre reutilises
Point3f[] points = new Point3f[10];
points[0] = new Point3f( 0f, 0.8f, 0f); // sommet
points[1] = new Point3f(-0.4f, 0.1f, -0.4f); // base 1
points[2] = new Point3f(-0.4f, 0.1f, 0.4f); // base 2
points[3] = new Point3f( 0.4f, 0.1f, 0.4f); // base 3
points[4] = new Point3f( 0.4f, 0.1f, -0.4f); // base 4
points[5] = points[1]; // base 1
points[6] = points[1]; // base 1
points[7] = points[4]; // base 4
points[8] = points[3]; // base 3
points[9] = points[2]; // base 2

// Creation des couleurs associees a chaque sommet de la pyramide
Color3f[] colors = new Color3f[10];
colors[0] = new Color3f(Color.red);
colors[1] = new Color3f(Color.cyan);
colors[2] = new Color3f(Color.yellow);
colors[3] = new Color3f(Color.green);
colors[4] = new Color3f(Color.white);
colors[5] = colors[1];
colors[6] = colors[4];
colors[7] = colors[4];
colors[8] = colors[4];
colors[9] = colors[4];

// Construction de l'objet de type GeometryInfo avec une geometrie
// a base de TriangleFanArray
GeometryInfo geometryInfo =
new GeometryInfo(GeometryInfo.TRIANGLE_FAN_ARRAY);

// On met a jour les tableaux des points et des couleurs de l'objet
// geometryInfo
geometryInfo.setCoordinates(points);
geometryInfo.setColors(colors);

// Construction du tableau contenant le nombre de points par eventail :
// 6 points pour le premier eventail (corps) et 4 points pour le
// second (base)
geometryInfo.setStripCounts(new int[] {6, 4});

// On recupere une instance de IndexedGeometryArray (ici equivalente
// a IndexedTriangleFanArray) que l'on ajoute a la geometrie de notre
// Shape3D
this.setGeometry(geometryInfo.getIndexedGeometryArray());
} // fin constructeur
} // fin class PyramideGeomIndicee extends Shape3D

Exécutez l'applet GeometryInfo3D.html pour voir le résultat.

V - Texte 3D

Alors que Text2D pouvait être assimilé à un rectangle transparent sur lequel on plaque une texture représentant le texte à afficher, Text3D s'apparente plutôt à un objet géométrique. L'objet Text3D dérive d'ailleurs de la classe Geometry.

V-A - Principaux champs

public static final int ALIGN_FIRST
//Texte aligné sur son premier caractère
//(par rapport à la position du texte définie dans le constructeur).

public static final int ALIGN_CENTER
//Texte aligné par rapport à son centre
//(par rapport à la position du texte définie dans le constructeur).

public static final int ALIGN_LAST
//Texte aligné par rapport à son dernier caractère
//(par rapport à la position du texte définie dans le constructeur).

public static final int PATH_DOWN
//Texte écrit de haut en bas.

public static final int PATH_LEFT
//Texte écrit de droite à gauche.

public static final int PATH_RIGHT
//Texte écrit de gauche à droite.

public static final int PATH_DOWN
//Texte écrit de bas en haut.

V-B - Principal constructeur

public Text3D(Font3D font3D, String string, Point3f position, int alignment, int path)

Ce constructeur permet de créer un texte 3D qui représente la chaine de caractères string, utilisant la police de caractères font3D, positionnée au point de coordonnées position, alignée selon la valeur du paramètre alignment et dont le sens d'écriture du texte est défini par la valeur du paramètre path.

V-C - Principales méthodes

public Font3D getFont3D()
//Récupère une référence sur l'instance de Font3D ayant été utilisée pour
//la création de l'objet Text3D.

public void setFont3D(Font3D font3D)
//Mets à jour l'objet de type Font3D associé à l'objet Text3D

public String getString()
//Renvoie la chaine de caractères affichée par l'objet Text3D

public String setString(String string)
//Mets à jour la chaine de caractères attachée à l'objet Text3D

public void getPosition(Point3f position)
//Renvoie la position (copie) dans le paramètre position fourni

public void setPosition(Point3f position)
//Mets à jour la position de l'objet Text3D avec la valeur du paramètre position

public int getAlignment()
//Renvoie le type d'alignement du texte de l'objet Text3D

public void setAlignment(int alignment)
//Mets à jour le type d'alignement du texte de l'objet Text3D

public int getPath()
//Renvoie la valeur du path associé à l'objet Text3D

public void setPath(int path)
//Mets à jour la valeur du path associée à l'objet Text3D

V-D - Exemple

L'exemple HelloWorld3D.java très simple décrit l'utilisation de la classe Text3D. Il s'agit d'afficher le texte « 3D » qui est en rotation autour de l'axe Y. Notre objet de type Text3D est créé au sein de la classe TextShape3D qui étend Shape3D.

Création d'un objet de type Font3D à partir d'une police AWT

Font3D font3D = new Font3D(new Font("Arial", Font.PLAIN, 1), new FontExtrusion());

L'objet de type FontExtrusion nécessaire à la création de l'instance de classe font3D crée simplement une profondeur de relief par défaut pour notre texte 3D.

Construction de l'objet de type Text3D

Nous créons notre texte 3D qui s'affichera de gauche à droite avec un alignement au centre :

Text3D text3D = new Text3D(font3D, "3D",
new Point3f(0.0f, -0.3f, 0.0f),
Text3D.ALIGN_CENTER,
Text3D.PATH_RIGHT);

Mise à jour de la géométrie de l'instance de classe TextShape3D avec l'objet de type Text3D

Pour terminer, nous mettons à jour la géométrie de l'instance de la classe TextShape3D avec celle de notre objet Text3D (qui est, rappelons-le, un objet géométrique) :

Text3D text3D = new Text3D(font3D, "3D",
new Point3f(0.0f, -0.3f, 0.0f),
Text3D.ALIGN_CENTER,
Text3D.PATH_RIGHT);

Nous remarquons que la chaine de caractères « 3D » occupe la quasi-totalité de notre fenêtre Canvas3D. C'est pour cela que nous avons pris une taille de police égale à 1.
Nous verrons dans le chapitre sur les transformations géométriques que l'on peut très facilement réduire la taille des objets 3D par une simple transformation, ce qui permettrait dans notre cas précis d'afficher une chaine de caractères beaucoup plus longue.

Le fichier HelloWorld3D.java présente le code source complet de cet exemple. Nous en avons extrait le listing de la classe TextShape3D qui prend en charge la construction d'un objet de type Text3D :

/**
* Objet geometrique qui represente une chaine de caractères affichée en 3D
*/
class TextShape3D extends Shape3D {

/**
* Constructeur
*/
public TextShape3D() {
Font3D font3D = new Font3D(new Font("Arial", Font.PLAIN, 1), new FontExtrusion());

Text3D text3D = new Text3D(font3D, "3D",
new Point3f(0.0f, -0.3f, 0.0f),
Text3D.ALIGN_CENTER,
Text3D.PATH_RIGHT);

// Mise a jour de la geometrie de l'objet TextShape3D
this.setGeometry(text3D);
} // fin constructeur
} // fin class TextShape3D extends Shape3D

Exécutez l'applet HelloWorld3D.html pour voir le résultat.

VI - En préparation

Le chapitre suivant de « Développez en 3D » sera dédié aux Transformations géométriques ( les translations, les rotations et les homothéties).

VII - Applets exemples

Voici la liste de toutes les applets données en exemple au cours de ce chapitre :

BackgroundColor.html
BackgroundImage.html
Box3D.html
Sphere3D.html
Cylindre3D.html
Cone3D.html
HelloWorld2D.html
PointArray3D.html
LineArray3D.html
TriangleArray3D.html
QuadArray3D.html
LineStripArray3D.html
TriangleStripArray3D.html
TriangleFanArray3D.html
IndexedTriangleFanArray3D.html
GeometryInfo3D.html
HelloWorld3D.html

Vous pouvez télécharger tous les codes sources ci-dessous.

VIII - Téléchargements

Article au format PDF (miroir)
Article HTML/ZIP (miroir)
Codes sources (miroir)