Vous êtes sur la page 1sur 206

Programmation C#

Guide Pratique
de la
Modélisation 3D
avec WPF 4
Avec l’environnement
de développement
.NET Framework 4 et
Visual Studio 2010
de MICROSOFT
Guide
pratique
de la
modélisation
3D
avec WPF 4

Patrice REY
Toutes les marques citées ont été déposées par leurs propriétaires respectifs.

La loi du 11 Mars 1957 n’autorisant aux termes des alinéas 2 et 3 de l’article 41,
d’une part, que les «copies ou reproductions strictement réservées à l’usage privé
du copiste et non destinées à une utilisation collective», et, d’autre part, que les
analyses et les courtes citations dans un but d’exemple et d’illustration, «toute
représentation ou reproduction intégrale, ou partielle, faite sans le consentement
de l’auteur ou de ses ayants droit ou ayant cause, est illicite» (alinéa 1er de l’article
40).
Cette représentation ou reproduction, par quelque procédé que ce soit,
constituerait donc une contre-façon sanctionnée par les articles 425 et suivants du
Code Pénal.

Titres déjà parus


Initiation au jeu 2D avec Silverlight 4
(ISBN : 978-2-8106-1168-3)
Les structures de données illustrées avec WPF et C#4
(ISBN : 978-2-8106-1387-8)
La programmation graphique 2D de WPF 4
(ISBN : 978-2-8106-1199-7)
La programmation graphique 3D de WPF 4
(ISBN : 978-2-8106-2086-9)

Éditeur
Books on Demand GmbH,
12/14 rond point des Champs Élysées,
75008 Paris, France
Impression :
Books on Demand GmbH, Norderstedt, Allemagne
ISBN : 978-2-8106-1308-3
Dépôt légal : Septembre 2011

Auteur
Patrice REY
85 rue de vincennes
App 23 B
33000 BORDEAUX

e-mail : reypatrice@orange.fr
Table des matières

Avant-propos .......................................................................................... 7
Chapitre 1 - Point3D et Vector3D
1. La structure Point3D ......................................................................... 13
2. La notion de vecteur ......................................................................... 15
3. La structure Vector3D ...................................................................... 18
4. Les méthodes de Point3D et de Vector3D ..................................... 19
4.1 - Les méthodes de Point3D ......................................................... 19
4.2 - Les méthodes de Vector3D ...................................................... 25
Chapitre 2 - La scène 3D
1. Visualisation de la scène ................................................................... 33
2. Le contrôle Viewport3D ................................................................... 34
3. La création de modèles 3D .............................................................. 35
3.1 - La classe ModelVisual3D ........................................................... 35
3.2 - La classe UIElement3D .............................................................. 37
3.3 - La classe GeometryModel3D .................................................... 39
4. La géométrie Geometry3D .............................................................. 40
5. Matières et surfaces ......................................................................... 45
5.1 - La surface mate .......................................................................... 46
5.2 - La surface lumineuse ................................................................. 47
5.3 - Combinaison de matières ......................................................... 47
5.4 - La réflexion spéculaire .............................................................. 48
6. L’éclairage de la scène ....................................................................... 49
7. Les caméras ....................................................................................... 51
4 Table des matières

Chapitre 3 - La modélisation du cube


1. La facette triangulaire ........................................................................ 55
2. La facette rectangulaire ..................................................................... 62
3. Le cube ............................................................................................... 67
3.1 - Un cube avec des faces uniformes .............................................. 67
3.2 - Un cube avec des faces texturées ............................................... 73
3.3 - Un cube générique .................................................................... 76
4. Les axes de coordonnées et le plan de travail .................................. 83
Chapitre 4 - La modélisation de la sphère
1. Les coordonnées sphériques ............................................................. 91
2. La modélisation sphérique ............................................................... 93
3. L’ellipsoïde ........................................................................................ 99
Chapitre 5 - La modélisation du cylindre
1. La géométrie du cylindre ................................................................... 103
2. Modélisation de la facette cylindrique ............................................. 105
Chapitre 6 - La modélisation du cône
1. La géométrie du cône ....................................................................... 111
2. La modélisation du cône ................................................................. 113
3. Des cônes particuliers ....................................................................... 117
Chapitre 7 - La modélisation du tore
1. La géométrie du tore ....................................................................... 121
2. La modélisation du tore ................................................................. 122
3. Différents tores ................................................................................. 126
Chapitre 8 - Les géométries 3D personnalisées
1. La configuration du projet ................................................................ 129
2. La géométrie personnalisée des axes de coordonnées ...................... 134
2.1 - Hériter de UIElement3D ............................................................. 134
2.2 - Générer le modèle ...................................................................... 139
3. La géométrie personnalisée du plan de travail ................................. 143
Table des matières 5

4. La géométrie personnalisée du cube ................................................. 151


5. La géométrie personnalisée de l’ellipsoïde ...................................... 159
6. La géométrie personnalisée du cylindre ......................................... 165
7. La géométrie personnalisée du cône .............................................. 172
8. La géométrie personnalisée du tore ............................................... 179
Annexe: implémentation d’un Trackball ................................................. 185
Index ......................................................................................................... 193
Avant-propos

WPF (Windows Presentation Foundation) est une technologie de développement


d’application riche (Rich Desktop Application) pour la plateforme Windows. La
version actuelle de WPF est la version 4, celle qui correspond à .NET 4.0, qui
est sortie en avril 2010. Depuis 2006, date de la première sortie de WPF, cette
technologie est devenue une technologie majeure du développement pour
Windows en code managé.
Les innovations de WPF, à la fois sur le plan architectural et sur le plan fonctionnel,
sont très importantes dans sa version actuelle. WPF constitue une synthèse et
une unification des différentes branches de l’informatique graphique (graphismes
vectoriels 2D et 3D, saisie, animation, typographie et multimédia).
A noter que WPF ne cible pas la réalisation des jeux vidéo évolués puisque Microsoft
fournit des technologies évoluées et adaptées qui sont XNA en code managé et
DirectX en code natif.
WPF est un framework managé qui exploite la puissance de Direct3D pour
l’affichage. Cette technologie de développement d’interface utilisateur permet
de moderniser et unifier les techniques de développement visuel, d’exploiter la
puissance graphique des machines modernes, d’intégrer l’infographie dans le
processus de développement, et de simplifier et sécuriser le déploiement des
applications.
En s’appuyant sur Direct3D, WPF exploite toute la puissance du GPU (Graphic
Processing Unit ou le processeur graphique), ce qui permet de libérer le CPU
(Central Processing Unit) et d’envisager des applications graphiques de plus en
plus riches.
WPF sépare dans des couches distinctes la programmation des fonctionnalités (au
moyen d’un langage .NET tel que le C#) de la présentation visuelle par l’utilisation
du langage XAML (eXtensible Application Markup Language).
8 Avant-propos

Les logiciels requis pour le développement

Pour réaliser plus facilement des programmes en C#, il est préférable d’utiliser
un environnement de développement intégré ou IDE (Integrated Development
Environment). Cet IDE permet de développer, compiler et exécuter un programme
dans un langage donné qui sera, dans ce livre, le C# (se prononce C Sharp). Microsoft
propose comme IDE soit Visual Studio 2010 (dans sa version payante avec 30 jours
d’essai gratuit), soit Visual C# 2010 Express (dans sa version allégée mais gratuite).
Puissante interface IDE garantissant la production d’un code de qualité, Visual
Studio 2010 intègre de nouvelles fonctionnalités qui simplifient le processus de
développement d’application, de la conception au déploiement.
Pour télécharger et installer l’environnement de développement intégré, ouvrez
votre navigateur et allez sur les pages web suivantes au choix:
• pour télécharger Visual C# 2010 Express (figure A1): http://msdn.microsoft.
com/fr-fr/express/aa975050.aspx
• pour télécharger une version d’évaluation Visual Studio 2010 Ultimate avec
une période d’essai gratuite de 30 jours (figure A2): http://www.microsoft.
com/france/visualstudio/download
Figure A1

Figure A2
Avant-propos 9

Le contenu du livre

Les différents chapitres permettent d’apprendre à modéliser des objets 3D, de les
insérer dans la scène 3D, et de pouvoir visualiser la scène sous différents angles
grâce aux manipulations 3D avec la souris. Les chapitres abordent les points
suivants:
• le chapitre 1 traite la notion de point et la notion de vecteur dans l’espace 3D;
ces deux notions, en géométrie vectorielle, sont fondamentales et essentielles
dans le développement 3D.
• le chapitre 2 aborde tout ce qui concerne la composition d’une scène 3D avec
la zone de rendu, l’éclairage, la caméra et les modèles 3D.
• le chapitre 3 traite de la modélisation de la facette triangulaire (objet 2D de
base); un assemblage de triangles permet de modéliser un cube; on y verra le
cube avec une couleur uniforme, le cube avec des faces texturées, et le cube
générique.
• le chapitre 4 traite de la modélisation de la sphère; ce chapitre introduit une
notion mathématique très utilisée en 3D que sont les coordonnées sphériques.
• le chapitre 5 traite de la modélisation du cylindre et de sa surface cylindrique
texturée.
• le chapitre 6 traite de la modélisation du cône avec sa surface conique; on
y verra le cône circulaire, le cône circulaire tronquée, et la pyramide (une
variante).
• le chapitre 7 traite de la modélisation du tore avec sa surface torique; on y
verra le tore dit «ouvert», le tore dit «à collier nul» et le tore dit «croisé».
• le chapitre 8 traite des géométries 3D personnalisées; on y verra comment
modéliser des modèles 3D par code procédural, comment les insérer
directement en XAML, et comment les rendre interactifs par l’intermédiaire de
la classe UIElement3D.

Toutes les notions abordées dans ce livre font l’objet d’une utilisation directe et
pratique que vous trouverez dans le code source en téléchargement. La figure A3
montre le projet tel qu’il est réalisé. Il y a un onglet par chapitre côté gauche, et
dans chaque onglet, les divers contrôles utilisateur réalisés s’affichent côté droit.
Il est ainsi possible de suivre aisément la réalisation technique des composants en
fonction des chapitres du livre.
10 Avant-propos
Figure A3

Les liens de téléchargement

Tout le code source de cet ouvrage pourra être téléchargé gratuitement à l’adresse
web suivante:
http://www.reypatrice.fr

Vous trouverez dans l’arborescence des fichiers du projet, un dossier pour chacun
des chapitres (figure A4). Chaque dossier contient tous les éléments nécessaires de
programmation qui sont expliqués dans le livre. De cette façon, vous serez capable
de suivre et de programmer assez rapidement et assez facilement.
Avant-propos 11
Figure A4

C’est une démarche volontaire, dans un but pédagogique, pour progresser


rapidement.

Bonne lecture à tous.


CHAPITRE 1

Point3D et Vector3D

D ans WPF, l’espace de noms System.Windows.Media.Media3D (assembly


PresentationCore.dll) contient toutes les classes et toutes les structures qui
supportent la représentation 3D. Les fonctionnalités 3D permettent aux
développeurs de dessiner, de transformer et d’animer des graphiques 3D, à la
fois en XAML et en code procédural. Les développeurs peuvent aussi combiner
de la 2D et des graphiques 3D pour créer des contrôles riches, pour fournir des
illustrations complexes de données et pour améliorer l’expérience utilisateur de
l’interface d’une application.
Dans ce chapitre, nous allons voir les structures Point3D et Vector3D qui
représentent les bases de la construction, en géométrie analytique, des objets
dans l’espace 3D.

1 - La structure Point3D

La localisation des points qui constituent une figure 3D dans un espace 3D, passe
par l’utilisation de coordonnées 3D. Le framework .NET 4 propose une structure
nommée Point3D. Cette structure Point3D représente un point de coordonnées x,
y et z dans l’espace 3D.
Dans un système à 3 dimensions, un point est représenté par ses coordonnées
selon les 3 axes X, Y et Z. Dans le repère 3D utilisé par WPF, depuis l’origine O du
repère, l’axe des abscisses X positives part vers la droite, l’axe des ordonnées Y
positives part vers le haut, et l’axe des coordonnées Z positives part vers l’extérieur
et devant.
Ces 3 axes peuvent être représentés au moyen des doigts d’une main: le pouce
représente l’axe des X, l’index représente l’axe des Y et le majeur représente
l’axe des Z. L’axe des X est généralement dirigé vers la droite et l’axe des Y est
14 Guide pratique de la modélisation 3D avec WPF 4
généralement dirigé vers le haut. Pour la direction de l’axe des Z, WPF utilise le
système «main droite» dans lequel l’axe des Z est dirigé vers l’avant (il sort de
l’écran). La figure 1-1 visualise ces 3 axes.
Figure 1-1

Y
plan (Ox,Oy)

plan (Oy,Oz)

O
X

plan (Ox,Oz)

Les coordonnées (x,y,z) d’un point dans l’espace 3D sont représentées par la
structure Point3D. Cette structure expose les propriétés:
• X qui représente la coordonnée x du Point3D sur l’axe des X.
• Y qui représente la coordonnée y du Point3D sur l’axe des Y.
• Z qui représente la coordonnée z du Point3D sur l’axe des Z.
La figure 1-2 visualise un point A de coordonnées (4,2,3) et de type Point3D. Pour
instancier le point A, en code procédural, on écrira:
Point3D pt_a = new Point3D(4,2,3).
La classe Point3DCollection est une collection typée d’objets Point3D. Elle est
très utile quand l’on souhaite stocker un ensemble de points, de type Point3D,
pour effectuer par exemple une visualisation d’un ensemble de points à un instant
Copyright 2011 Patrice REY

donné.
Pour instancier une nouvelle collection collect, de type Point3DCollection, on écrira
Point3DCollection collect = new Point3DCollection().
Et pour ajouter le point A(4,2,3) à cette collection, on écrira
• soit collect.Add(new Point3D(4,2,3)) pour ajouter un nouveau point A.
• soit collect.Add(pt_a) si le point A(4,2,3) a été instancié par Point3D pt_a=new
Point3D(4,2,3).
CHAPITRE 1 □ Point3D et Vector3D 15
Figure 1-2
Y

A
4
X

3
A(4,2,3)

2 - La notion de vecteur

René Descartes (1596-1650) est l’un des plus grands savants et philosophes de
son temps, fondateur de la géométrie analytique, de l’application de l’algèbre
à la géométrie, et d’une approche de la connaissance fondée sur la méthode
rationnelle. Avec les encouragements de ses amis scientifiques (Mersenne,
Beeckman, Mydorge, Hortensius, Huygens, van Schooten), René Descartes publia
son monumental traité « Discours de la Méthode, pour bien conduire sa raison
et chercher la vérité dans les sciences », fondement de la démarche scientifique
moderne (figure 1-3). Cet ouvrage comporte trois appendices qui illustrent
l’application de sa méthode, ce sont La Dioptrique, Les Météores et La Géométrie.
Ce traité fut publié à Leyden en 1637.
C’est dans son traité de géométrie que Descartes fit un apport décisif : il posa
le premier les principes de l’invariance, où fut soulevée pour la première fois
la question de référentiel pour observer et décrire les phénomènes. Pour René
Descartes, l’existence même d’un raisonnement mathématique et d’une façon
ordonnée de penser, prouve que l’homme, en suivant méthodiquement certaines
règles, peut se convaincre d’avoir atteint la vérité. L’ordre qu’il établit en géométrie
16 Guide pratique de la modélisation 3D avec WPF 4
des courbes repose sur l’emploi des coordonnées.
Figure 1-3

La géométrie analytique est un outil nouveau qui permet de résoudre par le calcul
un problème de géométrie. Il est forgé par Descartes alors que celui-ci cherche
à résoudre un problème posé par Pappus à la fin du IIIe siècle et non résolu
jusqu’alors. Il apporte l’idée de remplacer chaque point par deux nombres qui
seront ses coordonnées afin de résoudre par le calcul un problème de géométrie.
Par définition, un vecteur est un objet mathématique, représenté par deux points
A et B, et qui possède 3 caractéristiques (figure 1-4):
• une direction: c’est la droite (AB)
• un sens: celui qui va de A vers B
• une longueur: c’est la distance entre A et B
Figure 1-4

droite AB

B
Copyright 2011 Patrice REY

A
En mathématiques, les mots «sens» et «direction» ne sont pas synonymes (figure
1-5). Une direction est définie à l’aide d’une droite. Des droites parallèles ont la
même direction. Un sens n’est défini qu’associé à une direction. Pour une direction
il n’y a que deux sens possibles.
CHAPITRE 1 □ Point3D et Vector3D 17
Figure 1-5

sens de A vers B droite AB

A sens de B vers A

D1
D2 D3

les droites D1, D2 et D3 définissent sur la direction définie par (AB), il y a le sens «A
la même direction vers B» et le sens «B vers A»

D’un point de vue modélisation des données, un vecteur s’apparente à un


déplacement selon l’axe des abscisses et à un déplacement selon l’axe des
ordonnées. Un vecteur dans l’espace 2D sera matérialisé par ces déplacements,
par une valeur réelle x (pour les abscisses) et par une valeur réelle y pour les
ordonnées.
La connaissance de ces 2 valeurs suffit pour matérialiser n’importe quel vecteur
(figure 1-6). Et à partir de ces 2 valeurs, nous pouvons calculer facilement la
longueur du vecteur.
Figure 1-6

la longueur L du vecteur AB
est égale à sa norme
c’est-à-dire :

déplacement distance = b
selon Y
A

déplacement selon X

O
distance = a
18 Guide pratique de la modélisation 3D avec WPF 4

3 - La structure Vector3D

Le framework .NET 4 possède une structure Vector3D qui gère l’utilisation et la


manipulation des vecteurs dans l’espace 3D.
Un vecteur dans l’espace 3D est représenté par une structure Vector3D. Un vecteur
dans l’espace 3D, de type Vector3D, par définition, représente un déplacement
dans l’espace 3D. Cette structure expose les propriétés suivantes:
• X qui représente le composant x de cette structure.
• Y qui représente le composant y de cette structure.
• Z qui représente le composant z de cette structure.
• Length qui obtient la longueur de cette structure.
• LengthSquared qui obtient le carré de la longueur de cette structure.
La figure 1-7 montre un vecteur V dont ses composantes sont (4,3,3). Ce vecteur
part de l’origine O vers le point A(4,3,3). Un vecteur indique un déplacement par ses
composantes. Depuis l’origine O, le déplacement selon X est de 4, le déplacement
selon Y est de 3 et le déplacement selon Z est de 3.
De ce fait, on dit que le point A est l’image du point O par la translation de vecteur
(4,3,3). Il est important de garder à l’esprit qu’un vecteur est un déplacement dans
l’espace 3D. Il existe une infinité de vecteurs identiques à celui-ci.
Figure 1-7 Y

A
Copyright 2011 Patrice REY

4
O X

3 vecteur de
l’origine à A(4,3,3)

Z
CHAPITRE 1 □ Point3D et Vector3D 19

4 - Les méthodes de Point3D et Vector3D

Les structures Point3D et Vector3D possèdent un ensemble de méthodes pour


effectuer différents calculs vectoriels. Il est important de bien connaître ces
différents mécanismes qui interviendront plus tard systématiquement dans la
modélisation.

4.1 - Les méthodes de Point3D

La méthode statique Point3D.Add(..) permet d’additionner un vecteur à un point.


Cela permet de trouver les coordonnées d’un point B connaissant les coordonnées
d’un point A et celles d’un vecteur V. La figure 1-8 schématise géométriquement
le résultat recherché. La structure Vector3D possède une surcharge de l’opérateur
«+», ce qui permet d’écrire directement l’expression pt_b=pt_a+vect avec pt_a et
pt_b qui sont du type Point3D et vect qui est du type Vector3D. A noter qu’une
deuxième surcharge de l’opérateur permet d’écrire aussi pt_b=vect+pt_a.
Figure 1-8

B
1

A 1 4
X
2
3 A(1,1,2)
B(4,3,3)
vecteur de A vers B a
pour coordonnées (3,2,1)
Z
20 Guide pratique de la modélisation 3D avec WPF 4
Soient un point A, de type Point3D, de coordonnées (1,1,2) et un vecteur V, de type
Vector3D, de coordonnées (3,2,1), le point B recherché possède les coordonnées
(4,3,3).
Dans le fichier Index01.xaml.cs, dans le dossier chapitre01, la méthode
TesterAdditionPointVecteur() permet d’effectuer ces calculs. La figure 1-9 visualise
les résultats obtenus.

//action: tester addition


private void TesterAdditionPointVecteur() {
Point3D pt_a = new Point3D(1, 1, 2);
Vector3D vect = new Vector3D(3, 2, 1);
AfficherTexte(«pt_a = « + pt_a.ToString());
AfficherTexte(«vect = « + vect.ToString());
Point3D pt_b = Point3D.Add(pt_a, vect);
AfficherTexte(«-> pt_b = Point3D.Add(pt_a, vect)»);
AfficherTexte(«-> pt_b = « + pt_b.ToString());
pt_b = pt_a + vect;
AfficherTexte(«-> pt_b = pt_a + vect»);
AfficherTexte(«-> pt_b = « + pt_b.ToString());
pt_b = vect + pt_a;
AfficherTexte(«-> pt_b = vect + pt_a»);
AfficherTexte(«-> pt_b = « + pt_b.ToString());
}

Figure 1-9

Si à un point A, on soustrait un vecteur V, on obtient un point B. La figure 1-10


schématise géométriquement le résultat recherché. La méthode statique
Copyright 2011 Patrice REY

Point3D.Substract(..) permet de soustraire un vecteur à un point.


Soient le point A(4,3,3) et le vecteur V(3,2,1), la soustraction de V à A donne le
point B aux coordonnées (1,1,2). Il existe ici aussi une surcharge de l’opérateur «-»
pour soustraire directement un vecteur à un point par l’écriture pt_b=pt_a-vect
(avec pt_a et pt_b de type Point3D, et vect de type Vector3D).
CHAPITRE 1 □ Point3D et Vector3D 21
Figure 1-10
Y

A
1

B 1 4
X
2
3 A(4,3,3)
B(1,1,2)
A moins le vecteur V de
coordonnées (3,2,1)
Z donne B

La méthode TesterSoustractionPointVecteur() permet d’effectuer ces calculs. La


figure 1-11 visualise les résultats obtenus.

//action: tester soustraction


private void TesterSoustractionPointVecteur() {
Point3D pt_a = new Point3D(4,3,3);
Vector3D vect = new Vector3D(3, 2, 1);
AfficherTexte(«pt_a = « + pt_a.ToString());
AfficherTexte(«vect = « + vect.ToString());
Point3D pt_b = Point3D.Subtract(pt_a, vect);
AfficherTexte(«-> pt_b = Point3D.Subtract(pt_a, vect)»);
AfficherTexte(«-> pt_b = « + pt_b.ToString());
pt_b = pt_a - vect;
AfficherTexte(«-> pt_b = pt_a - vect»);
AfficherTexte(«-> pt_b = « + pt_b.ToString());}

Figure 1-11
22 Guide pratique de la modélisation 3D avec WPF 4
Pour trouver les coordonnées d’un vecteur connaissant un point A et un point B, il
faut utiliser une surcharge de l’opérateur «-» de Point3D qui retourne un vecteur,
de type Vector3D, quand on soustrait un point à un autre point (par exemple avec
l’écriture vect=pt_a-pt_b ou bien avec l’écriture vect=pt_b-pt_a).
Par exemple, sur la figure 1-8, on avait A(1,1,2) et B(4,3,3) et le vecteur V(3,2,1)
permettait de passer de A vers B. Connaissant ces deux points, nous allons trouver
le vecteur résultant orienté par la méthode TesterVecteurEntrePoints().

//action: determiner un vecteur connaissant deux points


private void TesterVecteurEntrePoints() {
Point3D pt_a = new Point3D(1, 1, 2);
Point3D pt_b = new Point3D(4, 3, 3);
AfficherTexte(«pt_a = « + pt_a.ToString());
AfficherTexte(«pt_b = « + pt_b.ToString());
Vector3D vect = pt_b - pt_a;
AfficherTexte(«-> vect = pt_b - pt_a «);
AfficherTexte(«-> vect = « + vect.ToString());
vect = pt_a - pt_b;
AfficherTexte(«-> vect = pt_a - pt_b «);
AfficherTexte(«-> vect = « + vect.ToString());
}

Trouver le vecteur résultant entre deux points c’est trouver un vecteur orienté.
Deux cas sont possibles:
• vecteur = point B - point A : correspond au vecteur dont le point de départ est
le point A et le point d’arrivée est le point B, donc un vecteur orienté de A vers
B.
• vecteur = point A - point B : correspond au vecteur dont le point de départ est
le point B et le point d’arrivée est le point A, donc un vecteur orienté de B vers
A.
La figure 1-12 montre les résultats obtenus pour des vecteurs orientés pour aller
de A(1,1,2) à B(4,3,3), et inversement.

Figure 1-12
Copyright 2011 Patrice REY
CHAPITRE 1 □ Point3D et Vector3D 23
Une méthode très intéressante de Point3D est la méthode Offset(..). Elle permet
de trouver directement les coordonnées d’un point B connaissant les coordonnées
d’un point A ainsi qu’une direction donnée. Cette direction est formulée par trois
composantes (x,y,z) qui sont des composantes de translation selon les 3 axes X, Y et
Z. Si nous reprenons les coordonnées de A(1,1,2) et une direction de déplacement
de coordonnées (3,2,1), comme sur la figure 1-8, nous obtenons le point B de
coordonnées (4,3,3).

//action: determiner un vecteur connaissant deux points


private void TesterMethodeOffset() {
Point3D pt_a = new Point3D(1, 1, 2);
AfficherTexte(«on a : pt_a = « + pt_a.ToString());
pt_a.Offset(3, 2, 1);
AfficherTexte(«on effectue: pt_a.Offset(3, 2, 1)»);
AfficherTexte(«-> on obtient : pt_a = « + pt_a.ToString());
}

Le résultat obtenu par la méthode TesterMethodeOffset(), est visualisé sur la figure


1-13.
Figure 1-13

Quand on a un ensemble de points, pour tester leur égalité (ou inégalité), on a le


choix entre trois façons:
• avec la surcharge de l’opérateur «==» et de l’opérateur «!=», on peut écrire
pt_1==pt_2 ou bien pt_1!=pt_2
• avec la méthode booléenne statique Point3D.Equals(..), on peut écrire
Point3D.Equals(pt_1,pt_2)
• avec la méthode booléenne Equals(..), héritée et redéfinie, on peut écrire pt_1.
Equals(pt_2)
Les résultats obtenus par la méthode TesterEgaliteInegalite(), sont visualisés sur la
figure 1-14.

//action: tester egalite inegalite


private void TesterEgaliteInegalite() {
24 Guide pratique de la modélisation 3D avec WPF 4
Point3D pt_a = new Point3D(1, 1, 2);
Point3D pt_b = new Point3D(4, 3, 3);
AfficherTexte(«pt_a = « + pt_a.ToString());
AfficherTexte(«pt_b = « + pt_b.ToString());
AfficherTexte(«-> pt_a == pt_b : « );
if (pt_a == pt_b) {
AfficherTexte(«-> pt_a et pt_b sont égaux»);
}
else {
AfficherTexte(«-> pt_a et pt_b ne sont pas égaux»);
}
AfficherTexte(«-> Point3D.Equals(pt_a,pt_b) : « );
if (Point3D.Equals(pt_a, pt_b) == true) {
AfficherTexte(«-> pt_a et pt_b sont égaux»);
}
else {
AfficherTexte(«-> pt_a et pt_b ne sont pas égaux»);
}
AfficherTexte(«-> pt_a.Equals(pt_b) : « );
if (pt_a.Equals(pt_b) == true) {
AfficherTexte(«-> pt_a et pt_b sont égaux»);
}
else {
AfficherTexte(«-> pt_a et pt_b ne sont pas égaux»);
}
}

Figure 1-14

Pour convertir une chaîne textuelle représentant uns structure Point3D en une
structure Point3D, il faut utiliser la méthode statique Point3D.Parse(..). Elle reçoit en
Copyright 2011 Patrice REY

paramètre une chaîne textuelle, de type string, et retourne une structure Point3D.
La figure 1-15 visualise le résultat obtenu de la méthode TesterPoint3dTextuelle().

//action: transformer chaine textuelle


private void TesterPoint3dTextuelle() {
Point3D pt_a = Point3D.Parse(«1,2,3»);
AfficherTexte(«pt_a = Point3D.Parse(\»1,2,3\»)»);
CHAPITRE 1 □ Point3D et Vector3D 25
AfficherTexte(«-> pt_a = « + pt_a.ToString());
}

Figure 1-15

4.2 - Les méthodes de Vector3D

La structure Vector3D possède un ensemble de méthodes pour effectuer des


calculs vectoriels. L’addition vectorielle permet de trouver le vecteur W résultant
de la somme du vecteur V et du vecteur W (figure 1-16).
Figure 1-16
Y

vecteur
V(4,-2,0)

vecteur
U(0,2,-3)
X

vecteur W=U+V
W(4,0,-3)

Z
Cette somme vectorielle s’effectue grâce à la surcharge de l’opérateur «+» de
Vector3D, ou bien avec la méthode statique Vector3D.Add(..). La méthode
TesterAdditionVecteurs() permet d’effectuer ces calculs avec les vecteurs de la
figure 1-16. La figure 1-17 visualise les résultats obtenus.
26 Guide pratique de la modélisation 3D avec WPF 4
//action: additionner 2 vecteurs
private void TesterAdditionVecteurs() {
Vector3D u = new Vector3D(0, 2, -3);
Vector3D v = new Vector3D(4, -2, 0);
Vector3D w = u + v;
AfficherTexte(«vecteur u = « + u.ToString());
AfficherTexte(«vecteur v = « + v.ToString());
AfficherTexte(«-> w = u + v « );
AfficherTexte(«-> vecteur w = « + w.ToString());
w = Vector3D.Add(u, v);
AfficherTexte(«-> w = Vector3D.Add(u, v) «);
AfficherTexte(«-> vecteur w = « + w.ToString());
}

Figure 1-17

Soient U et V deux vecteurs, le vecteur résultant W=U-V représente la soustraction


vectorielle qui consiste à ajouter à U le vecteur opposé à V. Ce qui donne W=U-V
= U+(-V).
En appliquant la soustraction vectorielle sur les 2 vecteurs de la figure 1-16, nous
obtenons le vecteur résultant de cette soustraction (figure 1-18).

//action: soustraire 2 vecteurs


private void TesterSoustractionVecteurs() {
Vector3D u = new Vector3D(0, 2, -3);
Vector3D v = new Vector3D(4, -2, 0);
Vector3D w = u - v;
AfficherTexte(«vecteur u = « + u.ToString());
AfficherTexte(«vecteur v = « + v.ToString());
Copyright 2011 Patrice REY

AfficherTexte(«-> w = u + v «);
AfficherTexte(«-> vecteur w = « + w.ToString());
w = Vector3D.Subtract(u, v);
AfficherTexte(«-> w = Vector3D.Subtract(u, v) «);
AfficherTexte(«-> vecteur w = « + w.ToString());
}
CHAPITRE 1 □ Point3D et Vector3D 27
Figure 1-18

Le produit vectoriel consiste à multiplier un vecteur par un scalaire (une valeur de


type double). Le vecteur se trouve alors augmenté en longueur mais sa direction
reste la même. Son sens peut être opposé si le scalaire multiplicateur est négatif.
La figure 1-19 schématise géométriquement le résultat d’un produit d’un vecteur
par un scalaire.
Figure 1-19
Y

vecteur U multiplié par 2 donne


U(4,2,-2)

X
vecteur
U(2,1,-1)

Z
La surcharge de l’opérateur «*» permet de multiplier un vecteur par une valeur de
type double. L’autre façon est d’utiliser la méthode statique Vector3D.Multiply(..). En
utilisant le vecteur de la figure 1-19, avec la méthode TesterVecteurProduitValeur(),
nous obtenons le résultat visualisé sur la figure 1-20.
28 Guide pratique de la modélisation 3D avec WPF 4
//action: multiplier vecteur par valeur
private void TesterVecteurProduitValeur() {
Vector3D u = new Vector3D(2, 1, -1);
AfficherTexte(«vecteur u = « + u.ToString());
Vector3D v = u * 2;
AfficherTexte(«-> v = u * 2»);
AfficherTexte(«-> v = « + v.ToString());
v = Vector3D.Multiply(2, u);
AfficherTexte(«-> Vector3D.Multiply(2, u)»);
AfficherTexte(«-> v = « + v.ToString());
}
Figure 1-20

La longueur d’un vecteur est obtenue par la propriété Length et la longueur élevée
au carré est obtenue par la propriété LengthSquared. La figure 1-21 schématise un
vecteur V de coordonnées (3,3,3).
Figure 1-21
Y

V
3
X
Copyright 2011 Patrice REY

3
vecteur V(3,3,3)

Z
CHAPITRE 1 □ Point3D et Vector3D 29
La méthode TesterVecteurLongueur() calcule la longueur du vecteur de la figure
1-21, ainsi que sa longueur élevée au carré. La figure 1-22 visualise les résultats
obtenus.

//action: longueur
private void TesterVecteurLongueur() {
Vector3D u = new Vector3D(3,3,3);
AfficherTexte(«vecteur u = « + u.ToString());
AfficherTexte(«-> longueur de u = «+u.Length.ToString());
AfficherTexte(«-> longueur de u au carré = « + u.LengthSquared.ToString());
}

Figure 1-22

La normalisation d’un vecteur consiste à trouver les coordonnées du vecteur ayant


pour longueur 1. La normalisation ne change ni la direction du vecteur, ni le sens
du vecteur. Elle ne fait que réduire le vecteur à une longueur de 1 en recalculant
ses composantes (x,y,z).
Pour normaliser un vecteur, il suffit de lui appliquer la méthode Normalize(). La
figure 1-23 visualise les résultats obtenus pour un vecteur V(3,3,3).

//action: longueur
private void TesterVecteurNormaliser() {
Vector3D u = new Vector3D(3, 3, 3);
AfficherTexte(«vecteur u = « + u.ToString());
AfficherTexte(«longueur de u = « + u.Length.ToString());
u.Normalize();
AfficherTexte(«-> u.Normalize() «);
AfficherTexte(«-> vecteur u = « + u.ToString());
AfficherTexte(«-> longueur de u = « + u.Length.ToString());
}
Figure 1-23
30 Guide pratique de la modélisation 3D avec WPF 4
Le calcul de l’angle entre deux vecteurs se fait par la méthode statique Vector3D.
AngleBetween. La figure 1-24 schématise géométriquement le résultat recherché.
Figure 1-24

vecteur
V(2,0,0)
vecteur
U(0,0,3) X
angle

Soient les vecteurs U(0,0,3) et V(2,0,0), l’angle recherché sera de 90 degrés. La


méthode TesterVecteurAngle() permet d’effectuer ce calcul et la figure 1-25
visualise le résultat correspondant obtenu.

//action: angle
private void TesterVecteurAngle() {
Vector3D u = new Vector3D(0, 0, 3);
Vector3D v = new Vector3D(2, 0, 0);
AfficherTexte(«vecteur u = « + u.ToString());
Copyright 2011 Patrice REY

AfficherTexte(«vecteur v = « + v.ToString());
double angle = Vector3D.AngleBetween(u, v);
AfficherTexte(«-> angle = Vector3D.AngleBetween(u, v)»);
AfficherTexte(«-> angle = « + angle.ToString()+» degrés»);
}
CHAPITRE 1 □ Point3D et Vector3D 31
Figure 1-25
CHAPITRE 2

La scène 3D

La scène 3D est un objet complexe. C’est l’endroit où l’on positionne des éléments
en 3D dans le but d’effectuer un rendu en 2D. Ce sont ces éléments qui permettent
de donner un réalisme à la scène 3D.
Dans ce chapitre nous allons voir comment s’organise une scène 3D au travers
des éléments nécessaires à sa composition avec notamment le Viewport3D, les
maillages et la géométrie 3D de base, les conteneurs qui reçoivent les objets 3D,
les différentes sources de lumière, les différentes caméras et leurs paramètres.

1 - Visualisation de la scène

La création d’une scène 3D avec l’objet le plus simple qu’est le triangle, ne peut se
faire qu’au travers d’un ensemble d’étapes qui sont:
• l’ajout d’un contrôle Viewport3D qui restitue le contenu 3D dans les limites de
disposition 2D de l’élément Viewport3D.
• l’ajout des objets 3D qui dérivent généralement des objets ModelVisual3D ou
ModelUIElement3D.
• l’ajout d’une source de lumière qui illumine la scène.
• l’application de textures à l’objet 3D qui déterminent l’apparence de sa surface.
• le positionnement de caméra, qui projette l’objet 3D dans une représentation
2D, et à partir de laquelle on peut visualiser la scène.
Cette liste d’étapes est juste une liste basique mais incontournable pour réaliser
une scène 3D.
Une scène 3D peut être très complexe en pratique, en contenant de nombreux
objets 3D, plusieurs sources d’illumination, de nombreuses caméras pour avoir
différents points de visualisation, ainsi que différents matériaux pour la composition
des objets. Tout cet ensemble concoure au réalisme d’une scène 3D mais oblige le
34 Guide pratique de la modélisation 3D avec WPF 4
programmeur à effectuer la même démarche quel que soit l’objet 3D à visualiser.

2 - Le contrôle Viewport3D

Le contenu graphique 3D dans WPF est encapsulé dans un élément Viewport3D


qui peut participer à la structure du document à deux dimensions. Le système
graphique traite Viewport3D comme un élément visuel à deux dimensions
semblable à bien d’autres éléments dans WPF. Le Viewport3D fonctionne comme
une fenêtre d’affichage dans une scène tridimensionnelle. Plus précisément, c’est
une surface sur laquelle une scène 3D est projetée. La classe Viewport3D expose
les propriétés suivantes:
• Camera qui définit un objet caméra qui projette le contenu en 3D de la fenêtre
Viewport3D sur la surface 2D de Viewport3D.
• Children qui est une collection des enfants Visual3D de Viewport3D.
Un Viewport3D est un contrôle (il hérite de FrameworkElement). Il contient
donc (figure 2-1) une collection de Visual3D dans sa propriété Children (propriété
implicite en XAML) c’est-à-dire tous les objets 3D qui composent la scène. Mais un
Viewport3D n’affiche rien sans caméra ni éclairage. Une caméra doit être définie
dans la propriété Camera.
Figure 2-1

Copyright 2011 Patrice REY


CHAPITRE 2 □ La scène 3D 35
En pratique, un Viewport3D sera ajouté dans une fenêtre de type Window
ou dans un contrôle de type UserControl. Généralement on l’encadre dans un
contrôle Border de façon à identifier la zone 3D. Ce Viewport3D doit avoir ses
propriétés Width et Height explicitement définies. De plus, sa propriété héritée
ClipToBounds sera fixée à true (la propriété UIElement.ClipToBounds définit une
valeur qui indique s’il faut découper le contenu de cet élément, ou le contenu
qui provient d’éléments enfants de cet élément, pour l’ajuster aux dimensions de
l’élément contenant; il s’agit d’une propriété de dépendance). La structure XAML
sera principalement de la forme suivante:

<Border BorderBrush=’Black’ BorderThickness=’1’ Width=’400’


Height=’400’ Canvas.Left=’12’ Canvas.Top=’68’
Background=’Black’>
<!-- le controle viewport3d -->
<Viewport3D ClipToBounds=’True’ Width=’400’ Height=’400’>
<!-- les ressources du viewport3d -->
<Viewport3D.Resources>
...
</Viewport3D.Resources>
<!-- les caméras du viewport3d -->
<Viewport3D.Camera>
...
</Viewport3D.Camera>
<!-- le conteneur des objets 3D du viewport3d -->
<ContainerUIElement3D>
...
</ContainerUIElement3D>
</Viewport3D>
</Border>

3 - La création de modèles 3D

La création d’objets 3D peut se faire de deux façons différentes: soit en utilisant la


classe ModelVisual3D, soit en utilisant la classe UIElement3D.

3.1 - La classe ModelVisual3D

La classe ModelVisual3D, issue du framework .NET 3.0, est une classe


bivalente (figure 2-2). Elle permet d’afficher un modèle défini par un Model3D
(GeometryModel3D ou Model3DGroup) spécifié dans la propriété Content. Elle
36 Guide pratique de la modélisation 3D avec WPF 4
peut contenir d’autres objets Visual3D spécifiés dans la propriété Children.
Figure 2-2

Les modèles composites peuvent être créés au moyen de la propriété Children,


mais également en définissant un contenu de type Model3DGroup dans la propriété
Content qui permet de regrouper plusieurs Model3D.
L’interactivité sur ModelVisual3D peut être obtenue au moyen du test d’atteinte
(hit testing). Le test d’atteinte est une technique de bas niveau que nous ne
détaillerons pas car elle est avantageusement remplacée par les fonctionnalités
de UIElement3D.
Voici un exemple de code représentant un modèle ModelVisual3D composite
regroupant plusieurs GeometryModel3D:

<ModelVisual3D>
<ModelVisual3D.Content>
Copyright 2011 Patrice REY

<Model3DGroup>
<GeometryModel3D ...></GeometryModel3D>
<GeometryModel3D ...></GeometryModel3D>
<GeometryModel3D ...></GeometryModel3D>
...
</Model3DGroup>
</ModelVisual3D.Content>
</ModelVisual3D>
CHAPITRE 2 □ La scène 3D 37
Voici un exemple de code représentant un modèle composite regroupant plusieurs
ModelVisual3D dans la propriété Children d’un ModelVisual3D:

<ModelVisual3D>
<ModelVisual3D>
...
</ModelVisual3D>
<ModelVisual3D>
...
</ModelVisual3D>
...
</ModelVisual3D>

3.2 - La classe UIElement3D

La classe abstraite UIElement3D est apparue dans le framework .NET 3.5,


accompagnée de deux classe héritées figure 2-3): ModelUIElement3D et
ContainerUIElement3D. Ces classes offrent une alternative intéressante à
ModelVisual3D car elles sont plus évoluées sur le plan fonctionnel et aussi car
chacune est spécialisée:
• UIElement3D hérite de Visual3D et apporte une gestion de haut niveau de
l’interactivité (gestion du focus, support du clavier, du stylet, du toucher et de
la souris); son interface est proche de celle de UIElement.
• ModelUIElement3D permet d’afficher un modèle défini par un Model3D
(GeometryModel3D ou Model3DGroup) spécifié dans la propriété Model.
• ContainerUIElement3D peut contenir d’autres objets Visual3D spécifiés dans
la propriété Children.
Il existe toujours deux techniques pour créer des modèles composites, mais ici en
exploitant deux classes différentes:
• assembler des Visual3D au sein d’un ContainerUIElement3D.
• assembler des Model3D au sein d’un Model3DGroup assigné à la propriété
Model d’un ModelUIElement3D.
Voici un exemple de modèle ModelUIElement3D composite regroupant plusieurs
GeometryModel3D:

<ModelUIElement3D>
<ModelUIElement3D.Model>
<Model3DGroup>
<GeometryModel3D></GeometryModel3D>
38 Guide pratique de la modélisation 3D avec WPF 4
<GeometryModel3D></GeometryModel3D>
<GeometryModel3D></GeometryModel3D>
...
</Model3DGroup>
</ModelUIElement3D.Model>
</ModelUIElement3D>
Figure 2-3

Voici un exemple de modèle composite regroupant plusieurs ContainerUIElement3D


dans la propriété Children d’un ContainerUIElement3D:

<ContainerUIElement3D>
<ContainerUIElement3D>
...
Copyright 2011 Patrice REY

</ContainerUIElement3D>
<ContainerUIElement3D>
...
</ContainerUIElement3D>
...
</ContainerUIElement3D>
CHAPITRE 2 □ La scène 3D 39

3.3 - La classe GeometryModel3D

La classe abstraite Model3D représente une description d’objet 3D. Un objet


Model3D peut être utilisé pour définir le visuel d’un objet Visual3D. Comme le
montre l’arbre d’héritage de la figure 2-4, les classes concrètes qui dérivent de
Model3D sont:
• GeometryModel3D qui définit un modèle basé sur une géométrie 3D.
• Model3DGroup qui permet l’utilisation de plusieurs modèles Model3D en tant
qu’unité.
Figure 2-4

Un objet GeometryModel3D définit un modèle basé sur une géométrie 3D. Il sert
à réaliser un modèle 3D au moyen de ses propriétés:
• Geometry qui représente une géométrie 3D.
• Material qui représente une matière pour la face avant spécifiée.
40 Guide pratique de la modélisation 3D avec WPF 4
• BackMaterial qui représente une matière pour la face arrière spécifiée
(propriété facultative).

4 - La géométrie Geometry3D

La classe Geometry3D est une classe abstraite qui sert de classe de base pour la
géométrie 3D. Les classes qui dérivent de cette classe de base abstraite définissent
des formes géométriques 3D. La classe d’objets Geometry3D peut être utilisée
pour le test d’atteinte et pour le rendu des données graphiques 3D.
Une géométrie 3D contient les données d’un modèle mais ne sait pas s’afficher
elle-même. Le seul type de géométrie hérité de la classe abstraite Geometry3D
est MeshGeometry3D. La figure 2-5 visualise l’arbre d’héritage de Geometry3D.
Figure 2-5

Copyright 2011 Patrice REY

La classe MeshGeometry3D définit le maillage d’un modèle 3D au moyen des


propriétés suivantes:
• Positions qui représente une collection des points formant les sommets (vertex)
du maillage (du type Point3D).
CHAPITRE 2 □ La scène 3D 41
• TriangleIndices qui représente une collection des indices des positions formant
les triangles des faces du maillage (du type Int32).
• Normals qui représente une collection des vecteurs normaux qui sont utilisés
pour le calcul de l’angle de réflexion des rayons lumineux sur la surface.
• TextureCoordinates qui représente une collection des points 2D de la texture
(le contenu dans le pinceau) correspondant aux positions des sommets du
maillage.
Pour que la production d’un contenu soit visible, la géométrie doit au moins définir
les propriétés Positions et TriangleIndices. Une valeur par défaut est calculée
automatiquement pour la propriété Normals. L’initialisation de TextureCoordinates
n’est pas nécessaire tant qu’une matière sans texture est utilisée.
La base des maillages est le triangle. Un modèle 3D est un assemblage de facettes
triangulaires. Le triangle est la surface la plus simple qui puisse exister. En effet,
trois points suffisent pour définir un triangle.
Les triangles du modèle sont définis au moyen des points formant les sommets
du maillage. La propriété TriangleIndices contient des séries de trois valeurs
correspondant aux indices des sommets (qui sont indiqués dans la propriété
Positions) formant chacune un triangle. L’ordre dans lequel les indices d’un triangle
sont spécifiés détermine le côté, avant ou arrière, sur lequel la face est représentée
par rapport à la position du point de vue courant. Pour être face à l’observateur,
les indices doivent être spécifiés dans l’ordre inverse des aiguilles d’une montre.
La figure 2-6 visualise la réalisation d’un modèle MeshGeometry3D constitué
d’un simple triangle. Le triangle est composé des trois points A(0,3,0), B(4,0,0)
et C(0,0,3). On affecte à chaque point un numéro d’indice, avec par exemple 0
pour A, 1 pour B et 2 pour C. Quand on observe le triangle, on veut que la face de
devant soit celle qui est vue (face qui comporterait une couleur ou une texture par
exemple). La démarche consiste à exprimer les points dans l’ordre des indices en
écrivant:
Positions = «0 3 0, 4 0 0, 0 0 3»
(la notation suivante est acceptée aussi: Positions = «0,3,0 4,0,0 0,0,3»)
Puis il faut exprimer l’ordre des indices par:
TriangleIndices = «0 2 1»
(la notation suivante est acceptée aussi: TriangleIndices = «0,2,1»)
L’ordre «0 2 1» est dans le sens antihoraire, donc la face du triangle que nous
voyons, sera la face qui comportera la couleur ou la texture. La face arrière de ce
triangle comportera une couleur ou une texture différente.
42 Guide pratique de la modélisation 3D avec WPF 4

Figure 2-6

sens
antihoraire

indice 0
A(0,3,0)

indice 1
B(4,0,0)
X

indice 2
C(0,0,3)

Pour afficher ce triangle, il faut l’intégrer à un Visual3D. En l’occurrence,


nous référençons l’objet MeshGeometry3D dans la propriété Content d’un
ModelVisual3D.
Dans la propriété Geometry de GeometryModel3D, on affecte le MeshGeometry3D
(avec les propriétés Positions et TriangleIndices).
Dans la propriété Material de GeometryModel3D, on ajoute un objet
Copyright 2011 Patrice REY

DiffuseMaterial dont sa propriété Brush est fixée à Red (la face avant du triangle
sera colorée en rouge).
Dans la propriété BackMaterial de GeometryModel3D, on ajoute un objet
DiffuseMaterial dont sa propriété Brush est fixée à Yellow (la face arrière du
triangle sera colorée en jaune).
CHAPITRE 2 □ La scène 3D 43
<ModelVisual3D>
<ModelVisual3D.Content>
<GeometryModel3D>
<GeometryModel3D.Geometry>
<MeshGeometry3D Positions=’0 3 0, 4 0 0, 0 0 3’
TriangleIndices=’0 2 1’></MeshGeometry3D>
</GeometryModel3D.Geometry>
<GeometryModel3D.Material>
<DiffuseMaterial Brush=’Red’></DiffuseMaterial>
</GeometryModel3D.Material>
<GeometryModel3D.BackMaterial>
<DiffuseMaterial Brush=’Yellow’></DiffuseMaterial>
</GeometryModel3D.BackMaterial>
</GeometryModel3D>
</ModelVisual3D.Content>
</ModelVisual3D>

La figure 2-7 visualise la réalisation d’un modèle MeshGeometry3D qui représente


un rectangle et qui est constitué par deux simples triangles. Le premier triangle
est composé des trois points A(4,2,0), B(4,0,0) et C(0,0,3). Le deuxième triangle
est composé des trois points C(0,0,3), D(0,2,3) et A(4,2,0). On affecte à chaque
point un numéro d’indice, avec par exemple 0 pour A, 1 pour B, 2 pour C et 3 pour
D. Quand on observe le rectangle, on veut que la face de devant soit celle qui est
vue (face qui comporterait une couleur ou une texture par exemple). La démarche
consiste à exprimer les points dans l’ordre des indices en écrivant:
Positions = «4 2 0, 4 0 0, 0 0 3, 0 2 3»
Puis il faut exprimer l’ordre des indices par:
TriangleIndices = «2 1 0, 0 3 2»
L’ordre «2 1 0» est dans le sens antihoraire, donc la face du triangle que nous
voyons, sera la face qui comportera la couleur ou la texture. La face arrière de ce
triangle comportera une couleur ou une texture différente. Il en est de même pour
l’ordre «0 3 2».
Pour afficher ce rectangle, il faut l’intégrer à un Visual3D. En l’occurrence,
nous référençons l’objet MeshGeometry3D dans la propriété Content d’un
ModelVisual3D.
Dans la propriété Geometry de GeometryModel3D, on affecte le MeshGeometry3D
(avec les propriétés Positions et TriangleIndices).
Dans la propriété Material de GeometryModel3D, on ajoute un objet
DiffuseMaterial dont sa propriété Brush est fixée à Red (la face avant du rectangle
44 Guide pratique de la modélisation 3D avec WPF 4
sera colorée en rouge).
Dans la propriété BackMaterial de GeometryModel3D, on ajoute un objet
DiffuseMaterial dont sa propriété Brush est fixée à Yellow (la face arrière du
rectangle sera colorée en jaune).
Figure 2-7

sens
antihoraire

indice 0
A(4,2,0)

indice 1
indice 3
D(0,2,3) B(4,0,0)
X

indice 2
C(0,0,3)

<ModelVisual3D>
<ModelVisual3D.Content>
<GeometryModel3D>
Copyright 2011 Patrice REY

<GeometryModel3D.Geometry>
<MeshGeometry3D Positions=’4 2 0, 4 0 0, 0 0 3, 0 2 3’
TriangleIndices=’2 1 0, 0 3 2’></MeshGeometry3D>
</GeometryModel3D.Geometry>
<GeometryModel3D.Material>
<DiffuseMaterial Brush=’Red’></DiffuseMaterial>
</GeometryModel3D.Material>
<GeometryModel3D.BackMaterial>
CHAPITRE 2 □ La scène 3D 45
<DiffuseMaterial Brush=’Yellow’></DiffuseMaterial>
</GeometryModel3D.BackMaterial>
</GeometryModel3D>
</ModelVisual3D.Content>
</ModelVisual3D>

5 - Matières et surfaces

Une matière est un objet hérité de la classe Material qui définit l’apparence
d’une surface, au moyen d’un pinceau spécifié dans sa propriété Brush (propriété
incluant tous les pinceaux 2D). Les pinceaux évolués contenant une image ou un
objet Visual doivent être appliqués à des modèles gérant le placage de texture.
La figure 2-8 visualise l’arbre d’héritage de la classe de base abstraite Material.

Figure 2-8
46 Guide pratique de la modélisation 3D avec WPF 4
Les classes dérivées de la classe Material sont:
• DiffuseMaterial qui représente une surface autorisant l’application d’un
pinceau 2D, tel qu’un SolidColorBrush ou un TileBrush, à un modèle 3D éclairé
de manière diffuse.
• EmissiveMaterial qui représente une surface autorisant l’application d’un
Brush à un modèle 3D afin qu’il soit compris dans les calculs de l’éclairage
comme si les surfaces émettaient une lumière égale à la couleur du Brush.
• SpecularMaterial qui représente une surface autorisant l’application d’un
pinceau 2D, tel qu’un SolidColorBrush ou un TileBrush, à un modèle 3D éclairé
de manière spéculaire.
• MaterialGroup qui représente un Material qui forme un élément composite
de la collection des matières.

5.1 - La surface mate

Une surface mate est définit par un objet DiffuseMaterial. La caractéristique d’une
surface mate est de diffuser la lumière qu’elle reçoit et dont le rendu est fonction
de l’éclairage. Les parties à l’ombre sont noires.
La classe DiffuseMaterial expose principalement les propriétés suivantes:
• Brush qui représente le pinceau utilisé.
• Color qui définit la couleur réfléchie pour la texture de la matière avec un
éclairage normal.
• AmbientColor qui définit la couleur réfléchie pour la texture de la matière avec
un éclairage de type AmbientLight.
Par exemple, la face d’un rectangle peinte en rouge s’exprimera en XAML par:

<ModelVisual3D>
<ModelVisual3D.Content>
<GeometryModel3D>
<GeometryModel3D.Geometry>
<MeshGeometry3D Positions=’4 2 0, 4 0 0, 0 0 3, 0 2 3’
Copyright 2011 Patrice REY

TriangleIndices=’2 1 0, 0 3 2’></MeshGeometry3D>
</GeometryModel3D.Geometry>
<GeometryModel3D.Material>
<DiffuseMaterial Brush=’Red’></DiffuseMaterial>
</GeometryModel3D.Material>
</GeometryModel3D>
</ModelVisual3D.Content>
</ModelVisual3D>
CHAPITRE 2 □ La scène 3D 47

5.2 - La surface lumineuse

Une surface lumineuse est définit par un objet EmissiveMaterial. Cette surface
lumineuse est indépendante de l’éclairage ambiant. Mais un objet avec une surface
lumineuse n’illumine pas les éléments 3D présents dans son entourage immédiat.
La classe EmissiveMaterial expose principalement les propriétés suivantes:
• Brush qui représente le pinceau utilisé.
• Color qui définit la couleur réfléchie pour la texture de la matière.
Par exemple, la face d’un rectangle peinte en jaune s’exprimera en XAML par:

<ModelVisual3D>
<ModelVisual3D.Content>
<GeometryModel3D>
<GeometryModel3D.Geometry>
<MeshGeometry3D Positions=’4 2 0, 4 0 0, 0 0 3, 0 2 3’
TriangleIndices=’2 1 0, 0 3 2’></MeshGeometry3D>
</GeometryModel3D.Geometry>
<GeometryModel3D.Material>
<EmissiveMaterial Brush=’Yellow’></EmissiveMaterial >
</GeometryModel3D.Material>
</GeometryModel3D>
</ModelVisual3D.Content>
</ModelVisual3D>

5.3 - Combinaison de matières

Les matières peuvent être combinées au sein d’un objet MaterialGroup, formant
alors une matière composite. La propriété Children de MaterialGroup contient
une collection d’objets Material enfants qui constituent la matière composite.Par
exemple, un MaterialGroup permet de définir une surface unie ornée de motifs
lumineux visibles même dans l’ombre. Un objet DiffuseMaterial définit la surface
unie. Un objet DrawingBrush, utilisé par un objet EmissiveMaterial, définit les
motifs lumineux. Cela s’exprimera en XAML par:

<ModelVisual3D>
<ModelVisual3D.Content>
<GeometryModel3D>
<GeometryModel3D.Geometry>
<MeshGeometry3D Positions=’4 2 0, 4 0 0, 0 0 3, 0 2 3’
48 Guide pratique de la modélisation 3D avec WPF 4
TriangleIndices=’2 1 0, 0 3 2’></MeshGeometry3D>
</GeometryModel3D.Geometry>
<GeometryModel3D.Material>
<MaterialGroup>
<DiffuseMaterial Brush=’Yellow’></DiffuseMaterial >
<EmissiveMaterial>
<EmissiveMaterial.Brush>
<DrawingBrush>
<DrawingBrush.Drawing>
<GeometryDrawing Brush=’MediumBlue’>
...
</GeometryDrawing>
</DrawingBrush.Drawing>
</DrawingBrush>
</EmissiveMaterial.Brush>
</EmissiveMaterial>
</MaterialGroup>
</GeometryModel3D.Material>
</GeometryModel3D>
</ModelVisual3D.Content>
</ModelVisual3D>

5.4 - La réflexion spéculaire

Un objet SpecularMaterial permet l’application d’un pinceau 2D, tel qu’un


SolidColorBrush ou un TileBrush, à un modèle 3D éclairé de manière spéculaire.
La classe SpecularMaterial gère la réflexion spéculaire en ajoutant de la brillance à
une surface définie avec d’autres matières. Elle s’utilise toujours en association avec
d’autres objets Material au sein d’un MaterialGroup. La brillance est constituée de
reflets en fonction de l’éclairage et de la position du point de vue.
La classe SpecularMaterial expose principalement les propriétés suivantes:
• SpecularPower qui indique l’intensité des reflets.
• Color qui indique la couleur des reflets.
Cela s’exprimera par exemple en XAML par:
Copyright 2011 Patrice REY

<ModelVisual3D>
<ModelVisual3D.Content>
<GeometryModel3D>
<GeometryModel3D.Geometry>
<MeshGeometry3D Positions=’4 2 0, 4 0 0, 0 0 3, 0 2 3’
TriangleIndices=’2 1 0, 0 3 2’></MeshGeometry3D>
CHAPITRE 2 □ La scène 3D 49
</GeometryModel3D.Geometry>
<GeometryModel3D.Material>
<MaterialGroup>
<DiffuseMaterial Brush=’Yellow’></DiffuseMaterial >
<SpecularMaterial SpecularPower=’100.0’ Brush=’White’/>
</MaterialGroup>
</GeometryModel3D.Material>
</GeometryModel3D>
</ModelVisual3D.Content>
</ModelVisual3D>

6 - L’éclairage de la scène

L’éclairage est géré par des objets dérivés de la classe de base abstraite Light. La
figure 2-9 visualise l’arbre d’héritage de la classe Light. WPF gère l’éclairage par un
objet Model3D d’un type particulier, invisible, utilisé pour calculer les couleurs des
éléments de la scène. C’est pour cette raison que l’objet Light hérite de la classe
Model3D.
Figure 2-9

Les classes dérivées de la clase abstraite Light sont:


• DirectionLight qui représente une lumière qui projette son effet dans une
direction spécifiée par un Vector3D.
• AmbientLight qui représente une lumière qui applique uniformément de la
50 Guide pratique de la modélisation 3D avec WPF 4
lumière sur les objets, indépendamment de leur forme.
• PointLightBase qui est une classe de base abstraite qui représente un objet
lumière comportant une position dans l’espace et projetant sa lumière dans
toutes les directions.
La classe PointLightBase possède comme classes dérivées les classes:
• PointLight qui représente une source de lumière qui a une position spécifiée
dans l’espace et qui projette sa lumière dans toutes les directions.
• SpotLight qui représente une lumière qui projette son effet dans une zone
conique selon une direction spécifiée.
Tous ces objets représentant un éclairage, expose la propriété Color qui définit la
couleur de l’éclairage.
L’objet AmbientLight produit un éclairage uniforme, sans ombre, avec une position
indéterminée.
L’objet DirectionalLight produit un éclairage similaire aux rayons solaires. Les rayons
sont parallèles comme s’ils provenaient d’une source très éloignée. Sa position
d’éclairage est indéterminée. Sa propriété Direction détermine l’orientation des
rayons lumineux au moyen d’un vecteur. Généralement la puissance de l’éclairage
directionnel est fixe. La seule façon de l’augmenter consiste à positionner plusieurs
objets DirectionLight.
Les objets PointLight et SpotLight produisent un éclairage similaire à une lampe
d’intérieur qui rayonne autour d’une position donnée. Ces deux objets exposent
principalement les propriétés suivantes:
• Position qui définit l’emplacement de la source d’éclairage (une position de
type Point3D).
• Range qui représente la portée maximale de la source d’éclairage; la portée a
une valeur infinie par défaut; les zones en dehors de cette portée ne sont pas
éclairées (dans le cas d’une valeur finie pour la portée maximale).
• ConstantAttenuation qui représente une valeur de constante par laquelle
l’intensité de la lumière diminue sur la distance; en agissant comme un facteur
de division, la luminosité de la lampe peut être réduite.
Copyright 2011 Patrice REY

• LinearAttenuation qui représente une valeur qui spécifie la diminution linéaire


de l’intensité de la lumière sur la distance; en agissant comme un facteur
multiplicateur de la distance, la lumière peut être réduite.
• QuadraticAttenuation qui représente une valeur qui spécifie la diminution de
l’effet de la lumière sur la distance, calculée par une opération quadratique; en
agissant comme facteur multiplicateur du carré de la distance, la lumière peut
être réduite.
CHAPITRE 2 □ La scène 3D 51
Si l’objet PointLight rayonne dans toutes les directions, l’objet SpotLight, quant à
lui, réduit son éclairage à un cône, en exposant des propriétés supplémentaires
qui sont:
• Direction qui définit un Vector3D qui spécifie la direction dans laquelle l’objet
SpotLight projette sa lumière.
• OuterConeAngle qui définit un angle qui spécifie la proportion d’une projection
conique d’un objet SpotLight en dehors de laquelle la lumière n’éclaire pas les
objets dans la scène.
• InnerConeAngle qui définit un angle qui spécifie la proportion d’une projection
conique d’un objet SpotLight dans laquelle la lumière éclaire entièrement les
objets dans la scène.

7 - Les caméras

La représentation d’une scène 3D dépend de la position du point de vue, et de la


direction du regard. Ces paramètres sont gérés par un objet Camera. La projection
2D d’une scène 3D est définit par la caméra qui spécifie quelle partie de la scène
3D devant être restituée par l’élément Viewport3DVisual ou Viewport3D.
La classe de base abstraite Camera gère les différents types de caméra. La figure
2-10 visualise son arbre d’héritage. Ses classes dérivées sont:
• ProjectionCamera qui est une classe de base abstraite pour les caméras à
projection perspective et à projection orthographique (ou parallèle).
• MatrixCamera qui définit une caméra qui spécifie les transformations de
projection et d’affichage comme des objets de type Matrix3D.
La classe abstraite ProjectionCamera possède deux classes dérivées qui sont:
• PerspectiveCamera qui représente une caméra avec une projection de type
perspective.
• OrthographicCamera qui représente une caméra avec une projection de type
orthographique (ou parallèle).
Un objet PerspectiveCamera définit une projection avec de la perspective c’est-à-
dire contenant un point vers lequel convergent toutes les lignes de fuite.
Un objet OrthographicCamera définit une projection orthographique sans
perspective. Les dimensions de la représentation d’un élément sont fixes et
indépendantes de sa position.
Les classes PerspectiveCamera et OrthographicCamera exposent principalement
les propriétés suivantes:
• Position qui définit la position de la caméra en coordonnées universelles.
52 Guide pratique de la modélisation 3D avec WPF 4
• LookDirection qui définit un vecteur Vector3D qui représente la direction de
visée de la caméra en coordonnées universelles.
• UpDirection qui définit un vecteur Vector3D qui indique l’inclinaison de la
caméra; par défaut, sa valeur est (0,1,0) ce qui signifie que la verticale de
l’image correspond à l’axe Y, valeurs positives vers le haut.
• NearPlaneDistance et FarPlaneDistance qui indiquent les limites de la zone de
rendu des éléments visuels respectivement à l’avant-plan et à l’arrière-plan par
rapport à la caméra; les parties des éléments au-delà des limites sont invisibles;
les valeurs par défaut sont respectivement 0.125 et l’infini.
De plus, l’objet PerspectiveCamera expose la propriété FieldOfView qui détermine
le champ de vision horizontal de la caméra. Une valeur élevée correspond à une vue
de type grand-angle, et une valeur faible correspond à une vue de type téléobjectif.
La figure 2-11 visualise les principales propriétés de la caméra perspective.
Figure 2-10

Copyright 2011 Patrice REY


CHAPITRE 2 □ La scène 3D 53
Figure 2-11 FarPlaneDistance

NearPlaneDistance

UpDirection

Y
LookDirection
Z

X FieldOfView
centre de
projection
(caméra)
plan de
projection volume
d’observation
plan de loin
Figure 2-12
FarPlaneDistance
NearPlaneDistance

plan de
projection
UpDirection Width

Y
LookDirection
Z

X
centre de
projection à
l’infini (caméra)
plan de volume
près d’observation plan de
loin
54 Guide pratique de la modélisation 3D avec WPF 4
Quant à l’objet OrthographicCamera, il expose la propriété Width qui représente
la largeur de la zone d’affichage. La figure 2-12 visualise les principales propriétés
de la caméra orthographique.

Copyright 2011 Patrice REY


CHAPITRE 3

La modélisation du cube

Les modèles 3D sont composés par des assemblages dont l’assemblage de base
est le triangle. Deux triangles qui sont joints par leur hypoténuse forment une
facette rectangulaire.
Nous allons voir dans ce chapitre comment réaliser des assemblages basiques avec
des triangles et comment les visualiser. A partir de ces assemblages, nous verrons
la réalisation du modèle 3D basique qu’est le cube, avec des faces texturées
uniformes et des faces texturées différentes.

1 - La facette triangulaire

Dans la construction 3D, la base des maillages est le triangle. Un modèle 3D est un
assemblage de facettes triangulaires. Le triangle est la surface la plus simple qui
puisse exister. En effet, trois points suffisent pour définir un triangle.
Dans le fichier Index02.xaml.cs, nous allons modéliser une facette triangulaire, en
lui appliquant sur chaque face une couleur différente. Puis nous allons faire tourner
la scène dans tous les sens avec l’utilisation de la souris pour voir les deux côtés du
triangle. La figure 3-1 visualise géométriquement la scène 3D telle qu’elle va être
réalisée. Il est important de comprendre que pour visualiser une scène 3D, il faut
exécuter un certain nombre d’étapes comme on l’a vu au chapitre précédent. Le
triangle aura des côtés de longueur de 2 unités. Il sera positionné avec son angle
droit au centre du repère.
La figure 3-2 visualise géométriquement la position de la caméra et de ses
caractéristiques. Il s’agit ici d’une caméra de type perspective, positionnée en
(0,0,5). Le LookDirection représente la direction de visée de la caméra, que l’on
définit en coordonnées opposées à celles de la caméra. Le UpDirection définit la
direction vers le haut de la caméra que l’on définit à (0,1,0) pour une direction
56 Guide pratique de la modélisation 3D avec WPF 4
Figure 3-1 Y

(0,2,0) indice 2

face de devant face arrière


gris clair gris foncé
(2,0,0) indice 1
(0,0,0) indice 0 X

angle 30°

(0,0,5) caméra
Z
Figure 3-2 Y

FarPlaneDistance
= infini par défaut
Copyright 2011 Patrice REY

X
LookDirection
(0,0,-5)

UpDirection angle 30°


(0,1,0)
NearPlaneDistance
= 0.125 par défaut

(0,0,5) caméra
Z
CHAPITRE 3 □ La modélisation du cube 57
verticale vers le haut.
Le FieldOfView représente le champ de vision horizontal de la caméra (60 degrés
ici). Tous les objets qui se trouvent entre la distance NearPlaneDistance et
FarPlaneDistance feront l’objet d’un rendu 2D dans la mesure où ils appartiennent,
complètement ou en partie, au volume d’observation.
Dans le fichier Index02.xaml, positionnons tout cela en vue d’obtenir un rendu de
la scène. Nous allons employer la démarche qui a été vue au chapitre 2 pour la
visualisation.
On commence par ajouter un contrôle de rendu 3D x_viewport1, de type
Viewport3D, avec ses propriétés With et Height fixées explicitement (400 pixels
dans notre exemple). La propriété ClipToBounds est fixée à true pour éviter tous
les débordements de la zone de rendu. La couleur du fond de la zone de rendu
est celle du contrôle x_border1, de type Border (propriété Background fixée à
WhiteSmoke).

<Border BorderBrush=’Black’ BorderThickness=’1’ Width=’402’


Height=’400’
Canvas.Left=’12’ Canvas.Top='79' Background='WhiteSmoke'
Name='x_border1'>
<Viewport3D ClipToBounds=’True’ Width='400' Height=’400’
Name=’x_viewport1’>
.....
</Viewport3D >
</Border >

Pour que la zone de rendu affiche quelque chose, il faut ajouter une caméra
(propriété Camera du Viewport3D). Pour cela on ajoute une caméra x_camera1
à projection perspective, de type PerspectiveCamera. On fixe sa position dans
l’espace 3D (Position = «0,0,5», de type Point3D), son axe de visée est représenté
par un vecteur (LookDirection = «0,0,-5», de type Vector3D), sa direction vers le
haut est représentée par un vecteur (UpDirection = «0 1 0») et l’angle de vue est
fixé à 60 degrés (FieldOfView = «60»).
Pour que la caméra fixe en permanence l’origine du repère 3D, il suffit de fixer
l’orientation de la visée par le vecteur qui va du point (0,0,5) qui correspond à la
position de la caméra, au point (0,0,0) qui est l’origine. Cela se traduit donc par un
Vector3D(0,0,-5) pour une position de caméra de (0,0,5) soit le signe opposé aux
trois coordonnées de la caméra. Le UpDirection de la caméra est celui de l’axe Y
pour signifier aucune inclinaison de la caméra. Son inclinaison est donc représentée
par le Vector3D(0,1,0).
58 Guide pratique de la modélisation 3D avec WPF 4
<Border BorderBrush=’Black’ BorderThickness=’1’ Width=’402’
Height=’400’
Canvas.Left=’12’ Canvas.Top='79' Background='WhiteSmoke'
Name='x_border1'>
<Viewport3D ClipToBounds=’True’ Width='400' Height=’400’
Name=’x_viewport1’>
<!-- cameras ****************************** -->
<Viewport3D.Camera>
<PerspectiveCamera x:Name=’x_camera1’ Position=’0,0,5’
LookDirection=’0,0,-5’ FieldOfView=’60’
UpDirection=’0 1 0’></PerspectiveCamera>
</Viewport3D.Camera>
.....
</Viewport3D >
</Border >

Les objets 3D sont positionnés dans un objet ContainerUIElement3D qui est affecté
à la propriété Children de Viewport3D (propriété implicite en XAML donc elle n’a
pas besoin d’être mentionnée avec <Viewport3D.Children>). On choisit un objet
ModelUIElement3D pour restituer un modèle 3D qui prend en charge l’entrée, le
focus et les événements.

<Viewport3D ClipToBounds=’True’ Width=’400’ Height=’400’


Name=’x_viewport1’>
...
<!-- conteneur des modeles **************** -->
<ContainerUIElement3D>
<ModelUIElement3D>
...
</ModelUIElement3D>
</ContainerUIElement3D>
...
</Viewport3D>

La propriété implicite Model de ModelUIElement3D (<ModelUIElement3D.Model>)


Copyright 2011 Patrice REY

est constituée d’un objet x_objets1, de type Model3DGroup, qui est composé des
différents maillages qui sont apportés à la scène 3D.

<Viewport3D ClipToBounds=’True’ Width=’400’ Height=’400’


Name=’x_viewport1’>
...
<!-- conteneur des modeles **************** -->
CHAPITRE 3 □ La modélisation du cube 59
<ContainerUIElement3D>
<ModelUIElement3D>
<Model3DGroup x:Name=’x_objets1’>
...
</Model3DGroup>
</ModelUIElement3D>
</ContainerUIElement3D>
...
</Viewport3D>

Un éclairage x_lumiere1, de type AmbientLight, permet d’éclairer la scène. On fixe


la propriété Color de AmbientLight à White pour un éclairage blanc.

<!-- conteneur des modeles **************** -->


<ContainerUIElement3D x:Name='x_scene1'>
<ModelUIElement3D>
<Model3DGroup x:Name=’x_objets1’>
<Model3DGroup x:Name=’x_lumiere1’>
<AmbientLight Color=’White’></AmbientLight>
</Model3DGroup>
...

On positionne un groupe x_triangle, de type Model3DGroup, qui va contenir la


définition du triangle telle qu’elle apparait sur la figure 3-1.

<!-- conteneur des modeles **************** -->


<ContainerUIElement3D x:Name='x_scene1'>
<ModelUIElement3D>
<Model3DGroup x:Name=’x_objets1’>
<Model3DGroup x:Name=’x_lumiere1’>
<AmbientLight Color=’White’></AmbientLight>
</Model3DGroup>
<Model3DGroup x:Name=’x_triangle’>
...
</Model3DGroup>
</Model3DGroup>
</ModelUIElement3D>
</ContainerUIElement3D>

Un objet GeometryModel3D, intitulé x_triangle_geomodel3d, constitue


le modèle 3D du triangle. La propriété Geometry de GeometryModel3D
(<GeometryModel3D.Geometry>) contient la définition du maillage du triangle. Ce
60 Guide pratique de la modélisation 3D avec WPF 4
maillage est un MeshGeometry3D avec sa propriété Positions fixée à «0 0 0, 2 0
0, 0 2 0», et sa propriété TriangleIndices fixée à «0 1 2». La propriété Material de
GeometryModel3D (<GeometryModel3D.Material>) contient la définition de la
surface avant du triangle. On l’initialise avec une surface mate x_surface_1 peinte en
gris clair (Brush = «LightGray»). La propriété BackMaterial de GeometryModel3D
(<GeometryModel3D. BackMaterial>) contient la définition de la surface arrière
du triangle. On l’initialise avec une surface mate peinte en gris foncé (Brush =
«DarkGray»).

<Model3DGroup x:Name=’x_triangle’>
<GeometryModel3D x:Name=’x_triangle_geomodel3d’>
<GeometryModel3D.Material>
<DiffuseMaterial x:Name=’x_surface_1’
Brush='LightGray'></DiffuseMaterial>
</GeometryModel3D.Material>
<GeometryModel3D.BackMaterial>
<DiffuseMaterial Brush='DarkGray'></DiffuseMaterial>
</GeometryModel3D.BackMaterial>
<GeometryModel3D.Geometry>
<MeshGeometry3D
Positions=’0 0 0, 2 0 0, 0 2 0’
TriangleIndices=’0 1 2’></MeshGeometry3D>
</GeometryModel3D.Geometry>
</GeometryModel3D>
</Model3DGroup>

La figure 3-3 visualise le triangle dans sa position de départ avec la caméra qui,
depuis sa position, permet d’obtenir le rendu.
Pour faire tourner la scène dans les 3 dimensions avec la souris, on ajoute
l’implémentation d’un TrackBall. Cette implémentation sera détaillée à la fin du
livre dans la section concernant les manipulations 3D.
Pour faire tourner la scène, il suffit de cliquer gauche avec la souris sur le triangle,
de maintenir ce clic tout en bougeant la souris pour que la scène puisse tourner.
Copyright 2011 Patrice REY

Ce sont les gestionnaires d’événements MouseLeftButtonDown, MouseMove et


MouseLeftButtonUp attachés à x_viewport1 qui gèrent l’implémentation d’un
TrackBall. La figure 3-4 montre des clichés du triangle lors de la rotation de la
scène. Le curseur prend la forme de quatre flèches lors de ces rotations.

<Viewport3D ClipToBounds=’True’ Width=»400» Height=’400’


Name=’x_viewport1’
CHAPITRE 3 □ La modélisation du cube 61
MouseLeftButtonDown='x_viewport1_MouseLeftButtonDown'
MouseMove='x_viewport1_MouseMove'
MouseLeftButtonUp='x_viewport1_MouseLeftButtonUp'>
.....
</Viewport3D >
Figure 3-3

Figure 3-4
62 Guide pratique de la modélisation 3D avec WPF 4

2 - La facette rectangulaire

Dans le fichier Index02.xaml.cs, nous allons modéliser une facette rectangulaire,


en lui appliquant sur chaque face une couleur différente. Puis nous allons faire
tourner la scène dans tous les sens avec l’utilisation de la souris pour voir les deux
côtés du rectangle. La figure 3-5 visualise géométriquement la scène 3D telle
qu’elle va être réalisée. Il est important de comprendre que pour visualiser une
scène 3D, il faut exécuter un certain nombre d’étapes comme on l’a vu au chapitre
précédent. Le rectangle aura des côtés de 6 unités pour la longueur et 4 unités pour
la largeur. La face du dessus du rectangle aura une couleur uniforme gris clair et la
face du dessous une couleur uniforme gris foncé. La caméra sera positionnée aux
coordonnées (3,5,7) et aura son axe de visée (propriété LookDirection), représenté
par le vecteur (-3,-5,-7), fixant l’origine du repère.
Figure 3-5 Y

texture gris foncé


face arrière

gle 30° (0,0,0) (6,0,0)


(0,0) indice 3
indice 0
X
(1,0) Copyright 2011 Patrice REY

(0,0,4)
indice 1 (6,0,4)
(0,1) (1,1) indice 2

Z texture gris clair


face avant
CHAPITRE 3 □ La modélisation du cube 63
Dans le fichier Index06.xaml, le rectangle dans la zone de rendu est visible
en fonction de la position de la caméra et de ses caractéristiques. Si, lors de la
construction du rectangle, des erreurs sont commises dans la définition de la
géométrie du rectangle, le concepteur de vues de Visual Studio n’affiche pas le
rectangle.
La figure 3-6 montre le concepteur de vues. Le bas de la figure 3-6 schématise le
rectangle dans le repère (OX,OY,OZ) ainsi que la position de la caméra avec son axe
de visée. Il ne faut pas oublier qu’ici, on est avec une caméra de type perspective
(et non orthographique). Cela induit donc, en projection perspective, un étirement
du rectangle côté droit (axe OX) pour la position de caméra (-3,-5,-7).
Définir une géométrie en forme de rectangle est équivalent à définir deux
géométries triangulaires, accolées par leur hypoténuse. La propriété Geometry
de GeometryModel3D est définit par un objet MeshGeometry3D qui contient la
définition géométrique du rectangle.
Cet objet MeshGeometry3D possède une propriété Positions qui est une collection
de points, de type Point3D, stockant les points de contour du rectangle.
Il possède aussi une propriété TriangleIndices qui contient l’ordre des indices
définissant les triangles de composition. Il s’agit là aussi d’une collection mais de
type int.

<Model3DGroup x:Name='x_rectangle'>
<GeometryModel3D x:Name='x_rectangle_geo'>
<GeometryModel3D.BackMaterial>
<DiffuseMaterial Brush='DarkGray' />
</GeometryModel3D.BackMaterial>
<GeometryModel3D.Geometry>
<MeshGeometry3D
Positions='0 0 0, 0 0 4, 6 0 4, 6 0 0'
TriangleIndices='0 1 2, 2 3 0' />
</GeometryModel3D.Geometry>
<GeometryModel3D.Material>
<DiffuseMaterial
x:Name='diffuseMaterial1'
Brush='LightGray' />
</GeometryModel3D.Material>
</GeometryModel3D>
</Model3DGroup>
64 Guide pratique de la modélisation 3D avec WPF 4
Figure 3-6

positionnement du positionnement de la
rectangle de 6 par 4 unités caméra
Y Y
Copyright 2011 Patrice REY

6
4
X X

Z Z
CHAPITRE 3 □ La modélisation du cube 65
La première étape consiste à faire le relevé des positions des bords du rectangle.
Le sens à choisir est celui du sens contraire des aiguilles d’une montre. Comme
le visualise la figure 3-7, on fait un relevé des points avec leurs coordonnées
universelles en leur attribuant un indice croissant (commençant par 0). Ici, on a
(0,0,0) avec l’indice 0, (0,0,4) avec l’indice 1, (6,0,4) avec l’indice 2, et (6,0,0) avec
l’indice 3. Donc la propriété Positions sera égale à Positions= «0 0 0, 0 0 4, 6 0 4, 6
0 0».
Figure 3-7 (6,0,0)
(0,0,0)
indice 0 indice 3

(0,0,4)
indice 1 (6,0,4)
indice 2
on relève les positions des bords du rectangle en coordonnées
universelles (avec le sens contraire des aiguilles d’une montre):
Positions="0 0 0, 0 0 4, 6 0 4, 6 0 0"
ngle 30°
La deuxième étape consiste à établir le relevé de chaque triangle par les indices
qui le constituent, et ce, en utilisant toujours le sens contraire des aiguilles d’une
montre. On a un premier triangle qui est composé par des points aux indices 0, 1
et 2. On a un second triangle qui est composé par des points aux indices 2, 3 et 0.
Donc la propriété TriangleIndices s’exprimera de la façon suivante: TriangleIndices=
«0 1 2, 2 3 0» (figure 3-8).
Figure 3-8
(0,0,0) (6,0,0)
indice 0 (0,0,0) indice 3
indice 0

(0,0,4) (6,0,4)
indice 1 indice 2 (6,0,4)
indice 2
TriangleIndices="0 1 2, 2 3 0"
66 Guide pratique de la modélisation 3D avec WPF 4
La face rectangulaire étant géométriquement définie, on lui ajoute une texture
sous forme d’une couleur gris clair sur le dessus. On affecte à la propriété Material
de GeometryModel3D, un objet DiffuseMaterial qui autorise l’application d’un
pinceau 2D, tel qu’un SolidColorBrush ou TileBrush, à un modèle 3D éclairé de
manière diffuse. La propriété Brush de DiffuseMaterial reçoit un SolidColorBrush
de teinte LightGray. Puis on ajoute à la face rectangulaire une texture sous forme
d’une couleur gris foncé sur le dessous (face arrière du rectangle). On affecte à la
propriété BackMaterial de GeometryModel3D, un objet DiffuseMaterial dont la
propriété Brush est définie par un DarkGray.
Comme vous avez pu le constater, on définit à chaque fois une propriété Material
(propriété obligatoire) et une propriété BackMaterial (propriété facultative). Si la
propriété BackMaterial n’est pas définie, alors le Viewport3D n’effectue pas de
rendu pour la face arrière du rectangle. De ce fait, la face arrière ne sera pas visible.
C’est pour cela que nous vous conseillons au début de définir systématiquement
la propriété BackMaterial pour une meilleure compréhension des géométries
réalisées.
Le résultat obtenu est visualisé sur la figure 3-9. Le rectangle peut être vu sous
différents angles en faisant varier la position de la caméra avec l’imitation du
TrackBall par la souris.
La figure 3-10 schématise différentes vues, en projection perspective, dans
lesquelles on a ajouté les axes du repère pour une meilleure compréhension,
avec à gauche une vue plongeante sur le dessus du rectangle, et à droite une vue
plongeante sur le dessous du rectangle.
Figure 3-9

Copyright 2011 Patrice REY


CHAPITRE 3 □ La modélisation du cube 67
Figure 3-10

Z Y
X

Z
X

3 - Le cube

La modélisation d’un cube peut se faire de différentes façons. Nous allons aborder,
dans un premier temps, la modélisation d’un cube comme un objet unique avec
une couleur uniforme (ou une texture uniforme) appliquée à tout le cube. Puis
nous verrons, dans un second temps, comment modéliser un cube, face par face,
de façon à colorer (ou texturer) les faces différemment. Enfin nous verrons, dans
un troisième temps, par la généralisation de la modélisation du cube, comment
modéliser un cube de façon générique.

3.1 - Un cube avec des faces uniformes

Un cube est un volume composé de six faces. Chaque face possède quatre points
qui représentent les coins, et chaque face peut être divisée en deux triangles
(facette rectangulaire comme on l’a vu précédemment).
De façon à pouvoir se repérer facilement et en vue d’une généralisation, nous
allons construire un cube dont les côtés auront une longueur de 1 unité.
La figure 3-11 schématise le cube géométriquement avec la position de ses points.
Il y a 8 points qui permettent de définir 6 faces rectangulaires différentes. La
méthode de modélisation consiste à repérer les six faces par leurs coordonnées
universelles.
68 Guide pratique de la modélisation 3D avec WPF 4
Figure 3-11
18 (0,1,0) 17 (1,1,0)

face face
gauche dessus

14 (0,1,0) 13 (0,1,1) Y 19 (0,1,1) 16 (1,1,1)

15 (0,0,0) 12 (0,0,1) (0,1,0) (1,1,0) face


arrière

10 (1,1,0) 9 (0,1,0)

(0,1,1) (1,1,1)
11 (1,0,0) 8 (0,0,0)

(0,0,0) (1,0,0)
X

(0,0,1) (1,0,1) 6 (1,1,1) 5 (1,1,0)

face
droite

Z
7 (1,0,1) 4 (1,0,0)
22 (0,0,1) 21 (1,0,1)
2 (0,1,1) 1 (1,1,1)

face face
avant dessous
Copyright 2011 Patrice REY

3 (0,0,1) 0 (1,0,1) 23 (0,0,0) 20 (1,0,0)

La propriété Positions du MeshGeometry3D va stocker pour chaque face la


position des points. La propriété TriangleIndices du MeshGeometry3D va stocker
pour chaque face l’ordre des indices qui définissent les triangles. La propriété
TextureCoordinates du MeshGeometry3D va stocker les positions 2D du placage
CHAPITRE 3 □ La modélisation du cube 69
de la texture. De façon à différencier les faces, on leur applique un dégradé de
couleurs (un objet RadialGradientBrush au lieu d’un objet SolidColorBrush dans la
propriété Brush du DiffuseMaterial). Le mappage de ce dégradé se fait par l’ajout
de la propriété TextureCoordinates, fixée ici à «1 1 1 0 0 0 0 1». Nous verrons juste
après avoir modéliser le cube, la façon de mapper le dégradé.
Commençons par la face avant du cube, on applique les indices de 0 à 3 pour les
points du bord du carré, dans le sens contraire des aiguilles d’une montre (ce qui
veut dire que la face que l’on voit sera la face de devant). La figure 3-12 visualise le
relevé des points et des indices.
Figure 3-12
2 (0,1,1) 1 (1,1,1)

face
avant

3 (0,0,1) 0 (1,0,1)

Positions = « 1 0 1, 1 1 1, 0 1 1, 0 0 1 »
TriangleIndices = « 0 1 2, 2 3 0 »
TextureCoordinates = « 1 1 1 0 0 0 0 1 » face avant

On continue avec la face droite du cube, on applique les indices de 4 à 7 pour les
points du bord du carré, dans le sens contraire des aiguilles d’une montre (ce qui
veut dire que la face que l’on voit sera la face de devant). La figure 3-13 visualise le
relevé des points et des indices.
Figure 3-13
6 (1,1,1) 5 (1,1,0)

face
droite

7 (1,0,1) 4 (1,0,0)

Positions = « 1 0 0, 1 1 0, 1 1 1, 1 0 1 »
TriangleIndices = « 4 5 6, 6 7 4 » face droite
TextureCoordinates = « 1 1 1 0 0 0 0 1 »
On continue avec la face arrière du cube, on applique les indices de 8 à 11 pour les
points du bord du carré, dans le sens contraire des aiguilles d’une montre (ce qui
veut dire que la face que l’on voit sera la face de devant). La figure 3-14 visualise le
relevé des points et des indices.
70 Guide pratique de la modélisation 3D avec WPF 4
Figure 3-14
10 (1,1,0) 9 (0,1,0)
face
arrière

11 (1,0,0) 8 (0,0,0)

Positions = « 0 0 0, 0 1 0, 1 1 0, 1 0 0 »
TriangleIndices = « 8 9 10, 10 11 8 » face arrière
TextureCoordinates = « 1 1 1 0 0 0 0 1 »
On continue avec la face gauche du cube, on applique les indices de 12 à 15 pour
les points du bord du carré, dans le sens contraire des aiguilles d’une montre (ce
qui veut dire que la face que l’on voit sera la face de devant). La figure 3-15 visualise
le relevé des points et des indices.
Figure 3-15
14 (0,1,0) 13 (0,1,1)
face
gauche

15 (0,0,0) 12 (0,0,1)

Positions = « 0 0 1, 0 1 1, 0 1 0, 0 0 0 »
TriangleIndices = « 12 13 14, 14 15 12» face gauche
TextureCoordinates = « 1 1 1 0 0 0 0 1 »
On continue avec la face de dessus du cube, on applique les indices de 16 à 19
pour les points du bord du carré, dans le sens contraire des aiguilles d’une montre
(ce qui veut dire que la face que l’on voit sera la face de devant). La figure 3-16
visualise le relevé des points et des indices.
Figure 3-16
18 (0,1,0) 17 (1,1,0)
Copyright 2011 Patrice REY

face
dessus

19 (0,1,1) 16 (1,1,1)

Positions = « 1 1 1, 1 1 0, 0 1 0, 0 1 1 »
TriangleIndices = « 16 17 18, 18 19 16» face dessus
TextureCoordinates = « 1 1 1 0 0 0 0 1 »
CHAPITRE 3 □ La modélisation du cube 71
On termine avec la face de dessous du cube, on applique les indices de 20 à 23
pour les points du bord du carré, dans le sens contraire des aiguilles d’une montre
(ce qui veut dire que la face que l’on voit sera la face de devant). La figure 3-17
visualise le relevé des points et des indices.
Figure 3-17
22 (0,0,1) 21 (1,0,1)

face
dessous

23 (0,0,0) 20 (1,0,0)

Positions = « 1 0 0, 1 0 1, 0 0 1, 0 0 0 »
TriangleIndices = « 20 21 22, 22 23 20» face dessous
TextureCoordinates = « 1 1 1 0 0 0 0 1 »
La propriété TextureCoordinates permet de stocker les positions 2D des textures
à appliquer. Le mappage (opération qui consiste à appliquer une texture) sert
à étendre une image sur une surface par des correspondances. Ici notre image
à étendre est un dégradé de couleurs, de type radial, avec 3 composantes de
dégradé. Ce dégradé est affecté à la propriété Brush du DiffuseMaterial que l’on
applique à la propriété Material du GeometryModel3D.

<GeometryModel3D.Material>
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<RadialGradientBrush>
<GradientStop Color='White' Offset='0.279' />
<GradientStop Color='LightGray' Offset='0.808' />
<GradientStop Color='DimGray' Offset='1' />
</RadialGradientBrush>
</DiffuseMaterial.Brush>
</DiffuseMaterial>
</GeometryModel3D.Material>

L’image à étendre est au format 2D avec l’origine du repère en haut à gauche.


La figure 3-18 montre le mappage à effectuer. Les quatre coins de l’image
sont repérés par leur position: 0 pour 0%, 1 pour 100%, etc. La face avant qui
est traitée ici, a comme ordre des indices 0, 1, 2 et 3. Il faut donc que l’indice 0
soit en correspondance avec la position (1,1), l’indice 1 soit en correspondance
avec la position (0,1), l’indice 2 soit en correspondance avec la position (0,0) et
72 Guide pratique de la modélisation 3D avec WPF 4
l’indice 3 soit en correspondance avec la position (1,0). De ce fait la propriété
TextureCoordinates, pour cette face avec cet ordre, sera «1 1, 0 1, 0 0, 1 0». A
chaque face, on lui assigne un TextureCoordinates précis. C’est de cette façon que
l’on peut appliquer une texture sur une face.
Figure 3-18

(0,0) (0,1)
2 (0,1,1) 1 (1,1,1) X

face avant dégradé de


couleurs

3 (0,0,1) 0 (1,0,1)
(1,0)
(1,1)

La géométrie du cube x_cube_uni_geo se définit ainsi par ses propriétés Positions,


TriangleIndices et TextureCoordinates:

<Model3DGroup x:Name='x_cube_uniforme'>
<GeometryModel3D x:Name='x_cube_uni_geo'>
<GeometryModel3D.Geometry>
<MeshGeometry3D
Positions=
‘1 0 1, 1 1 1, 0 1 1, 0 0 1,
1 0 0, 1 1 0, 1 1 1, 1 0 1,
0 0 0, 0 1 0, 1 1 0, 1 0 0,
0 0 1, 0 1 1, 0 1 0, 0 0 0,
1 1 1, 1 1 0, 0 1 0, 0 1 1,
1 0 0, 1 0 1, 0 0 1, 0 0 0’
TriangleIndices=
‘0 1 2, 2 3 0,
4 5 6, 6 7 4,
Copyright 2011 Patrice REY

8 9 10, 10 11 8,
12 13 14, 14 15 12,
16 17 18, 18 19 16,
20 21 22, 22 23 20’
TextureCoordinates=
‘1 1 1 0 0 0 0 1,
1 1 1 0 0 0 0 1,
1 1 1 0 0 0 0 1,
CHAPITRE 3 □ La modélisation du cube 73
1 1 1 0 0 0 0 1,
1 1 1 0 0 0 0 1,
1 1 1 0 0 0 0 1’ />
</GeometryModel3D.Geometry>
...
</GeometryModel3D>
</Model3DGroup>

Le résultat de la modélisation du cube avec une texture uniforme, est visualisé


sur le figure 3-19. La figure 3-20 schématise le cube avec ses axes au cours d’un
changement de point de vue.
Figure 3-19

Figure 3-20 Y Y

X X

3.2 - Un cube avec des faces texturées

Il s’agit ici de réaliser un cube pour lequel chaque face se voit appliquer une
texture différente. Dans le sous-dossier image du dossier chapitre03, on importe
74 Guide pratique de la modélisation 3D avec WPF 4
six images (figure 3-21), au format PNG, qui représentent la texture d’une face
avec son nom (texture_face_avant.png, texture_face_droite.png, etc.).
Figure 3-21

Chaque face du cube est traitée comme un élément 3D unique, composée


d’une géométrie de type GeometryModel3D avec ses propriétés propres
Positions, TriangleIndices et TextureCoordinates. Par exemple, la face avant est le
GeometryModel3D x_cube_diff_avant, la face de droite est le GeometryModel3D
x_cube_diff_droite, etc. L’architecture de la modélisation du cube est donc la
suivante, face par face:

<Model3DGroup x:Name='x_objets4'>
...
<Model3DGroup x:Name='x_cube_face_diff'>
<GeometryModel3D x:Name='x_cube_diff_avant'>
...
</GeometryModel3D>
<GeometryModel3D x:Name='x_cube_diff_droite'>
...
</GeometryModel3D>
<GeometryModel3D x:Name='x_cube_diff_arriere'>
...
</GeometryModel3D>
<GeometryModel3D x:Name='x_cube_diff_gauche'>
...
</GeometryModel3D>
<GeometryModel3D x:Name='x_cube_diff_dessus'>
...
</GeometryModel3D>
<GeometryModel3D x:Name='x_cube_diff_dessous'>
Copyright 2011 Patrice REY

...
</GeometryModel3D>
</Model3DGroup>
</Model3DGroup>

Pour appliquer une texture au format image, on instancie un objet DiffuseMaterial.


On affecte à sa propriété Brush, un objet ImageBrush dont sa propriété ImageSource
CHAPITRE 3 □ La modélisation du cube 75
pointe sur le chemin de la ressource de la texture. Pour la géométrie de la face
avant, le Brush du DiffuseMaterial est un objet ImageBrush avec sa propriété
ImageSource qui pointe sur le fichier image texture_face_avant.png.

<Model3DGroup x:Name='x_objets4'>
...
<Model3DGroup x:Name='x_cube_face_diff'>
<GeometryModel3D x:Name='x_cube_diff_avant'>
<GeometryModel3D.Geometry>
<MeshGeometry3D
Positions='1 0 1, 1 1 1, 0 1 1, 0 0 1'
TextureCoordinates='1 1 1 0 0 0 0 1'
TriangleIndices='0 1 2, 2 3 0' />
</GeometryModel3D.Geometry>
<GeometryModel3D.Material>
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<ImageBrush ImageSource='/GuideModelisation3D;
component/chapitre03/image/texture_face_avant.png'
Stretch='Fill'></ImageBrush>
</DiffuseMaterial.Brush>
</DiffuseMaterial>
</GeometryModel3D.Material>
<GeometryModel3D.BackMaterial>
<DiffuseMaterial Brush='DarkGray' />
</GeometryModel3D.BackMaterial>
</GeometryModel3D>
...
</Model3DGroup>
</Model3DGroup>

Figure 3-22
76 Guide pratique de la modélisation 3D avec WPF 4
La figure 3-22 visualise le résultat obtenu avec le cube à six faces texturées
différentes. Le figure 3-23 montre différents points de vue après l’utilisation du
TrackBall.
Figure 3-23

3.3 - Un cube générique

Nous allons aborder la modélisation d’un cube générique. Cette modélisation


consiste à réaliser un cube par code procédural, en indiquant une longueur, une
largeur et une profondeur pour le cube. Dans le Viewport3D x_viewport5 (fichier
Index03.xaml), on positionne une caméra perspective avec ses réglages. On ajoute
un conteneur x_scene5, de type ContainerUIElement3D, qui contient les éléments
3D de la scène. On place un x_objets5, de type Model3DGroup, qui contient
l’éclairage (x_lumiere5) ainsi que le cube modélisé qui sera ajouté par programme.
Le code du Viewport3D est le suivant:

<Border Background='WhiteSmoke' BorderBrush='Black'


BorderThickness='1'
Canvas.Left='16' Canvas.Top='1890' Height='400' Name='x_border5'
Width='402'>
<Viewport3D ClipToBounds='True' Height='400'
MouseLeftButtonDown='x_viewport5_MouseLeftButtonDown'
MouseLeftButtonUp='x_viewport5_MouseLeftButtonUp'
MouseMove='x_viewport5_MouseMove' Name='x_viewport5'
Copyright 2011 Patrice REY

Width='400'>
<Viewport3D.Camera>
<PerspectiveCamera x:Name='x_camera5' FieldOfView='40'
LookDirection='-3,-2,-5' Position='3,2,5'
UpDirection='0 1 0' />
</Viewport3D.Camera>
<ContainerUIElement3D x:Name='x_scene5'>
<ModelUIElement3D>
CHAPITRE 3 □ La modélisation du cube 77
<Model3DGroup x:Name='x_objets5'>
<Model3DGroup x:Name='x_lumiere5'>
<AmbientLight Color='White' />
</Model3DGroup>
</Model3DGroup>
</ModelUIElement3D>
</ContainerUIElement3D>
</Viewport3D>
</Border>

En se reportant à la figure 3-24, la modélisation d’un cube générique est assez


simple. Il faut commencer par dessiner géométriquement un cube avec des arêtes
de 1 unité. Les huit points qui schématisent les coins du cube, sont notés avec leurs
coordonnées. Puis on remplace dans leurs coordonnées tous les nombres 1 par
leur correspondance d’axe avec x, y ou z.
Par exemple le point 2 (1,1,1) deviendra 2 (x,y,z), tout comme le point 6 (1,1,0)
deviendra 6 (x,y,0). De cette façon, chaque face est localisable dans l’espace 3D.
Ensuite il faut générer une face rectangulaire avec sa géométrie et ses textures
sur chaque face. Dans le fichier Index03.xaml.cs, on définit une méthode
ModeliserFaceRectangle(..) qui reçoit en paramètre quatre points de type Point3D,
et qui retourne un modèle de type GeometryModel3D. Comme le montre la figure
3-25 avec la face avant, on récupère les points concernés par cette face (pt1, pt2,
pt3 et pt4) et on passe ces points à la méthode ModeliserFaceRectangle(..). L’ordre
de ces points, comme toujours, a une grande importance comme on l’a déjà vu.
Figure 3-25

2 (0,y,z) 1 (x,y,z)

(0,y,z) (x,y,z) face


3 2 avant

3 (0,0,z) 0 (x,0,z)

(0,0) (1,0)

4 1
(0,0,z) (x,0,z)
(0,1) (1,1)
78 Guide pratique de la modélisation 3D avec WPF 4
Figure 3-24
2 (0,y,0) 1 (x,y,0)
face face
gauche dessus

2 (0,y,0) 1 (0,y,z)
3 (0,y,z) 0 (x,y,z)
Y

3 (0,0,0) 0 (0,0,z) face


(0,y,0) (x,y,0) arrière
7 6
2 (x,y,0) 1 (0,y,0)

(0,y,z) (x,y,z)
3 2 3 (x,0,0) 0 (0,0,0)
8 5
(0,0,0) (x,0,0)
X

4 2 (x,y,z) 1 (x,y,0)
1
(0,0,z) (x,0,z)
face
droite

Z 3 (x,0,z) 0 (x,0,0)

2 (0,y,z) 1 (x,y,z) 2 (0,0,z) 1 (x,0,z)

face face
avant dessous
Copyright 2011 Patrice REY

3 (0,0,z) 0 (x,0,z) 3 (0,0,0) 0 (x,0,0)

Pour chaque face, en tournant dans le sens contraire des aiguilles d’une montre pour
signifier que c’est une face que l’on regarde, on passe les points en commençant
par le coin bas droit, puis le coin haut droit, puis le coin haut gauche, enfin le coin
CHAPITRE 3 □ La modélisation du cube 79
bas gauche.
La méthode ModeliserFaceRectangle(..) va générer une surface 3D avec sa texture
en retournant un objet GeometryModel3D.
Pour cela, il faut commencer par instancier une géométrie maillage, de type
MeshGeometry3D. Cette géométrie reçoit dans sa propriété Positions, les points
Point3D de la surface par l’intermédiaire de la méthode Add. Les points, pt1 à
pt4, sont ajoutés dans cet ordre. Puis cette géométrie reçoit dans sa propriété
TriangleIndices, l’ordre des indices par l’intermédiaire de la méthode Add (ici 0,
1, 2 pour le premier triangle et 2, 1, 3 pour le deuxième triangle). Enfin cette
géométrie reçoit dans sa propriété TextureCoordinates les points 2D, de type Point,
pour l’orientation du placage de texture, par l’intermédiaire de la méthode Add.
Ce maillage étant généré, il est affecté à la propriété Geometry de face, de type
GeometryModel3D.
Pour appliquer une texture, on instancie un objet diffuse, de type DiffuseMaterial.
Sa propriété Brush reçoit, comme pinceau, un ImageBrush dont la source est une
ressource image avec son emplacement chemin_texture. L’objet diffuse est alors
affecté à la propriété Material de face. Pour la texture de l’arrière de la facette,
on affecte un DiffuseMaterial avec sa propriété Brush fixée à Brushes.Black, à la
propriété BackMaterial de face.

//modeliser une face rectangulaire avec texture prédéfinie


private GeometryModel3D ModeliserFaceRectangle(Point3D pt1, Point3D
pt2, Point3D pt3, Point3D pt4) {
GeometryModel3D face = new GeometryModel3D();
MeshGeometry3D maillage = new MeshGeometry3D();
maillage.Positions.Add(pt1);
maillage.Positions.Add(pt2);
maillage.Positions.Add(pt3);
maillage.Positions.Add(pt4);
maillage.TriangleIndices.Add(0);
maillage.TriangleIndices.Add(1);
maillage.TriangleIndices.Add(2);
maillage.TriangleIndices.Add(2);
maillage.TriangleIndices.Add(3);
maillage.TriangleIndices.Add(0);
maillage.TextureCoordinates.Add(new Point(1, 1));
maillage.TextureCoordinates.Add(new Point(1, 0));
maillage.TextureCoordinates.Add(new Point(0, 0));
maillage.TextureCoordinates.Add(new Point(0, 1));
face.Geometry = maillage;
80 Guide pratique de la modélisation 3D avec WPF 4
DiffuseMaterial diffuse = new DiffuseMaterial();
ImageBrush img_brush = new ImageBrush();
string chemin_texture = «chapitre03/image/texture_generique.png»;
img_brush.ImageSource = new BitmapImage(
new Uri(«pack://application:,,/» + chemin_texture,
UriKind.Absolute));
diffuse.Brush = img_brush;
face.Material = diffuse;
face.BackMaterial = new DiffuseMaterial(Brushes.Black);
return face;
}

A partir de là, pour modéliser un cube avec des unités de longueur pour les côtés,
on utilise la méthode ModeliserCube(..) qui reçoit, en paramètre, les longueurs
dist_x selon l’axe X, dist_y selon l’axe Y et dist_z selon l’axe Z. Cette méthode
commence par instancier un modèle 3D m_modele, de type Model3DGroup. On
lui fixe un nom, pour le repérer dans l’arbre visuel du Model3DGroup x_objets5,
par la méthode SetValue (méthode qui permet d’enregistrer la propriété Name,
propriété de dépendance NameProperty, avec la valeur x_cube_generique, de
type string). On ajoute m_modele aux enfants de l’arbre visuel de x_objets5 par la
méthode Add.

//modeliser le cube
private void ModeliserCube(double dist_x, double dist_y, double
dist_z) {
m_modele = new Model3DGroup();
m_modele.SetValue(NameProperty, «x_cube_generique»);
...
x_objets5.Children.Add(m_modele);
}

On définit les 8 points, de type Point3D, avec leurs coordonnées en fonction de


dist_x, dist_y et dist_z comme on l’a vu sur la figure 3-24.
Copyright 2011 Patrice REY

//modeliser le cube
private void ModeliserCube(double dist_x, double dist_y, double
dist_z) {
...
Point3D pt1 = new Point3D(dist_x, 0, dist_z); //x 0 z
Point3D pt2 = new Point3D(dist_x, dist_y, dist_z); //x y z
Point3D pt3 = new Point3D(0, dist_y, dist_z); //0 y z
CHAPITRE 3 □ La modélisation du cube 81
Point3D pt4 = new Point3D(0, 0, dist_z); //0 0 z
Point3D pt5 = new Point3D(dist_x, 0, 0); //x 0 0
Point3D pt6 = new Point3D(dist_x, dist_y, 0); //x y 0
Point3D pt7 = new Point3D(0, dist_y, 0); //0 y 0
Point3D pt8 = new Point3D(0, 0, 0); //0 0 0
...
}

Enfin, on génère chaque face, de type GeometryModel3D, et on l’ajoute aux enfants


de m_modele par la méthode Add. Il faut veiller à ne pas se tromper dans l’ordre
des points passés à la méthode ModeliserFaceRectangle(..). En suivant le modèle
géométrique de la figure 3-24, cela facilite grandement les choses.

//modeliser le cube
private void ModeliserCube(double dist_x, double dist_y, double
dist_z) {
...
//1234 avant
GeometryModel3D face_avant = ModeliserFaceRectangle(pt1, pt2, pt3,
pt4);
m_modele.Children.Add(face_avant);
//5621 droite
GeometryModel3D face_droite = ModeliserFaceRectangle(pt5, pt6, pt2,
pt1);
m_modele.Children.Add(face_droite);
//8765 arriere
GeometryModel3D face_arriere = ModeliserFaceRectangle(pt8, pt7,
pt6, pt5);
m_modele.Children.Add(face_arriere);
//4378 gauche
GeometryModel3D face_gauche = ModeliserFaceRectangle(pt4, pt3, pt7,
pt8);
m_modele.Children.Add(face_gauche);
//2673 dessus
GeometryModel3D face_dessus = ModeliserFaceRectangle(pt2, pt6, pt7,
pt3);
m_modele.Children.Add(face_dessus);
//5148 dessous
GeometryModel3D face_dessous = ModeliserFaceRectangle(pt5, pt1,
pt4, pt8);
m_modele.Children.Add(face_dessous);
...
}
82 Guide pratique de la modélisation 3D avec WPF 4
Figure 3-26

face dessus

face avant face droite

face dessus

face droite
face avant

face avant face droite

Copyright 2011 Patrice REY

face dessus

face droite
face avant
CHAPITRE 3 □ La modélisation du cube 83
La figure 3-26 montre les résultats obtenus. En choisissant dans le sélecteur:
• «un cube avec des côtés de 1 unité», on génère un cube, avec 1 unité par côté,
par l’intermédiaire de la méthode ModeliserCube(1,1,1).
• «un cube allongé suivant X», on génère un cube, étiré suivant l’axe X, par
l’intermédiaire de la méthode ModeliserCube(2,0.5,0.5).
• «un cube allongé suivant Y», on génère un cube, étiré suivant l’axe Y, par
l’intermédiaire de la méthode ModeliserCube(0.5,2,0.5).
• «un cube allongé suivant Z», on génère un cube, étiré suivant l’axe Z, par
l’intermédiaire de la méthode ModeliserCube(0.5,0.5,2).

4 - Les axes de coordonnées et le plan de travail

La modélisation des axes de coordonnées est une extension de la modélisation du


cube. En effet, on peut considérer qu’un axe de coordonnée a la forme d’un cube
très long, pas haut et pas profond. A partir de ce constat, modéliser un axe revient
à modéliser un cube centré sur l’origine du repère des coordonnées.
La figure 3-27 visualise géométriquement un cube centré sur l’origine du repère,
et dont les coordonnées de ses coins sont exprimées en fonction de x, y et z. Il y a
huit coins repérés par les points numéro 1(+x,-y,+z), numéro 2(+x,+y,+z), numéro
3(-x,+y,+z), numéro 4(-x,-y,+z), numéro 5(+x,-y,-z), numéro 6(+x,+y,-z), numéro
7(-x,+y,-z) et numéro 8(-x,-y,-z). Chaque face est repérée par un ensemble de
quatre points qui représentent deux triangles avec (en suivant toujours le sens
contraire des aiguilles d’une montre pour signifier la face visible):
• la face avant avec les points 1, 2, 3 et 4.
• la face droite avec les points 5, 6, 2 et 1.
• la face arrière avec les points 8, 7, 6 et 5.
• la face gauche avec les points 4, 3, 7 et 8.
• la face dessus avec les points 2, 6, 7 et 3.
• la face dessous avec les points 5, 1, 4 et 8.
Pour ajouter un repère complet avec les trois axes, on définit une méthode
AjouterAxesCoordonnees(..) qui reçoit, en paramètre, une distance (pour indiquer
la longueur de l’axe de part et d’autre de l’origine) et un objet Model3DGroup
(où ce repère sera inséré). Le repère mod_repere_axe, de type Model3DGroup,
est instancié. Pour lui attribuer un nom x_repere_axe dans l’arbre visuel du
conteneur des objets, on utilise la méthode SetValue pour lui fixer sa propriété de
dépendance NameProperty à cette chaîne. Puis on ajoute à ses enfants les trois
axes par l’intermédiaire de la méthode ModeliserUnAxe(..). Cette méthode reçoit,
84 Guide pratique de la modélisation 3D avec WPF 4
Figure 3-27

2 (-x,+y,-z) 1 (+x,+y,-z) 8 7 6 5

face face
dessus arrière

3 (-x,+y,+z) 0 (+x,+y,+z) 2 (+x,+y,-z) 1 (-x,+y,-z)


face
gauche
2 6 7 3
2 (-x,+y,-z) 1 (-x,+y,+z)

3 (+x,-y,-z) 0 (-x,-y,-z)
Y

7 6
3 (-x,-y,-z) 0 (-x,-y,+z) (-x,+y,-z) (+x,+y,-z)
4 3 7 8

3 2
(-x,+y,+z) (+x,+y,+z)
8 X
(-x,-y,-z)
(+x,-y,-z)
5

2 (+x,+y,+z) 1 (+x,+y,-z)
4
face
(-x,-y,+z) droite
Z 1 (+x,-y,+z)
3 (+x,-y,+z) 0 (+x,-y,-z)
2 (-x,-y,+z) 1 (+x,-y,+z)
2 (-x,+y,+z) 1 (+x,+y,+z)
5 6 2 1
Copyright 2011 Patrice REY

face face
avant dessous

3 (-x,-y,+z) 0 (+x,-y,+z)) 3 (-x,-y,-z) 0 (+x,-y,-z)

1 2 3 4 5 1 4 8
CHAPITRE 3 □ La modélisation du cube 85
en paramètre, une distance et une chaîne pour différencier l’axe que l’on construit
(«x», «y» ou «z»).

//
private void AjouterAxesCoordonnees(double dist, Model3DGroup mod_gp)
{
Model3DGroup mod_repere_axe = new Model3DGroup();
mod_repere_axe.SetValue(NameProperty, «x_repere_axe»);
mod_repere_axe.Children.Add(ModeliserUnAxe(dist, «x»));
mod_repere_axe.Children.Add(ModeliserUnAxe(dist, «y»));
mod_repere_axe.Children.Add(ModeliserUnAxe(dist, «z»));
mod_gp.Children.Add(mod_repere_axe);
}

En fonction de la distance et de l’axe choisi, la méthode ModeliserUnAxe(..) génère


un cube étiré suivant l’axe choisi. De façon à ce que le rendu du cube étiré, se
rapproche le plus possible d’une vision traditionnelle d’un axe de coordonnée, il
faut sélectionner une valeur de 0.01, de type double, comme longueur dans les 2
parties non étirées. La modélisation de l’axe, représenté par un cube étiré, reste la
même que celle vue pour modéliser le cube.

//
private Model3D ModeliserUnAxe(double dist, string axe) {
Model3DGroup un_axe = new Model3DGroup();
un_axe.SetValue(NameProperty, «x_axe_» + axe);
double dist_x = 0;
double dist_y = 0;
double dist_z = 0;
switch (axe) {
case «x»: dist_x = dist; dist_y = 0.01; dist_z = 0.01; break;
case «y»: dist_x = 0.01; dist_y = dist; dist_z = 0.01; break;
case «z»: dist_x = 0.01; dist_y = 0.01; dist_z = dist; break;
}
Point3D pt1 = new Point3D(+dist_x, -dist_y, +dist_z); //+x -y +z
Point3D pt2 = new Point3D(+dist_x, +dist_y, +dist_z); //+x +y +z
Point3D pt3 = new Point3D(-dist_x, +dist_y, +dist_z); //-x +y +z
Point3D pt4 = new Point3D(-dist_x, -dist_y, +dist_z); //-x -y +z
Point3D pt5 = new Point3D(+dist_x, -dist_y, -dist_z); //+x -y -z
Point3D pt6 = new Point3D(+dist_x, +dist_y, -dist_z); //+x +y -z
Point3D pt7 = new Point3D(-dist_x, +dist_y, -dist_z); //-x +y -z
Point3D pt8 = new Point3D(-dist_x, -dist_y, -dist_z); //-x -y -z
//1234 avant
86 Guide pratique de la modélisation 3D avec WPF 4
GeometryModel3D face_avant = ModeliserFaceAxe(pt1, pt2, pt3, pt4);
un_axe.Children.Add(face_avant);
//5621 droite
GeometryModel3D face_droite = ModeliserFaceAxe(pt5, pt6, pt2, pt1);
un_axe.Children.Add(face_droite);
//8765 arriere
GeometryModel3D face_arriere = ModeliserFaceAxe(pt8, pt7, pt6,
pt5);
un_axe.Children.Add(face_arriere);
//4378 gauche
GeometryModel3D face_gauche = ModeliserFaceAxe(pt4, pt3, pt7, pt8);
un_axe.Children.Add(face_gauche);
//2673 dessus
GeometryModel3D face_dessus = ModeliserFaceAxe(pt2, pt6, pt7, pt3);
un_axe.Children.Add(face_dessus);
//5148 dessous
GeometryModel3D face_dessous = ModeliserFaceAxe(pt5, pt1, pt4,
pt8);
un_axe.Children.Add(face_dessous);
return un_axe;
}

Les six faces d’un axe ont la même couleur. Cette couleur est fixée ici à une valeur
Brushes.Black affectée à un objet DiffuseMaterial, lui-même affecté aux propriétés
Material et BackMaterial du GeometryModel3D généré. La figure 3-28 montre le
repère des coordonnées avec un cube de 1 unité de côté.

//
private GeometryModel3D ModeliserFaceAxe(Point3D pt1, Point3D pt2,
Point3D pt3, Point3D pt4) {
GeometryModel3D face = new GeometryModel3D();
MeshGeometry3D maillage = new MeshGeometry3D();
maillage.Positions.Add(pt1);
maillage.Positions.Add(pt2);
maillage.Positions.Add(pt3);
Copyright 2011 Patrice REY

maillage.Positions.Add(pt4);
maillage.TriangleIndices.Add(0);
maillage.TriangleIndices.Add(1);
maillage.TriangleIndices.Add(2);
maillage.TriangleIndices.Add(2);
maillage.TriangleIndices.Add(3);
maillage.TriangleIndices.Add(0);
maillage.TextureCoordinates.Add(new Point(1, 1));
CHAPITRE 3 □ La modélisation du cube 87
maillage.TextureCoordinates.Add(new Point(1, 0));
maillage.TextureCoordinates.Add(new Point(0, 0));
maillage.TextureCoordinates.Add(new Point(0, 1));
face.Geometry = maillage;
face.Material = new DiffuseMaterial(Brushes.Black); ;
face.BackMaterial = new DiffuseMaterial(Brushes.Black);
return face;
}

Pour augmenter le réalisme de la scène 3D, généralement on ajoute un plan de


travail, sous forme d’une grille, pour symboliser le sol sur lequel on positionne les
objets. Ce plan de travail est représenté par le plan (Ox,Oz). De plus, il faut à la
fois voir à travers la grille, du dessus et du dessous. La manière la plus simple de
réaliser ce plan de travail avec ces exigences, c’est de modéliser plusieurs petites
faces planes séparées d’une unité.
D’un point de vue de l’implémentation, la méthode AjouterPlanDeTravail(..) génère
un plan de travail, nommé x_plan_travail. Le maillage du plan de travail reste le
même que pour celui d’une face rectangulaire.

//plan de travail sous forme de grillage


private void AjouterPlanDeTravail(double dist, Model3DGroup mod_gp) {
Model3DGroup plan_travail = new Model3DGroup();
plan_travail.SetValue(NameProperty, «x_plan_travail»);
for (double xx = -dist; xx <= dist; xx += 1) {
if (xx != 0) {
GeometryModel3D face = new GeometryModel3D();
MeshGeometry3D maillage = new MeshGeometry3D();
maillage.Positions.Add(new Point3D(xx + 0.005, 0, +dist));
maillage.Positions.Add(new Point3D(xx + 0.005, 0, -dist));
maillage.Positions.Add(new Point3D(xx - 0.005, 0, -dist));
maillage.Positions.Add(new Point3D(xx - 0.005, 0, +dist));
maillage.TriangleIndices.Add(0);
maillage.TriangleIndices.Add(1);
maillage.TriangleIndices.Add(2);
maillage.TriangleIndices.Add(2);
maillage.TriangleIndices.Add(3);
maillage.TriangleIndices.Add(0);
face.Geometry = maillage;
face.Material = new DiffuseMaterial(Brushes.LightGray);
face.BackMaterial = new DiffuseMaterial(Brushes.LightGray);
plan_travail.Children.Add(face);
}
88 Guide pratique de la modélisation 3D avec WPF 4
}
for (double zz = -dist; zz <= dist; zz += 1) {
if (zz != 0) {
GeometryModel3D face = new GeometryModel3D();
MeshGeometry3D maillage = new MeshGeometry3D();
maillage.Positions.Add(new Point3D(+dist, 0, zz+0.005));
maillage.Positions.Add(new Point3D(-dist, 0, zz+0.005));
maillage.Positions.Add(new Point3D(-dist, 0, zz-0.005));
maillage.Positions.Add(new Point3D(+dist, 0, zz-0.005));
maillage.TriangleIndices.Add(0);
maillage.TriangleIndices.Add(1);
maillage.TriangleIndices.Add(2);
maillage.TriangleIndices.Add(2);
maillage.TriangleIndices.Add(3);
maillage.TriangleIndices.Add(0);
face.Geometry = maillage;
face.Material = new DiffuseMaterial(Brushes.LightGray);
face.BackMaterial = new DiffuseMaterial(Brushes.LightGray);
plan_travail.Children.Add(face);
}
}
mod_gp.Children.Add(plan_travail);
}

La figure 3-28 visualise le résultat obtenu en affichant le cube avec le repère de


coordonnées et le plan de travail. Le haut de la figure montre une vue quand on
se trouve au-dessus du plan de travail. Le bas de la figure montre une vue quand
on se trouve en dessous du plan de travail. On constate bien que l’on aperçoit le
cube à travers le plan de travail. Là, on a bien l’impression d’être dans un espace
3D complet, doté d’un fort réalisme de vérité.

Copyright 2011 Patrice REY


CHAPITRE 3 □ La modélisation du cube 89

Figure 3-28
CHAPITRE 4

La modélisation de la sphère

T ous les modèles 3D sont composés de facettes à base de triangle. La modélisation


de la sphère passe par la réalisation de ces facettes dont le rendu visuel donnera
l’impression de se rapprocher d’une sphère théorique, voire de l’atteindre.
Nous allons voir la modélisation d’une sphère en passant par les coordonnées
sphériques. Et par extension, nous allons modéliser l’ellipsoïde.

1 - Les coordonnées sphériques

Une sphère est composée de facettes triangulaires qui sont localisées dans l’espace
3D et assemblées entre elles. Les sommets des triangles doivent être localisés par
rapport au centre de la sphère. Tous les points d’une sphère ont une caractéristique
unique, c’est qu’ils se trouvent à une distance fixe d’un centre. Les points d’une
sphère appartiennent à une surface qui se trouve à une distance R d’un centre 0:
R est le rayon de la sphère et O est le centre de la sphère.
Les coordonnées cartésiennes d’un point M s’expriment par 3 coordonnées (x,y,z)
selon les 3 axes. Or, pour balayer selon des angles à une distance R, en vue de
l’obtention de coordonnées, il va falloir exprimer (x,y,z) en ce que l’on appelle les
coordonnées sphériques.
Comme le montre géométriquement le haut de la figure 4-1, il y a une infinité de
point M de coordonnées (x,y,z) qui sont positionnés à une distance R du centre O.
Dans le plan (OX,OZ), l’ensemble des points M à une distance R (les points A et D
par exemple) correspond au balayage de l’angle ϕ quand celui-ci varie de 0 à 2π
(avec l’angle β égal à 0). Dans un plan quelconque, l’ensemble des points M à une
distance R (les points B et C par exemple) correspond au balayage de l’angle ϕ
quand celui-ci varie de 0 à 2π, avec l’angle β qui varie de -π/2 à +π/2.
92 Guide pratique de la modélisation 3D avec WPF 4

Figure 4-1

C
B

β
D
O φ X
A

Y
M(x,y,z)
ym points M:
xm = OP*cos(φ) = R*cos(β)*cos(φ)
R ym = R*sin(β)
zm = -OP*sin(φ) = -R*cos(β)*sin(φ)

zm P(x,0,z)
Copyright 2011 Patrice REY

β
O φ
xm
X

Z
CHAPITRE 4 □ La modélisation de la sphère 93
On s’aperçoit donc que l’on peut construire des facettes, comme celle dont les
coins sont A, B, C et D. Et par conséquent, on peut définir un nombre de facettes à
la fois sur le plan horizontal et sur le plan vertical. Un nombre identique de facettes
horizontalement et verticalement, conduira à avoir des facettes généralement de
forme carré, sauf à l’approche des pôles de la sphère. Un nombre important de
facettes, horizontalement et verticalement, permettra une meilleure définition de
la sphère.
Le schéma géométrique au bas de la figure 4-1 nous permet de définir les
coordonnées sphériques d’un point M. Soit un point M appartenant à la sphère,
et par conséquent, se trouvant à une distance R du centre O. On effectue les
projections orthogonales du point M sur les axes (X,Y,Z). Cela conduit à déterminer
les coordonnées du point M qui sont xm, ym et zm:
• dans le triangle (O,P,xm), rectangle en xm, on a xm=OP*cos(ϕ); dans le triangle
(O,M,P), rectangle en P, on a la distance OP=R*cos(β); on en déduit donc que la
coordonnée xm=OP*cos(ϕ)= R*cos(β)*cos(ϕ).
• dans le triangle (O,M,P), rectangle en P, on a la distance MP=R*sin(β); comme
la distance MP est égale justement à ym, on a donc ym= R*sin(β).
• dans le triangle (O,P,xm), rectangle en xm, on a la distance Pxm=zm=-OP*sin(ϕ);
comme OP= R*cos(β), on en déduit que zm=-R*cos(β)*sin(β).
Ainsi on a pu exprimer les coordonnées cartésiennes (xm,ym,zm) en fonction du
triplet (R,ϕ,β). Ce triplet constitue les coordonnées sphériques du point M.

2 - La modélisation sphérique

La modélisation sphérique consiste à générer les facettes de la sphère, et en


particulier, à calculer les coordonnées sphériques de quatre points qui constituent
les coins de la facette.
Chaque facette, dont les points sont pt0, pt1, pt2 et pt3, est composée de deux
triangles avec le premier triangle (pt3,pt2,pt1) et le deuxième triangle (pt1,pt0,pt3).
Comme on l’a déjà vu, on utilise cet ordre, dans le sens contraire des aiguilles
d’une montre, pour signifier que c’est la face que l’on voit et qui est texturée (celle
de devant).
La figure 4-2 montre les points pt0, pt1, pt2 et pt3, pour une facette avec une
division de l’angle ϕ et une division de l’angle β. Le bas de la figure 4-2 montre une
portion de la sphère générée quand l’angle ϕ varie de 0 à π/2 et l’angle β varie de
-π2 à +π/2.
94 Guide pratique de la modélisation 3D avec WPF 4
Figure 4-2

pt2
pt1

β pt3
Z pt0

Copyright 2011 Patrice REY

φ de 0 à 90 degrés
CHAPITRE 4 □ La modélisation de la sphère 95
La génération des points de la facette débute par une localisation de ces points
en fonction du triplet des coordonnées sphériques (R,ϕ,β). Comme on a défini
les coordonnées sphériques (figure 4-1), l’implémentation de la méthode
ObtenirPosition(..) reçoit, en paramètre, un rayon rayon, un angle phi et un
angle beta. Elle retourne alors un point, de type Point3D, correspondant à la
localisation d’un point par rapport à un centre absolu (coordonnées 0,0,0). Les
angles que l’on passe, phi et beta, sont exprimés en degrés pour plus de facilité
et de compréhension. Or les méthodes, Math.Sin pour le sinus et Math.Cos pour
le cosinus, reçoivent des valeurs, de type double, correspondant à des radians. La
conversion d’un angle pour le passage des degrés aux radians, se fait en multipliant
l’angle en degrés par Math.PI/180.

//
private Point3D ObtenirPosition(double rayon, double phi, double
beta) {
Point3D pt = new Point3D();
pt.X = +rayon * Math.Cos(beta * Math.PI / 180) *
Math.Cos(phi * Math.PI / 180);
pt.Y = +rayon * Math.Sin(beta * Math.PI / 180);
pt.Z = -rayon * Math.Cos(beta * Math.PI / 180) *
Math.Sin(phi * Math.PI / 180);
return pt;
}

Pour générer une sphère, nous allons définir une méthode CreerSphere(..) qui
reçoit, en paramètre, un centre de type Point3D, une rayon de type double, un
nombre de division selon l’horizontale div_phi de type int, et un nombre de division
selon la verticale div_beta de type int. Cette méthode retournera une sphère
modele_sphere, de type Model3DGroup, et cet objet sphérique sera intégré à la
scène 3D.
Pour un nombre de division, div_phi et div_beta, l’angle, angle_phi et angle_beta,
balayera des valeurs déterminées par:
• angle_phi = 360 / (div_phi - 1).
• angle_beta = 360 / (div_beta - 1).
A partir de là, par des boucles imbriquées, on fait varier angle_phi de 0 à 360 degrés,
et angle_beta de -90 à +90 degrés. En fonction de ces angles, on détermine les
quatre points de la facette qui sont pt0, pt1, pt2 et pt3. Puis on ajoute à chacun de
ces points, le centre, de type Point3D, en faisant un cast en Vector3D (importante
notion vue au chapitre 1 en pratique). Cela permet de repositionner tous les points
96 Guide pratique de la modélisation 3D avec WPF 4
générés par rapport à un centre qui ne serait pas l’origine du repère. Enfin, on
passe ces quatre points, dans l’ordre (pt3,pt2,pt1,pt0) comme on l’a vu plus haut,
à la méthode GenererFacette(..).

//
private Model3DGroup CreerSphere(Point3D centre, double rayon, int
div_phi, int div_beta) {
Model3DGroup modele_sphere = new Model3DGroup();
if (div_phi < 2 || div_beta < 2) {
return modele_sphere;
}
modele_sphere.SetValue(NameProperty, «x_sphere»);
double angle_phi = 360 / (div_phi - 1);
double angle_beta = 360 / (div_beta - 1);
for (double i = 0; i < 360; i += angle_phi) {
for (double j = -90; j < 90; j += angle_beta) {
Point3D pt_0 = ObtenirPosition(rayon, i, j);
pt_0 += (Vector3D)centre;
Point3D pt_1 = ObtenirPosition(rayon, i, j + angle_beta);
pt_1 += (Vector3D)centre;
Point3D pt_2 = ObtenirPosition(rayon, i+angle_phi, j
+ angle_beta);
pt_2 += (Vector3D)centre;
Point3D pt_3 = ObtenirPosition(rayon, i+angle_phi, j);
pt_3 += (Vector3D)centre;
GenererFacette(pt_3, pt_2, pt_1, pt_0, modele_sphere);
}
}
return modele_sphere;
}

La méthode GenererFacette(..) va générer la facette en fonction des quatre


points passés, lui appliquer une texture, et ajouter cette facette au modèle
Model3DGroup. Pour la texture, face avant de la facette, on lui applique l’image
texture_generique.png (dans le sous-dossier image du dossier chapitre04). Pour la
Copyright 2011 Patrice REY

texture, face arrière de la facette, on lui applique une couleur Brushes.DarkGray.

private void GenererFacette(Point3D pt_0, Point3D pt_1, Point3D pt_2,


Point3D pt_3, Model3DGroup modele_sphere) {
GeometryModel3D facette = new GeometryModel3D();
MeshGeometry3D geometrie = new MeshGeometry3D();
geometrie.Positions.Add(pt_0);
CHAPITRE 4 □ La modélisation de la sphère 97
geometrie.Positions.Add(pt_1);
geometrie.Positions.Add(pt_2);
geometrie.Positions.Add(pt_3);
geometrie.TriangleIndices.Add(0);
geometrie.TriangleIndices.Add(1);
geometrie.TriangleIndices.Add(2);
geometrie.TriangleIndices.Add(2);
geometrie.TriangleIndices.Add(3);
geometrie.TriangleIndices.Add(0);
geometrie.TextureCoordinates.Add(new Point(1, 1));
geometrie.TextureCoordinates.Add(new Point(1, 0));
geometrie.TextureCoordinates.Add(new Point(0, 0));
geometrie.TextureCoordinates.Add(new Point(0, 1));
facette.Geometry = geometrie;
DiffuseMaterial mat_diffuse = new DiffuseMaterial();
ImageBrush img_brush = new ImageBrush();
img_brush.ImageSource = new BitmapImage(
new Uri(«pack://application:,,/chapitre04/image/
texture_generique.png», UriKind.Absolute));
mat_diffuse.Brush = img_brush;
facette.Material = mat_diffuse;
facette.BackMaterial = new DiffuseMaterial(Brushes.DarkGray);
modele_sphere.Children.Add(facette);
}

Le haut de la figure 4-3 montre la sphère avec un nombre de 10 divisions horizontales


et verticales. Au niveau des pôles de la sphère, on voit qu’il y a un aplatissement. En
choisissant 20 divisions horizontales et verticales (bas de la figure 4-3), la définition
au niveau des pôles est nettement meilleure, donnant l’impression d’une véritable
sphère. Le milieu de la figure 4-3 montre la sphère dans le cas où l’on ait 20 divisions
horizontales et 10 divisions verticales, et inversement.
Lors de la création d’une sphère, on spécifie le positionnement d’un centre pour
modéliser la sphère. Dans la figure 4-4, on instancie quatre sphères avec des
positionnements différents pour leurs centres respectifs.

//initialiser le viewport
private void InitialiserViewport() {
AjouterAxesCoordonnees(10, x_objets);
x_objets.Children.Add(CreerSphere(new Point3D(-1.5, 0, 0),
0.5, 40, 40));
x_objets.Children.Add(CreerSphere(new Point3D(0, 0, 1.5),
0.5, 40, 20));
98 Guide pratique de la modélisation 3D avec WPF 4
Figure 4-3

avec 10 divisions horizontales


avec 10 divisions verticales

avec 20 divisions horizontales


avec 10 divisions verticales

avec 10 divisions horizontales


avec 20 divisions verticales
Copyright 2011 Patrice REY

avec 20 divisions horizontales


avec 20 divisions verticales
CHAPITRE 4 □ La modélisation de la sphère 99
x_objets.Children.Add(CreerSphere(new Point3D(1.5, 0, 0),
0.5, 20, 40));
x_objets.Children.Add(CreerSphere(new Point3D(0, 1.5, 0),
0.5, 50, 50));
}
Figure 4-4

3 - L’ellipsoïde

La modélisation de l’ellipsoïde est réalisée par extension de la modélisation de la


sphère. En effet, l’ellipsoïde possède trois rayons différents, et si ces trois rayons
sont égaux, on est alors en présence d’une sphère.
La méthode ObtenirPositionEllipsoide(..) reçoit les trois rayons comme paramètres
au lieu d’un rayon pour la sphère. Le calcul des positions sphériques se fait de la
même manière que pour la sphère, en précisant le rayon concerné pour le calcul
de coordonnées.

//position point sur ellipsoide


private Point3D ObtenirPositionEllipsoide(double rayon_x, double
rayon_y, double rayon_z, double phi, double beta) {
Point3D pt = new Point3D();
100 Guide pratique de la modélisation 3D avec WPF 4
pt.X = +rayon_x * Math.Cos(beta * Math.PI / 180) *
Math.Cos(phi * Math.PI / 180);
pt.Y = +rayon_y * Math.Sin(beta * Math.PI / 180);
pt.Z = -rayon_z * Math.Cos(beta * Math.PI / 180) *
Math.Sin(phi * Math.PI / 180);
return pt;
}

La création de l’ellipsoïde se fait par la méthode CreerEllipsoide(..) qui reçoit un


centre de positionnement, trois rayons et les deux nombres de division pour les
facettes.

//ellipsoide
private Model3DGroup CreerEllipsoide(Point3D centre, double rayon_x,
double rayon_y,
double rayon_z, int div_phi, int div_beta) {
Model3DGroup modele_ellipsoide = new Model3DGroup();
if (div_phi < 2 || div_beta < 2) {
return modele_ellipsoide;
}
modele_ellipsoide.SetValue(NameProperty, «x_sphere»);
double angle_phi = 360 / (div_phi - 1);
double angle_beta = 360 / (div_beta - 1);
for (double i = 0; i < 360; i += angle_phi) {
for (double j = -90; j < 90; j += angle_beta) {
Point3D pt_0 = ObtenirPositionEllipsoide(rayon_x, rayon_y,
rayon_z, i, j);
pt_0 += (Vector3D)centre;
Point3D pt_1 = ObtenirPositionEllipsoide(rayon_x, rayon_y,
rayon_z, i, j + angle_beta);
pt_1 += (Vector3D)centre;
Point3D pt_2 = ObtenirPositionEllipsoide(rayon_x, rayon_y,
rayon_z, i + angle_phi, j + angle_beta);
pt_2 += (Vector3D)centre;
Point3D pt_3 = ObtenirPositionEllipsoide(rayon_x, rayon_y,
Copyright 2011 Patrice REY

rayon_z, i + angle_phi, j);


pt_3 += (Vector3D)centre;
GenererFacette(pt_3, pt_2, pt_1, pt_0, modele_ellipsoide);
}
}
return modele_ellipsoide;
}
CHAPITRE 4 □ La modélisation de la sphère 101
La figure 4-5 visualise le résultat obtenu pour la création d’une ellipsoïde centrée
sur l’origine du repère, avec un rayon suivant X de 2 unités, un rayon suivant Y de 1
unité et un rayon suivant Z de 0.5 unité. Ces trois rayons sont visualisés sur la figure
4-6 dans deux vues différentes.

//initialiser le viewport
private void InitialiserViewport() {
AjouterAxesCoordonnees(10, x_objets);
x_objets.Children.Add(
CreerEllipsoide(new Point3D(0, 0, 0), 2, 1, 0.5, 40, 40));
}
Figure 4-5

Figure 4-6
2*rayon_z
2*rayon_x

2*rayon_y
CHAPITRE 5

La modélisation du cylindre

Le cylindre est un solide avec une surface cylindrique délimitée par deux plans
parallèles. Nous allons voir la modélisation du cylindre circulaire plein et la
modélisation du cylindre circulaire creux (le tube par exemple).

1 - La géométrie du cylindre

Le cylindre est un solide avec une surface cylindrique délimitée par deux plans
parallèles. Une surface cylindrique est formée par le déplacement parallèle d’une
droite le long d’une courbe fermée. La figure 5-1 visualise géométriquement la
constitution d’un cylindre circulaire plein et la constitution d’un cylindre circulaire
creux.
Dans le cas du cylindre circulaire plein, le point A peut être repéré par ses
coordonnées sphériques (avec Rg le rayon du cercle et ϕ l’angle de rotation):
• xa = Rg*cos(ϕ)
• ya = 0
• za = -Rg*sin(ϕ)
Le point B a des coordonnées similaires à part une hauteur différente (H hauteur
du cylindre) d’où yb=H. Le cylindre creux est similaire au cylindre plein avec un
cercle extérieur de rayon Rg et un cercle intérieur plus petit de rayon Rp. La
position des points se calculera de la même façon en choisissant le rayon Rg ou Rp
d’appartenance du point considéré.
Partant de là, on s’aperçoit déjà que l’on va devoir modéliser quatre facettes dans
le cas général (cas du cylindre creux). Le cylindre plein sera en fait une exception,
puisque l’on choisira un rayon interne Rp de quantité nulle.
104 Guide pratique de la modélisation 3D avec WPF 4

Figure 5-1

B
Rg = rayon du cercle externe

point A:
xa = Rg*cos(φ)
ya = 0
za = -Rg*sin(φ)

cas du point B:
cylindre xb = Rg*cos(φ) = xa
plein: yb = H
zb = -Rg*sin(φ) = za
A
za
O φ
X
xa

Z Y

B Rg = rayon du cercle externe


Rp = rayon du cercle interne
C

cas du
cylindre
creux:

A
O
Copyright 2011 Patrice REY

D
X

Z
CHAPITRE 5 □ La modélisation du cylindre 105

2 - Modélisation de la facette cylindrique

Il y a donc quatre facettes à générer pour modéliser un cylindre de façon générale


(figure 5-2). Les facettes de quatre points, qui sont composées de deux triangles,
sont (avec l’ordre dans le sens contraire des aiguilles d’une montre):
• facette extérieure ABCD,
• facette du dessus BFGC,
• facette intérieure HGFE,
• facette du dessous EADH.
La figure 5-2 visualise les coordonnées de chacun de ces points en fonction de leur
position externe ou interne.
Figure 5-2
B
F point A:
xa = Rg*cos(φ)
C ya = 0
G za = -Rg*sin(φ)

point B:
facette ABCD
xb = Rg*cos(φ)
ya = H
facette BFGC zb = -Rg*sin(φ)

point F:
facette HGFE
xf = Rp*cos(φ)
yf = H
facette EADH zf = -Rp*sin(φ)

point E:
A xe = Rp*cos(φ)
ye = 0
E ze = -Rp*sin(φ)

H D
D’où une implémentation de quatre méthodes pour obtenir la position des points:
ObtenirPositonHauteExterne calcule la position du point de la surface externe
haute, ObtenirPositonHauteInterne calcule la position du point de la surface
interne haute, ObtenirPositonBasseExterne calcule la position du point de la
surface externe basse et ObtenirPositonBasseInterne calcule la position du point
de la surface interne basse.
106 Guide pratique de la modélisation 3D avec WPF 4
//
private Point3D ObtenirPositionHauteExterne(double ray_ext, double
phi, double hauteur) {
Point3D pt = new Point3D();
pt.X = +ray_ext * Math.Cos(phi * Math.PI / 180);
pt.Y = hauteur;
pt.Z = -ray_ext * Math.Sin(phi * Math.PI / 180);
return pt;
}
//
private Point3D ObtenirPositionHauteInterne(double ray_int, double
phi, double hauteur) {
Point3D pt = new Point3D();
pt.X = +ray_int * Math.Cos(phi * Math.PI / 180);
pt.Y = hauteur;
pt.Z = -ray_int * Math.Sin(phi * Math.PI / 180);
return pt;
}
//
private Point3D ObtenirPositionBasseExterne(double ray_ext, double
phi) {
Point3D pt = new Point3D();
pt.X = +ray_ext * Math.Cos(phi * Math.PI / 180);
pt.Y = 0;
pt.Z = -ray_ext * Math.Sin(phi * Math.PI / 180);
return pt;
}
//
private Point3D ObtenirPositionBasseInterne(double ray_int, double
phi) {
Point3D pt = new Point3D();
pt.X = +ray_int * Math.Cos(phi * Math.PI / 180);
pt.Y = 0;
pt.Z = -ray_int * Math.Sin(phi * Math.PI / 180);
return pt;
}
Copyright 2011 Patrice REY

Avec une boucle pour parcourir le nombre de division, en fonction de l’angle


angle_phi, on calcule la position des points que l’on positionne par rapport à
un centre de référence (centre du cercle interne bas). Puis on passe ces points
à la méthode GenererFacette(..) pour générer la facette avec sa texture et pour
l’ajouter au modèle.
CHAPITRE 5 □ La modélisation du cylindre 107
//
private Model3D CreerCylindre(Point3D centre, double ray_ext, double
ray_int, int div_phi, double hauteur) {
Model3DGroup modele_cylindre = null;
if (div_phi < 2 || ray_int >= ray_ext) {
return modele_cylindre;
}
else {
modele_cylindre = new Model3DGroup();
modele_cylindre.SetCurrentValue(NameProperty, «x_cylindre»);
double angle_phi = 360 / (div_phi - 1);
for (double i = 0; i < 360; i += angle_phi) {
//face abcd
Point3D pt_a = ObtenirPositionBasseExterne(ray_ext, i +
angle_phi);
pt_a += (Vector3D)centre;
Point3D pt_b = ObtenirPositionHauteExterne(ray_ext, i +
angle_phi, hauteur);
pt_b += (Vector3D)centre;
Point3D pt_c = ObtenirPositionHauteExterne(ray_ext, i,
hauteur);
pt_c += (Vector3D)centre;
Point3D pt_d = ObtenirPositionBasseExterne(ray_ext, i);
pt_d += (Vector3D)centre;
GenererFacette(pt_a, pt_b, pt_c, pt_d, modele_cylindre);
//bfgc
Point3D pt_f = ObtenirPositionHauteInterne(ray_int, i +
angle_phi,hauteur);
pt_f += (Vector3D)centre;
Point3D pt_g = ObtenirPositionHauteInterne(ray_int, i,
hauteur);
pt_g += (Vector3D)centre;
GenererFacette(pt_b, pt_f, pt_g, pt_c, modele_cylindre);
//hgfe
Point3D pt_h = ObtenirPositionBasseInterne(ray_int, i);
pt_h += (Vector3D)centre;
Point3D pt_e = ObtenirPositionBasseInterne(ray_int, i+angle_
phi);
pt_e += (Vector3D)centre;
GenererFacette(pt_h, pt_g, pt_f, pt_e, modele_cylindre);
//eadh
GenererFacette(pt_e, pt_a, pt_d, pt_h, modele_cylindre);
}
return modele_cylindre; } }
108 Guide pratique de la modélisation 3D avec WPF 4
Figure 5-3

Copyright 2011 Patrice REY

texture
employée
CHAPITRE 5 □ La modélisation du cylindre 109
La figure 5-3 montre les résultats obtenus avec un cylindre circulaire plein au milieu
et un cylindre circulaire creux autour.

//initialiser le viewport
private void InitialiserViewport() {
AjouterAxesCoordonnees(10, x_objets);
AjouterPlanDeTravail(10, x_objets);
x_objets.Children.Add(
CreerCylindre(new Point3D(0, 0, 0), 4, 3.5, 20, 0.5));
x_objets.Children.Add(
CreerCylindre(new Point3D(0, -1.5, 0), 2, 0, 20, 4));
}
CHAPITRE 6

La modélisation du cône

Le cône est un solide formé par l’intersection d’une surface conique avec un
plan quelconque. Nous allons voir la modélisation du cône circulaire droit et la
modélisation du cône circulaire tronqué. Avec un nombre de division particulier,
nous verrons une exception qu’est la pyramide et la pyramide tronquée.

1 - La géométrie du cône

Le cône est un solide formé par l’intersection d’une surface conique avec un plan
quelconque. Une surface conique est déterminée par une droite qui se déplace le
long d’une courbe et qui passe toujours par un point fixe (le sommet du cône). La
figure 6-1 montre la visualisation géométrique du cône.
Un point A qui appartient à la base du cône a comme coordonnées (avec Rb rayon
du cercle de la base):
• xa = Rb*cos(ϕ)
• ya = 0
• za = -Rb*sin(ϕ)
Un point B qui représente le sommet du cône dans le cas du cône circulaire droit,
a comme coordonnées (avec H hauteur du cône):
• xb = 0
• yb = H
• zb = 0
Un point B, dans le cas du cône circulaire tronqué, a comme coordonnées (avec H
hauteur du cône, et Rh rayon du cercle du sommet):
• xb = Rh*cos(ϕ)
• yb = H
• zb = -Rh*sin(ϕ)
112 Guide pratique de la modélisation 3D avec WPF 4

Figure 6-1
Y

Rb = rayon du cercle bas


Rh = rayon du cercle haut
point A:
xa = Rb*cos(φ)
B ya = 0
za = -Rb*sin(φ)

point B:
xb = Rh*cos(φ) = xa
yb = H
zb = -Rh*sin(φ) = za
A
za
O φ
X
xa

Y Rb = rayon du cercle bas


Rh = rayon du cercle haut

A
Copyright 2011 Patrice REY

O D
X

Z
CHAPITRE 6 □ La modélisation du cône 113
On s’aperçoit donc qu’il va falloir générer une facette rectangulaire et deux facettes
triangulaires dans le cas du cône circulaire tronqué (le cône circulaire droit étant
une exception avec le rayon du cercle du sommet de valeur nulle).

2 - La modélisation du cône

Trois facettes doivent être générées (figure 6-2) avec la facette rectangulaire ABCD,
avec la facette triangulaire BEC et la facette triangulaire DOA. Deux méthodes,
ObtenirPositionHaute et ObtenirPositionBasse, permettent de calculer la position
des points en fonction du cercle d’appartenance (cercle haut et cercle bas), de
l’angle phi (correspondant au nombre de division souhaité) et de la hauteur du
cône.
Figure 6-2

Y Rb = rayon du cercle bas


Rh = rayon du cercle haut
Y B
B

C E C
Rh

A
O D
X A
O D X
Z
Z Rb

//
private Point3D ObtenirPositionHaute(double ray_haut, double phi,
double hauteur) {
Point3D pt = new Point3D();
pt.X = +ray_haut * Math.Cos(phi * Math.PI / 180);
pt.Y = hauteur;
pt.Z = -ray_haut * Math.Sin(phi * Math.PI / 180);
return pt;
}
114 Guide pratique de la modélisation 3D avec WPF 4
//
private Point3D ObtenirPositionBasse(double ray_bas, double phi) {
Point3D pt = new Point3D();
pt.X = +ray_bas * Math.Cos(phi * Math.PI / 180);
pt.Y = 0;
pt.Z = -ray_bas * Math.Sin(phi * Math.PI / 180);
return pt;
}

Pour modéliser un cône, la méthode CreerCone(..) reçoit, en paramètre, un point


de référence centre, un rayon ray_haut du cercle du sommet, un rayon ray_bas du
cercle de la base, un nombre de division div_phi, et une hauteur hauteur du cône.
Cette méthode calcule, par un parcours de l’angle angle_phi, les points de la face
ABCD, de la face BEC et de la face DOA.

//
private Model3D CreerCone(Point3D centre, double ray_bas,
double ray_haut, int div_phi, double hauteur) {
Model3DGroup modele_cone = null;
if (div_phi < 2) {
return modele_cone;
}
else {
modele_cone = new Model3DGroup();
modele_cone.SetCurrentValue(NameProperty, «x_cone»);
double angle_phi = 360 / (div_phi - 1);
for (double i = 0; i < 360; i += angle_phi) {
//face abcd
Point3D pt_a = ObtenirPositionBasse(ray_bas, i + angle_phi);
pt_a += (Vector3D)centre;
Point3D pt_b = ObtenirPositionHaute(ray_haut, i + angle_phi,
hauteur);
pt_b += (Vector3D)centre;
Point3D pt_c = ObtenirPositionHaute(ray_haut, i, hauteur);
pt_c += (Vector3D)centre;
Copyright 2011 Patrice REY

Point3D pt_d = ObtenirPositionBasse(ray_bas, i);


pt_d += (Vector3D)centre;
GenererFacette(pt_a, pt_b, pt_c, pt_d, modele_cone);
//triangle bec
Point3D pt_e = new Point3D(0, hauteur, 0);
pt_e += (Vector3D)centre;
GenererTriangle(pt_b, pt_e, pt_c, modele_cone);
//triangle doa
CHAPITRE 6 □ La modélisation du cône 115
GenererTriangle(pt_d, centre, pt_a, modele_cone);
}
return modele_cone;
}
}

La méthode GenererFacette(..) génère une facette rectangulaire comme on l’a déjà


vu et la méthode GenererTriangle(..) génère une facette triangulaire. A noter que
les coordonnées de mappage pour un triangle sont différentes avec une texture
représentant un triangle (bas de la figure 6-3).

//
private void GenererTriangle(Point3D pt_0, Point3D pt_1,
Point3D pt_2,
Model3DGroup modele_sphere) {
GeometryModel3D facette = new GeometryModel3D();
MeshGeometry3D geometrie = new MeshGeometry3D();
geometrie.Positions.Add(pt_0);
geometrie.Positions.Add(pt_1);
geometrie.Positions.Add(pt_2);
geometrie.TriangleIndices.Add(0);
geometrie.TriangleIndices.Add(1);
geometrie.TriangleIndices.Add(2);
geometrie.TextureCoordinates.Add(new Point(0,1));
geometrie.TextureCoordinates.Add(new Point(0, 0));
geometrie.TextureCoordinates.Add(new Point(1, 1));
facette.Geometry = geometrie;
DiffuseMaterial mat_diffuse = new DiffuseMaterial();
ImageBrush img_brush = new ImageBrush();
img_brush.ImageSource = new BitmapImage(
new Uri(«pack://application:,,/chapitre06/image/
texture_generique_3_triangle.png», UriKind.Absolute));
mat_diffuse.Brush = img_brush;
facette.Material = mat_diffuse;
facette.BackMaterial = new DiffuseMaterial(Brushes.DarkGray);
modele_sphere.Children.Add(facette);
}

La figure 6-3 visualise la réalisation d’un cône circulaire droit avec des vues sur
le côté, le dessus et le dessous (ici le rayon de la base est de 1 unité, le rayon du
sommet est nul, le nombre de division est de 30, et la hauteur est de 2.5 unités).
116 Guide pratique de la modélisation 3D avec WPF 4
//initialiser le viewport
private void InitialiserViewport() {
AjouterAxesCoordonnees(10, x_objets);
AjouterPlanDeTravail(10, x_objets);
x_objets.Children.Add(CreerCone(new Point3D(0, 0, 0), 1, 0, 30,
2.5));
}
Figure 6-3

dessus du
côté du cône cône

(0,0)

dessous du
cône

(0,1) (1,1)

texture employée avec mappage


des coordonnées pour générer un
triangle

La figure 6-4 visualise la réalisation d’un cône circulaire tronqué avec des vues sur
Copyright 2011 Patrice REY

le côté, le dessus et le dessous (ici le rayon de la base est de 1 unité, le rayon du


sommet est de 0.5 unité, le nombre de division est de 30, et la hauteur est de 1
unité).

//initialiser le viewport
private void InitialiserViewport() {
CHAPITRE 6 □ La modélisation du cône 117
AjouterAxesCoordonnees(10, x_objets);
AjouterPlanDeTravail(10, x_objets);
x_objets.Children.Add(CreerCone(new Point3D(0, 0, 0), 1, 0.5, 30,
1));
}

Figure 6-4

3 - Des cônes particuliers

En jouant sur le nombre de division, on peut obtenir des cônes particuliers. Par
exemple sur la figure 6-5, un nombre de division égal à 5, ce qui provoque 4 faces,
permet de générer une pyramide.

//initialiser le viewport
private void InitialiserViewport() {
AjouterAxesCoordonnees(10, x_objets);
AjouterPlanDeTravail(10, x_objets);
x_objets.Children.Add(CreerCone(new Point3D(0, 0, 0), 1, 0, 5, 2));
}
118 Guide pratique de la modélisation 3D avec WPF 4
Figure 6-5

Et si le haut de la pyramide est tronqué, on obtient comme sur la figure 6-6, une
pyramide tronquée.

//initialiser le viewport
Copyright 2011 Patrice REY

private void InitialiserViewport() {


AjouterAxesCoordonnees(10, x_objets);
AjouterPlanDeTravail(10, x_objets);
x_objets.Children.Add(CreerCone(new Point3D(0, 0, 0), 1, 0.5, 5,
1));
}
CHAPITRE 6 □ La modélisation du cône 119
Figure 6-6

Comme sur la figure 6-7, on peut ajouter différentes configurations de cône en


précisant leurs paramètres et le positionnement sur la scène comme point de
référence. On positionne:
• au point de référence (0,0,0) un cône circulaire droit de hauteur 2.5 unités.
• au point de référence (-2.5,0,0) un cône circulaire tronqué de hauteur 1 unité.
• au point de référence (2.5,0,0) une pyramide de hauteur 2 unités.
• au point de référence (0,0,2.5) une pyramide tronquée de hauteur 1 unité.

//initialiser le viewport
private void InitialiserViewport() {
AjouterAxesCoordonnees(10, x_objets);
AjouterPlanDeTravail(10, x_objets);
x_objets.Children.Add(CreerCone(new Point3D(0, 0, 0),
1, 0, 30, 2.5));
x_objets.Children.Add(CreerCone(new Point3D(-2.5, 0, 0),
1, 0.5, 30, 1));
x_objets.Children.Add(CreerCone(new Point3D(2.5, 0, 0),
1, 0, 5, 2));
x_objets.Children.Add(CreerCone(new Point3D(0, 0, 2.5),
1, 0.5, 5, 1));
}
120 Guide pratique de la modélisation 3D avec WPF 4
Figure 6-7

Copyright 2011 Patrice REY


CHAPITRE 7

La modélisation du tore

Le tore est un solide engendré par la rotation d’un cercle autour d’une droite.
Nous allons voir la modélisation du tore avec notamment le tore dit «ouvert», le
tore dit «à collier nul» et le tore dit «croisé».

1 - La géométrie du tore

Le tore désigne un solide géométrique de l’espace euclidien 3D engendré par la


rotation d’un cercle C de rayon r autour d’une droite affine D située dans son plan
à une distance R de son centre.
Si R est inférieur à r, on est en présence d’un tore dit «croisé» (le tore ressemble
visuellement à une citrouille). Si R est égal à r, on est en présence d’un tore dit «à
collier nul». Si R est supérieur à r, on est en présence d’un tore dit «ouvert» (le
tore ressemble à une chambre à air). La figure 7-1 visualise géométriquement la
réalisation d’un tore dit «ouvert».
Un point A sur le tore sera localisé par ses coordonnées sphériques suivantes (avec
R la distance de l’axe Y au centre du cercle, et r le rayon du cercle):
• xa = ( R + r*cos(β)) * cos(ϕ)
• ya = r*sin(β)
• za = -( R + r*cos(β)) * sin(ϕ)
Intuitivement, on déduit que l’on va devoir générer des facettes rectangulaires
avec quatre points.
122 Guide pratique de la modélisation 3D avec WPF 4
Figure 7-1

Y
point A:
xa = (R + r*cos(β))*cos(φ)
ya = r*sin(β)
za = -(R+r*cos(β))*sin(φ)

A
r
O1 φ β
X
O2

Z R

2 - La modélisation du tore

Comme le schématise la figure 7-2, on va générer des facettes rectangulaires en


fonction d’un nombre de division (angle ϕ) dans le plan (OX,OZ) et d’un nombre de
division (angle β) dans le plan (OX,OY).
Pour un angle ϕ donné, on fera varier l’angle β de 0 à 2π. L’angle ϕ variera quant à
lui de 0 à 2π. Le nombre de division div_phi permettra de calculer le pas pour l’angle
ϕ et le nombre de division div_beta permettra de calculer le pas pour l’angle β.
Plus les nombres de division seront importants, plus les facettes seront petites et
la définition meilleure. Le bas de la figure 7-2 montre une partie du tore pour un
angle ϕ allant de 0 à π/2. Copyright 2011 Patrice REY

//position des points


private Point3D ObtenirPosition(double dist_r, double ray_cercle,
double phi, double beta) {
Point3D pt = new Point3D();
pt.X = (dist_r + ray_cercle * Math.Cos(beta * Math.PI / 180)) *
Math.Cos(phi * Math.PI / 180);
pt.Y = ray_cercle * Math.Sin(beta * Math.PI / 180);
pt.Z = -(dist_r + ray_cercle * Math.Cos(beta * Math.PI / 180)) *
CHAPITRE 7 □ La modélisation du tore 123
Math.Sin(phi * Math.PI / 180);
return pt;
}
Figure 7-2

R
B
r C
β A
point A:
xa = (R + r*cos(β))*cos(φ) D
φ
ya = r*sin(β)
za = -(R+r*cos(β))*sin(φ)
X

tore généré avec


l’angle φ variant
de 0 à 90 degrés
124 Guide pratique de la modélisation 3D avec WPF 4
La méthode CreerTore(..) permet de générer un tore en fonction d’un centre de
référence centre, d’une distance dist_r de la droite au centre du cercle, d’un rayon
ray_cercle du cercle, d’un nombre de division div_phi et d’un nombre de division
div_beta.

//generer le tore
private Model3D CreerTore(Point3D centre, double dist_r, double
ray_cercle, int div_phi, int div_beta) {
if (div_phi < 2 || div_beta < 2) {
return v_modele_tore;
}
else {
v_modele_tore = new Model3DGroup();
v_modele_tore.SetCurrentValue(NameProperty, «x_tore»);
double angle_phi = 360 / (div_phi - 1);
double angle_beta = 360 / (div_beta - 1);
for (double i = 0; i < 360; i += angle_phi) {
for (double j = 0; j < 360; j += angle_beta) {
//face abcd
Point3D pt_a = ObtenirPosition(dist_r, ray_cercle,
i + angle_phi, j);
pt_a += (Vector3D)centre;
Point3D pt_b = ObtenirPosition(dist_r, ray_cercle,
i + angle_phi, j + angle_beta);
pt_b += (Vector3D)centre;
Point3D pt_c = ObtenirPosition(dist_r, ray_cercle,
i, j + angle_beta);
pt_c += (Vector3D)centre;
Point3D pt_d = ObtenirPosition(dist_r, ray_cercle, i, j);
pt_d += (Vector3D)centre;
GenererFacette(pt_a, pt_b, pt_c, pt_d, v_modele_tore);
}
}
return v_modele_tore;
}
}
Copyright 2011 Patrice REY

On peut visualiser le résultat obtenu pour le tore dit «ouvert» (forme d’une
chambre à air) sur la figure 7-3. Les vues du dessus et du dessous permettent de
bien apprécier la modélisation du tore ouvert.
CHAPITRE 7 □ La modélisation du tore 125

Figure 7-3
126 Guide pratique de la modélisation 3D avec WPF 4

3 - Différents tores

Le sélecteur permet de choisir le type de tore à générer. Par exemple, le choix:


• «type de tore ouvert» génère un tore centré sur l’origine du repère avec R=2,
r=1, div_phi=20 et div_beta=20.
• «type de tore à collier nul» génère un tore centré sur l’origine du repère avec
R=1, r=1, div_phi=20 et div_beta=20.
• «type de tore croisé» génère un tore centré sur l’origine du repère avec R=0.5,
r=1, div_phi=20 et div_beta=20.

private void x_select_SelectionChanged(object sender,


SelectionChangedEventArgs e) {
if (this.IsLoaded == true) {
if (v_modele_tore != null) {
x_objets.Children.Remove(v_modele_tore);
}
switch (x_select.SelectedIndex) {
case 0:
x_objets.Children.Add(
CreerTore(new Point3D(0, 0, 0), 2, 1, 20, 20));
break;
case 1:
x_objets.Children.Add(
CreerTore(new Point3D(0, 0, 0), 1, 1, 20, 20));
break;
case 2:
x_objets.Children.Add(
CreerTore(new Point3D(0, 0, 0), 0.5, 1, 20, 20));
break;
}
}
}
Copyright 2011 Patrice REY

La figure 7-4 montre le résultat obtenu pour le tore dit «à collier nul» et la figure
7-5 montre le résultat obtenu pour le tore dit «croisé».
CHAPITRE 7 □ La modélisation du tore 127
Figure 7-4

Figure 7-5
CHAPITRE 8

Les géométries 3D personnalisées

Nous avons vu que les géométries des modèles 3D pouvaient être exprimées en
XAML et en code procédural. Très souvent, il s’avère pratique de pouvoir modéliser
en XAML tout comme en code procédural, un modèle 3D avec des propriétés
spécifiques déterminées à l’avance et en fonction d’une utilisation ultérieure.
Cette façon de faire passe par une personnalisation des objets 3D avec pour but
une réutilisation à volonté, rapide et précise.
Ce chapitre est consacré à la façon de créer ces modèles personnalisés et
réutilisables. Tout cela demande un peu d’ordre, et donc, nous aborderons au
préalable la façon de configurer le projet d’une façon optimale en vue de son
déploiement.

1 - La configuration du projet

Ce que nous voulons réaliser c’est un contrôle utilisateur par exemple qui fait
référence à du code stocké dans une dll (dynamic link library) ou bibliothèque de
liens dynamiques. Dans le cadre du système d’exploitation Windows, une dll peut
contenir du code ou des ressources qui sont alors rendus disponibles pour d’autres
applications.
Notre dll, intitulée Geo3d, sera accessible par des programmes externes ou par
des contrôles personnalisés. Dans cette dll, on stockera les modèles 3D avec leurs
géométries personnalisées. En faisant référence à cette dll, on pourra accéder à ces
objets 3D par code procédural ou bien directement en XAML (en notifiant l’espace
de noms concerné). Tout est une question d’ordre. C’est pour cela que nous allons
configurer le projet à la fois pour s’y retrouver et pour acquérir une façon de faire
qui sera identique à chaque fois.
La première étape consiste à créer un dossier qui va contenir l’exécutable de
l’application ainsi que les dll requises. Par exemple, à côté du dossier contenant le
projet de Visual Studio 2010, on ajoute un dossier intitulé «GuideModelisation3D-
Exe» (fig 8-1).
130 Guide pratique de la modélisation 3D avec WPF 4
Figure 8-1

La deuxième étape consiste à personnaliser les propriétés du projet


GuideModelisation3D en choisissant, dans le menu projet, l’item «propriétés de
GuideModelisation3D...» (figure 8-2).
Figure 8-2

Dans l’onglet «application» (figure 8-3), choisir comme type de sortie l’item
«application windows», comme objet de démarrage l’item «GuideModelisation3D.
App», et comme icône représentant l’exécutable l’item «contenu_icone\icone_
exe.ico» (fichier au format .ico se trouvant dans le sous-dossier icone du dossier
contenu).
Dans l’onglet «générer» (figure 8-4), cliquez sur le bouton parcourir et sélectionnez
Copyright 2011 Patrice REY

le dossier de l’exécutable que l’on a créé précédemment.


Enregistrez le projet puis compilez le projet par la touche F6. Cela provoque la
génération de l’exécutable dans le dossier «GuideModelisation3D-Exe» (figure
8-5).
CHAPITRE 8 □ Les géométries 3D personnalisées 131
Figure 8-3

Figure 8-4

Figure 8-5
132 Guide pratique de la modélisation 3D avec WPF 4
La troisième étape consiste à ajouter au projet de base «Solution
GuideModelisation3D» un nouveau projet, de type Bibliothèque de classes et
intitulé Geo3d (figure 8-6).
Figure 8-6

Dans les propriétés du projet Geo3D (en procédant de la même manière que tout
à l’heure), dans l’onglet «générer», choisir dans la section «sortie» un chemin de
sortie qui pointe sur le dossier de l’exécutable (en cliquant sur le bouton parcourir).
La figure 8-7 montre le résultat.

Figure 8-7

Copyright 2011 Patrice REY


CHAPITRE 8 □ Les géométries 3D personnalisées 133
Enregistrez le projet Geo3d puis compilez le projet en appuyant sur F6. La
bibliothèque de classes Geo3d.dll est générée dans le dossier de sortie de
l’exécutable (figure 8-8).
Figure 8-8

La quatrième et dernière étape consiste à ajouter les références de la dll pour son
utilisation. Dans le dossier «références» du projet GuideModelisation3D, cliquez
droit dessus et choisissez «ajouter une référence...» (figure 8-9). Sélectionnez
l’onglet «projets» puis «Geo3d» et cliquez sur OK.

Figure 8-9

Et pour terminer, dans le projet Geo3D, ajoutez les références PresentationCore,


PresentationFramework et WindowsBase (bibliothèques nécessaires à la 3D). Le
résultat obtenu est celui de la figure 8-10.
134 Guide pratique de la modélisation 3D avec WPF 4
Figure 8-10

Maintenant le projet est configuré correctement et on pourra accéder à la


bibliothèque de classes Geo3d.dll dans laquelle on va intégrer les modèles 3D
réutilisables. Dans vos applications futures, vous aurez juste à copier la dll dans
le dossier de l’exécutable, et vous pourrez y accéder en ajoutant une référence à
cette dll comme on l’a fait plus haut.

2 - La géométrie personnalisée des axes de coordonnées

La création de modèles 3D est passionnante, mais faire en sorte que votre objet
3D réalisé puisse réagir aux entrées clavier, au focus et aux événements est encore
plus attrayant. La solution consiste à faire hériter votre modèle 3D de la classe
UIElement3D.

2.1 - Hériter de UIElement3D

UIElement3D est une classe de base pour les implémentations au niveau du noyau
WPF, reposant sur les éléments WPF et les caractéristiques de présentation de
base. UIElement3D est une classe de base abstraite à partir de laquelle vous pouvez
Copyright 2011 Patrice REY

dériver des classes pour représenter des éléments 3D spécifiques. La majeure


partie du comportement d’entrée, de mise en focus et de traitement d’événements
pour des éléments 3D est généralement définie dans la classe UIElement3D. Cela
inclut les événements liés à l’entrée au niveau du clavier, de la souris et du stylet,
ainsi que les propriétés d’état qui s’y rattachent. Ces événements correspondent
souvent à des événements routés et de nombreux événements associés à l’entrée
CHAPITRE 8 □ Les géométries 3D personnalisées 135
présentent aussi bien une version de routage par propagation qu’une version
par tunneling. Ces événements doubles sont en général les événements les plus
intéressants pour contrôler des objets.
L’objet UIElement3D présente les fonctionnalités suivantes définies spécialement
par la classe UIElement3D :
• il peut répondre à l’entrée de l’utilisateur (y compris contrôler la destination
d’envoi de l’entrée à travers la gestion d’événements de routage ou le routage
de commandes).
• il peut déclencher des événements routés qui suivent un itinéraire à travers
l’arborescence logique d’éléments.
La démarche consiste à créer un contrôle qui hérite de UIElement3D, et à lui
ajouter ses propriétés de dépendance spécifiques. Pour cela nous créons une
nouvelle classe intitulée Repere, qui hérite de UIElement3D. On redéfinit la
méthode héritée OnUpdateModel() qui participe aux opérations de rendu en cas
de substitution dans une classe dérivée.
Lorsque vous dérivez une classe à partir de la classe UIElement3D, vous pouvez
utiliser cette méthode en combinaison avec la méthode InvalidateModel() pour
actualiser le modèle de l’élément. Vous devez uniquement appeler cette méthode
dans des scénarios avancés. C’est notamment le cas si la classe dérivée possède
plusieurs propriétés qui affectent l’apparence et que vous ne souhaitez mettre à jour
le modèle sous-jacent qu’une seule fois. Au sein de la méthode OnUpdateModel()
vous pouvez mettre à jour la propriété Visual3DModel de la classe Visual3D. A
noter que cette méthode ne possède aucune implémentation par défaut dans la
classe UIElement3D.

namespace Geo3d {
public class Repere : UIElement3D {
...
//redefinition ------------------------------------
protected override void OnUpdateModel() {
...
}
...
}

On définit une propriété de dépendance Modele pour Repere et on affecte à cette


propriété un Model3DGroup intitulé groupe_axe. Ce modèle contient les trois
axes X, Y et Z.
136 Guide pratique de la modélisation 3D avec WPF 4
//-------------------------------------------------
protected override void OnUpdateModel() {
Model3DGroup groupe_axe = new Model3DGroup();
...
Modele = groupe_axe;
}

La démarche qui consiste à ajouter une propriété de dépendance s’effectue


toujours de la même façon quelque soit le type de la propriété de dépendance à
définir. Prenons le cas de la propriété de dépendance Modele dont nous détaillons
ici la façon de l’implémenter.
On commence par ajouter une propriété publique statique, en lecture seule
(readonly), de type DependencyProperty, nommée ProprieteModele. Sa déclaration
passe par l’emploi de la méthode statique DependencyProperty.Register(..) qui
reçoit en paramètre:
• une chaîne qui indique le nom de la propriété de dépendance à inscrire (ici
Modele).
• un type de propriété correspondant à cette propriété (ici un type Model3D).
• le type du propriétaire qui inscrit la propriété de dépendance (ici c’est Repere).
• une instance de PropertyMetadata qui représente les métadonnées de
propriété pour la propriété de dépendance (ici on passe le nom de la méthode
statique, ProprieteModeleModifiee, qui modifie la propriété de dépendance).
La méthode ProprieteModeleModifiee récupère l’objet de dépendance d, de
type Repere, et définit sa propriété héritée Visual3DModel par l’affectation de la
propriété de dépendance Repere.Modele. Une fois la propriété de dépendance
définie, on déclare les accesseurs, get et set, pour lire et écrire la propriété Modele.

//la propriete Modele pour le repere


private static readonly DependencyProperty ProprieteModele =
DependencyProperty.Register(«Modele»,
typeof(Model3D),
typeof(Repere),
Copyright 2011 Patrice REY

new PropertyMetadata(ProprieteModeleModifiee));
//methode pour la modification du modele
private static void ProprieteModeleModifiee(DependencyObject d,
DependencyPropertyChangedEventArgs e) {
Repere le_repere = (Repere)d;
le_repere.Visual3DModel = le_repere.Modele;
}
//accesseurs pour la propriete modele
CHAPITRE 8 □ Les géométries 3D personnalisées 137
private Model3D Modele {
get {
return (Model3D)GetValue(ProprieteModele);
}
set {
SetValue(ProprieteModele, value);
}
}

Ce que nous avons besoin aussi comme propriété de dépendance, c’est celle qui
stocke la longueur de l’axe. Nous déclarons une propriété de dépendance nommée
LongueurDemiAxe, qui stocke la longueur d’un demi-axe (le demi-axe côté positif
étant égal au demi-axe côté négatif). Cette propriété est de type double, son type
propriétaire est Repere, et l’instance de PropertyMetadata spécifie la méthode
ProprieteLongueurDemiAxeModifiee comme méthode qui invalide le modèle pour
le redessiner ainsi qu’une valeur 1.0, de type double comme valeur d’initialisation.
La figure 8-11 montre que si on n’explicite pas la longueur du demi-axe, celle-ci est
initialisée à 1 unité (valeur d’initialisation par défaut).

//-----------------------------------------
//la propriete LongueurDemiAxe
private static readonly DependencyProperty ProprieteLongueurDemiAxe =
DependencyProperty.Register(«LongueurDemiAxe»,
typeof(double),
typeof(Repere),
new PropertyMetadata(1.0, ProprieteLongueurDemiAxeModifiee));
//
private static void ProprieteLongueurDemiAxeModifiee(DependencyObject
d, DependencyPropertyChangedEventArgs e) {
Repere le_repere = (Repere)d;
le_repere.Visual3DModel = le_repere.Modele;
}
//
public double LongueurDemiAxe {
get {
return (double)GetValue(ProprieteLongueurDemiAxe);
}
set {
SetValue(ProprieteLongueurDemiAxe, value);
}
}
138 Guide pratique de la modélisation 3D avec WPF 4
Figure 8-11

Copyright 2011 Patrice REY

La figure 8-12 montre que si on explicite la longueur du demi-axe par exemple


à une valeur de 10 unités, celle-ci est initialisée à 10 unités. Puis la méthode
d’invalidation du modèle est appelée suite au changement de la valeur de la
propriété de dépendance.
CHAPITRE 8 □ Les géométries 3D personnalisées 139
Figure 8-12

2.2 - Générer le modèle

Maintenant on va générer le modèle qui contient les trois axes de coordonnées. La


modélisation des axes est identique à celle que l’on a réalisée à la fin du chapitre 3.
Le modèle groupe_axe, de type Model3dGroup, reçoit de nouveaux enfants sous
forme de Model3DGroup représentant un axe, par la méthode GenererMaillage.

//-------------------------------------------------
protected override void OnUpdateModel() {
Model3DGroup groupe_axe = new Model3DGroup();
groupe_axe.Children.Add(GenererMaillage(LongueurDemiAxe, «x»));
groupe_axe.Children.Add(GenererMaillage(LongueurDemiAxe, «y»));
groupe_axe.Children.Add(GenererMaillage(LongueurDemiAxe, «z»));
140 Guide pratique de la modélisation 3D avec WPF 4
Modele = groupe_axe;
}

En fonction d’une longueur de demi-axe et d’un type d’axe (sous forme d’une
chaîne de type string comme «x», «y» ou «z»), la méthode GenererMaillage(..)
génère le modèle du repère.

//generer la geometrie du maillage


private Model3DGroup GenererMaillage(double long_demi_axe, string
type_axe) {
double dist_x = 0;
double dist_y = 0;
double dist_z = 0;
double prof = 0.01;
Model3DGroup un_axe = new Model3DGroup();
switch (type_axe) {
case «x»: dist_x = long_demi_axe; dist_y = prof; dist_z = prof;
break;
case «y»: dist_x = prof; dist_y = long_demi_axe; dist_z = prof;
break;
case «z»: dist_x = prof; dist_y = prof; dist_z = long_demi_axe;
break;
}
Point3D pt1 = new Point3D(+dist_x, -dist_y, +dist_z); //+x -y +z
Point3D pt2 = new Point3D(+dist_x, +dist_y, +dist_z); //+x +y +z
Point3D pt3 = new Point3D(-dist_x, +dist_y, +dist_z); //-x +y +z
Point3D pt4 = new Point3D(-dist_x, -dist_y, +dist_z); //-x -y +z
Point3D pt5 = new Point3D(+dist_x, -dist_y, -dist_z); //+x -y -z
Point3D pt6 = new Point3D(+dist_x, +dist_y, -dist_z); //+x +y -z
Point3D pt7 = new Point3D(-dist_x, +dist_y, -dist_z); //-x +y -z
Point3D pt8 = new Point3D(-dist_x, -dist_y, -dist_z); //-x -y -z
//1234 avant
GeometryModel3D face_avant = ModeliserFaceAxe(pt1, pt2, pt3, pt4);
un_axe.Children.Add(face_avant);
//5621 droite
Copyright 2011 Patrice REY

GeometryModel3D face_droite = ModeliserFaceAxe(pt5, pt6, pt2, pt1);


un_axe.Children.Add(face_droite);
//8765 arriere
GeometryModel3D face_arriere = ModeliserFaceAxe(pt8, pt7, pt6,
pt5);
un_axe.Children.Add(face_arriere);
//4378 gauche
GeometryModel3D face_gauche = ModeliserFaceAxe(pt4, pt3, pt7, pt8);
CHAPITRE 8 □ Les géométries 3D personnalisées 141
un_axe.Children.Add(face_gauche);
//2673 dessus
GeometryModel3D face_dessus = ModeliserFaceAxe(pt2, pt6, pt7, pt3);
un_axe.Children.Add(face_dessus);
//5148 dessous
GeometryModel3D face_dessous = ModeliserFaceAxe(pt5, pt1, pt4,
pt8);
un_axe.Children.Add(face_dessous);
return un_axe;
}

La face d’un axe est générée par la méthode ModeliserFaceAxe(..). On affecte à la


propriété Material de la face, une couleur noire (Brushes.Black).

//face d’un axe


private GeometryModel3D ModeliserFaceAxe(Point3D pt1, Point3D pt2,
Point3D pt3, Point3D pt4) {
GeometryModel3D face = new GeometryModel3D();
MeshGeometry3D maillage = new MeshGeometry3D();
maillage.Positions.Add(pt1);
maillage.Positions.Add(pt2);
maillage.Positions.Add(pt3);
maillage.Positions.Add(pt4);
maillage.TriangleIndices.Add(0);
maillage.TriangleIndices.Add(1);
maillage.TriangleIndices.Add(2);
maillage.TriangleIndices.Add(2);
maillage.TriangleIndices.Add(3);
maillage.TriangleIndices.Add(0);
maillage.TextureCoordinates.Add(new Point(1, 1));
maillage.TextureCoordinates.Add(new Point(1, 0));
maillage.TextureCoordinates.Add(new Point(0, 0));
maillage.TextureCoordinates.Add(new Point(0, 1));
maillage.Freeze();
face.Geometry = maillage;
face.Material = new DiffuseMaterial(Brushes.Black);
return face;
}

Il ne reste plus qu’à ajouter le modèle Repere dans le fichier Index08.xaml. Pour
cela il faut commencer par ajouter une référence à l’espace de noms qui contient
le modèle. On préfixe cet espace de noms par «objet» ici en écrivant xmlns:objet =
«clr-namespace:Geo3d;assembly=Geo3d».
142 Guide pratique de la modélisation 3D avec WPF 4
<UserControl x:Class='GuideModelisation3D.Index08'
xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
xmlns:mc='http://schemas.openxmlformats.org/markup-
compatibility/2006'
xmlns:d='http://schemas.microsoft.com/expression/blend/2008'
xmlns:objet='clr-namespace:Geo3d;assembly=Geo3d' mc:Ignorable='d'
Loaded='UserControl_Loaded' Width='744' Height='768'>
<Canvas Name='x_cnv_root' Background='White' Width='744'
Height='768'
HorizontalAlignment='Left' VerticalAlignment='Top'>
...
</Canvas>
</UserControl>

On instancie un objet Repere, nommé x_repere, de longueur de demi-axe fixée


à 10 unités, par <objet:Repere x:Name = «x_repere» LongueurDemiAxe = «10»
></objet:Repere>. L’objet x_repere est un UIElement3D donc il doit être positionné
dans le conteneur x_scene, de type ContainerUIElement3D. La figure 8-13 montre
le résultat obtenu. Le repère est bien intégré à la scène 3D et on peut utiliser le
trackball pour faire tourner la scène.

<Viewport3D ClipToBounds='True' Height='700'


MouseLeftButtonDown='x_viewport_MouseLeftButtonDown'
MouseLeftButtonUp='x_viewport_MouseLeftButtonUp'
MouseMove='x_viewport_MouseMove' Name='x_viewport'
Width='700'>
<Viewport3D.Camera>
<PerspectiveCamera x:Name='x_camera' FieldOfView='80'
LookDirection='-2,-2,-5' Position='2,2,5'
UpDirection='0 1 0' />
</Viewport3D.Camera>
<ContainerUIElement3D x:Name='x_scene'>
<!-- eclairage -->
<ModelUIElement3D x:Name='x_eclairage'>
Copyright 2011 Patrice REY

<Model3DGroup x:Name='x_lumiere'>
<AmbientLight Color='White'></AmbientLight>
</Model3DGroup>
</ModelUIElement3D>
<!-- repere avec axes -->
<objet:Repere x:Name='x_repere' LongueurDemiAxe='10'>
</objet:Repere>
CHAPITRE 8 □ Les géométries 3D personnalisées 143
</ContainerUIElement3D>
</Viewport3D>
Figure 8-13

3 - La géométrie personnalisée du plan de travail

Nous allons construire un plan de travail personnalisé sous forme d’un plan
quadrillé (comme on l’a vu à la fin du chapitre 3) dont son centre sera l’origine du
repère de coordonnée. Des propriétés de dépendance vont être ajoutées pour
personnaliser ce plan de travail:
• avec la propriété de dépendance LongueurX qui définit la longueur totale du
plan de travail suivant l’axe X et qui est initialisée à 2 unités (1 unité de chaque
côté).
• avec la propriété de dépendance LongueurZ qui définit la longueur totale du
144 Guide pratique de la modélisation 3D avec WPF 4
plan de travail suivant l’axe Z et qui est initialisée à 2 unités (1 unité de chaque
côté).
• avec la propriété de dépendance LongueurPas qui définit le nombre de division
par unité pour les 2 axes X et Z.
• avec la propriété de dépendance CouleurGrille qui définit le pinceau couleur
utilisé pour colorer le plan quadrillé.
Dans le projet Geo3d, on ajoute une classe PlanDeTravail (fichier PlanDeTravail.cs)
et on la fait hériter de la classe UIElement3D. On ajoute, comme précédemment,
une propriété de dépendance Modele pour le rendu de la grille.
Les longueurs LongueurX et LongueurZ, de type double, représentent les longueurs
totales du plan de travail suivant respectivement l’axe X et l’axe Z (longueurs
initialisées à 2 unités).

//la propriete LongueurX (longueur centré sur l’origine suivant X)


private static readonly DependencyProperty ProprieteLongueurX =
DependencyProperty.Register(«LongueurX»,
typeof(double),
typeof(PlanDeTravail),
new PropertyMetadata(2.0, ProprieteLongueurXModifiee));
private static void ProprieteLongueurXModifiee(DependencyObject d,
DependencyPropertyChangedEventArgs e) {
PlanDeTravail le_plan = (PlanDeTravail)d;
le_plan.InvalidateModel();
}
public double LongueurX {
get {
return (double)GetValue(ProprieteLongueurX);
}
set {
SetValue(ProprieteLongueurX, value);
}
}
//la propriete LongueurZ (longueur centré sur l’origine suivant Z)
private static readonly DependencyProperty ProprieteLongueurZ =
Copyright 2011 Patrice REY

DependencyProperty.Register(«LongueurZ»,
typeof(double),
typeof(PlanDeTravail),
new PropertyMetadata(2.0, ProprieteLongueurZModifiee));
private static void ProprieteLongueurZModifiee(DependencyObject d,
DependencyPropertyChangedEventArgs e) {
PlanDeTravail le_plan = (PlanDeTravail)d;
le_plan.InvalidateModel();
CHAPITRE 8 □ Les géométries 3D personnalisées 145
}
public double LongueurZ {
get {
return (double)GetValue(ProprieteLongueurZ);
}
set {
SetValue(ProprieteLongueurZ, value);
}
}

La propriété de dépendance LongueurPas, de type double, est initialisée à 1 ce qui


signifie aucune subdivision (2 signifierait une subdivision par unité).

//la propriete LongueurPas


private static readonly DependencyProperty ProprieteLongueurPas =
DependencyProperty.Register(«LongueurPas»,
typeof(double),
typeof(PlanDeTravail),
new PropertyMetadata(1.0, ProprieteLongueurPasModifiee));
private static void ProprieteLongueurPasModifiee(DependencyObject d,
DependencyPropertyChangedEventArgs e) {
PlanDeTravail le_plan = (PlanDeTravail)d;
le_plan.InvalidateModel();
}
public double LongueurPas {
get {
return (double)GetValue(ProprieteLongueurPas);
}
set {
SetValue(ProprieteLongueurPas, value);
}
}

En ce qui concerne la couleur de la grille, on doit pouvoir modifier la propriété


Brush du DiffuseMaterial, objet qui est affecté à la propriété Material des faces
générées. Donc on inscrit une propriété de dépendance CouleurGrille, de type
Material, initialisée par un DiffuseMaterial dont la propriété Brush est fixée à
Brushes.Black.

//la propriete CouleurGrille (couleur de la grille)


public static readonly DependencyProperty ProprieteCouleurGrille =
DependencyProperty.Register(«CouleurGrille»,
146 Guide pratique de la modélisation 3D avec WPF 4
typeof(Material),
typeof(PlanDeTravail),
new PropertyMetadata(new DiffuseMaterial(Brushes.Black),
ProprieteCouleurGrilleModifiee));
private static void ProprieteCouleurGrilleModifiee(DependencyObject d,
DependencyPropertyChangedEventArgs e) {
PlanDeTravail le_plan = (PlanDeTravail)d;
le_plan.InvalidateModel();
}
public Material CouleurGrille {
get { return (Material)GetValue(ProprieteCouleurGrille); }
set { SetValue(ProprieteCouleurGrille, value); }
}

La composition du plan quadrillé est un ensemble de faces planes dont la texture


appliquée recto verso est identique. Dans la méthode redéfinie OnUpdateModel,
pour le rendu de la grille, on génère les faces en fonction de LongueurX, LongueurZ
et LongueurPas. Et on applique aux propriétés Material et BackMaterial des faces,
la texture CouleurGrille.

//redefinition de methode
protected override void OnUpdateModel() {
Model3DGroup plan = new Model3DGroup();
double dist_x = this.LongueurX / 2;
double dist_z = this.LongueurZ / 2;
for (double xx = -dist_x; xx <= dist_x; xx += this.LongueurPas) {
if (xx != 0) {
GeometryModel3D face = new GeometryModel3D();
MeshGeometry3D maillage = new MeshGeometry3D();
maillage.Positions.Add(new Point3D(xx + 0.005, 0, +dist_z));
maillage.Positions.Add(new Point3D(xx + 0.005, 0, -dist_z));
maillage.Positions.Add(new Point3D(xx - 0.005, 0, -dist_z));
maillage.Positions.Add(new Point3D(xx - 0.005, 0, +dist_z));
maillage.TriangleIndices.Add(0);
maillage.TriangleIndices.Add(1);
Copyright 2011 Patrice REY

maillage.TriangleIndices.Add(2);
maillage.TriangleIndices.Add(2);
maillage.TriangleIndices.Add(3);
maillage.TriangleIndices.Add(0);
face.Geometry = maillage;
face.Material = this.CouleurGrille;
face.BackMaterial = this.CouleurGrille;
plan.Children.Add(face);
CHAPITRE 8 □ Les géométries 3D personnalisées 147
}
}
for (double zz = -dist_z; zz <= dist_z; zz += this.LongueurPas) {
if (zz != 0) {
GeometryModel3D face = new GeometryModel3D();
MeshGeometry3D maillage = new MeshGeometry3D();
maillage.Positions.Add(new Point3D(+dist_x, 0, zz + 0.005));
maillage.Positions.Add(new Point3D(-dist_x, 0, zz + 0.005));
maillage.Positions.Add(new Point3D(-dist_x, 0, zz - 0.005));
maillage.Positions.Add(new Point3D(+dist_x, 0, zz - 0.005));
maillage.TriangleIndices.Add(0);
maillage.TriangleIndices.Add(1);
maillage.TriangleIndices.Add(2);
maillage.TriangleIndices.Add(2);
maillage.TriangleIndices.Add(3);
maillage.TriangleIndices.Add(0);
face.Geometry = maillage;
face.Material = this.CouleurGrille;
face.BackMaterial = this.CouleurGrille;
plan.Children.Add(face);
}
}
Modele = plan;
}

Dans le fichier Index08.xaml, on ajoute un objet x_plan_de_travail, de type


objet:PlanDeTravail (grâce à l’espace de noms préfixé par objet) dans le conteneur
de type ContainerUIElement3D (indicateur n°1 sur la figure 8-14). Par défaut, on
est en présence d’un plan de travail de longueur de 2 unités suivant X et Z, avec
un pas de grille de 1 et une couleur de grille noire (Brushes.Black). De plus on voit
que le concepteur de vues de Visual Studio génère la grille, et dans la fenêtre des
propriétés, nos nouvelles propriétés de dépendance sont affichées (CouleurGrille,
LongueurPas, LongueurX et LongueurZ).
Si dans la fenêtre des propriétés, on change la valeur de LongueurX à 4 unités
(indicateur n°2 de la figure 8-14), notre grille est modifiée en conséquence.
Si on modifie LongueurZ en le passant à 4 (indicateur n°3 de la figure 8-14), on
obtient une grille de 4 par 4 unités avec des espacements de 1 unité. Si on modifie
LongueurPas en le passant à 0.5 (indicateur n°4 de la figure 8-15), on obtient une
grille de 4 par 4 unités avec des espacements de 0.5 unité.
Si on veut modifier la couleur de la grille, la fenêtre des propriétés indique que la
valeur doit être définie en XAML (indicateur n°5 de la figure 8-15).
148 Guide pratique de la modélisation 3D avec WPF 4
Figure 8-14

Copyright 2011 Patrice REY

3
CHAPITRE 8 □ Les géométries 3D personnalisées 149
Figure 8-15

6
150 Guide pratique de la modélisation 3D avec WPF 4
En effet, le changement de couleur se fait par l’intermédiaire d’un objet complexe
DiffuseMaterial. D’où, en XAML (indicateur n°6 de la figure 8-15), on ouvre le
nœud, en notation pointée, de la propriété CouleurGrille par <objet:PlanDeTravail.
CouleurGrille> et on instancie un objet DiffuseMaterial dont la propriété Brush
sera fixée à DarkGray par exemple. On se trouve alors avec une grille dont les faces
vues sont de couleur grise.

<ContainerUIElement3D x:Name='x_scene'>
...
<!-- plan de travail -->
<objet:PlanDeTravail x:Name='x_plan_de_travail'
LongueurX='4' LongueurZ='4' LongueurPas='0.5'>
<objet:PlanDeTravail.CouleurGrille>
<DiffuseMaterial Brush='DarkGray'></DiffuseMaterial>
</objet:PlanDeTravail.CouleurGrille>
</objet:PlanDeTravail>
</ContainerUIElement3D>

La figure 8-17 montre le résultat obtenu. En utilisant la souris pour modifier l’angle
de vue de la scène, on constate bien que le plan de travail est une grille de couleur
grise recto verso, et dont le centre est l’origine du repère (figure 8-16).

Figure 8-16

Copyright 2011 Patrice REY

grille vue du dessus grille vue du dessous


CHAPITRE 8 □ Les géométries 3D personnalisées 151
Figure 8-17

4 - La géométrie personnalisée du cube

Dans le projet Geo3d, on ajoute une classe Cube (fichier Cube.cs) qui hérite de la
classe UIElement3D. On ajoute une propriété de dépendance Modele qui stocke
le modèle 3D. Le but est de générer un cube générique dont le côté suivant l’axe X
a pour longueur DistanceX, dont le côté suivant l’axe Y a pour longueur DistanceY,
et dont le côté suivant l’axe Z a pour longueur DistanceZ. Tous les points du cube
sont positionnés par rapport à un centre de référence PositionCentre.
La démarche consiste à inscrire en premier les propriétés de dépendance DistanceX,
DistanceY, DistanceZ (toutes les trois initialisées à la valeur 1, de type double) et
PositionCentre (initialisée à la valeur (0,0,0) de type Point3D).
152 Guide pratique de la modélisation 3D avec WPF 4
//la propriete PositionCentre pour le cube
private static readonly DependencyProperty PrPositionCentre =
DependencyProperty.Register(«PositionCentre»,
typeof(Point3D),
typeof(Cube),
new PropertyMetadata(new Point3D(0, 0, 0),
PrModPositionCentre));
private static void PrModPositionCentre(DependencyObject d,
DependencyPropertyChangedEventArgs e) {
Cube le_cube = (Cube)d;
le_cube.InvalidateModel();
}
public Point3D PositionCentre {
get {
return (Point3D)GetValue(PrPositionCentre);
}
set {
SetValue(PrPositionCentre, value);
}
}
//la propriete DistanceX pour le cube
private static readonly DependencyProperty PrDistanceX =
DependencyProperty.Register(«DistanceX»,
typeof(double),
typeof(Cube),
new PropertyMetadata(1.0, PrModDistanceX));
private static void PrModDistanceX(DependencyObject d,
DependencyPropertyChangedEventArgs e) {
Cube le_cube = (Cube)d;
le_cube.InvalidateModel();
}
public double DistanceX {
get {
return (double)GetValue(PrDistanceX);
}
set {
Copyright 2011 Patrice REY

SetValue(PrDistanceX, value);
}
}
//la propriete DistanceY pour le cube
private static readonly DependencyProperty PrDistanceY =
DependencyProperty.Register(«DistanceY»,
typeof(double),
typeof(Cube),
CHAPITRE 8 □ Les géométries 3D personnalisées 153
new PropertyMetadata(1.0, PrModDistanceY));
private static void PrModDistanceY(DependencyObject d,
DependencyPropertyChangedEventArgs e) {
Cube le_cube = (Cube)d;
le_cube.InvalidateModel();
}
public double DistanceY {
get {
return (double)GetValue(PrDistanceY);
}
set {
SetValue(PrDistanceY, value);
}
}
//la propriete DistanceZ pour le cube
private static readonly DependencyProperty PrDistanceZ =
DependencyProperty.Register(«DistanceZ»,
typeof(double),
typeof(Cube),
new PropertyMetadata(1.0, PrModDistanceZ));
private static void PrModDistanceZ(DependencyObject d,
DependencyPropertyChangedEventArgs e) {
Cube le_cube = (Cube)d;
le_cube.InvalidateModel();
}
public double DistanceZ {
get {
return (double)GetValue(PrDistanceZ);
}
set {
SetValue(PrDistanceZ, value);
}
}

Nous devons pouvoir modifier la texture identique appliquée sur chaque face. On
inscrit donc une propriété de dépendance TextureFace de type Material.

//la propriete TextureFace (texture de la face a appliquer)


public static readonly DependencyProperty PrTextureFace =
DependencyProperty.Register(«TextureFace»,
typeof(Material),
typeof(Cube),
new PropertyMetadata(new DiffuseMaterial(Brushes.DarkGray),
154 Guide pratique de la modélisation 3D avec WPF 4
PrModTextureFace));
private static void PrModTextureFace(DependencyObject d,
DependencyPropertyChangedEventArgs e) {
Cube le_cube = (Cube)d;
le_cube.InvalidateModel();
}
public Material TextureFace {
get { return (Material)GetValue(PrTextureFace); }
set { SetValue(PrTextureFace, value); }
}

Dans la méthode redéfinie OnUpdateModel(), on génère un cube générique en


fonction de ses propriétés de dépendance initialisées. On procède de manière
identique à celle employée au chapitre 3.

//redefinition de methode
protected override void OnUpdateModel() {
Model3DGroup cube = new Model3DGroup();
Point3D pt0 = new Point3D(-DistanceX / 2, -DistanceY / 2,
DistanceZ / 2);//0 0 0
pt0 += (Vector3D)PositionCentre;
Point3D pt1 = new Point3D(-DistanceX / 2, DistanceY / 2,
DistanceZ / 2);//0 y 0
pt1 += (Vector3D)PositionCentre;
Point3D pt2 = new Point3D(DistanceX / 2, DistanceY / 2,
DistanceZ / 2);//x y 0
pt2 += (Vector3D)PositionCentre;
Point3D pt3 = new Point3D(DistanceX / 2, -DistanceY / 2,
DistanceZ / 2);//x 0 0
pt3 += (Vector3D)PositionCentre;
Point3D pt4 = new Point3D(DistanceX / 2, -DistanceY / 2,
-DistanceZ / 2);//x 0 -z
pt4 += (Vector3D)PositionCentre;
Point3D pt5 = new Point3D(DistanceX / 2, DistanceY / 2,
-DistanceZ / 2);//x y -z
Copyright 2011 Patrice REY

pt5 += (Vector3D)PositionCentre;
Point3D pt6 = new Point3D(-DistanceX / 2, DistanceY / 2,
-DistanceZ / 2);//0 y -z
pt6 += (Vector3D)PositionCentre;
Point3D pt7 = new Point3D(-DistanceX / 2, -DistanceY / 2,
-DistanceZ / 2);//0 0 -z
pt7 += (Vector3D)PositionCentre;
//face avant 3210
CHAPITRE 8 □ Les géométries 3D personnalisées 155
GeometryModel3D face_avant = ModeliserFaceRectangle(pt3, pt2, pt1,
pt0);
cube.Children.Add(face_avant);
//face droite 4523
GeometryModel3D face_droite = ModeliserFaceRectangle(pt4, pt5, pt2,
pt3);
cube.Children.Add(face_droite);
//face arriere 7654
GeometryModel3D face_arriere = ModeliserFaceRectangle(pt7, pt6,
pt5, pt4);
cube.Children.Add(face_arriere);
//face gauche 0167
GeometryModel3D face_gauche = ModeliserFaceRectangle(pt0, pt1, pt6,
pt7);
cube.Children.Add(face_gauche);
//face dessus 2561
GeometryModel3D face_dessus = ModeliserFaceRectangle(pt2, pt5, pt6,
pt1);
cube.Children.Add(face_dessus);
//face dessous 4307
GeometryModel3D face_dessous = ModeliserFaceRectangle(pt4, pt3,
pt0, pt7);
cube.Children.Add(face_dessous);
Modele = cube;
}

L’indicateur n°1 de la figure 8-18 visualise le cube dans son contexte par défaut.
L’indicateur n°2 de la figure 8-18 visualise le cube avec application d’un pinceau
dont la propriété Brush est un dégradé de couleurs (RadialGradientBrush en
l’occurrence).
L’indicateur n°3 de la figure 8-18 visualise le cube avec application d’un pinceau
dont la propriété Brush est une image (texture_face.png dans le sous-dossier
image du dossier chapitre08).
L’indicateur n°4 de la figure 8-19 visualise le cube avec une modification de la
propriété de dépendance PositionCentre qui amène le cube au niveau du plan de
travail.
L’indicateur n°5 de la figure 8-19 visualise le cube avec application d’une
transformation comme une translation, de type TranslateTransform3D, dont le
déplacement suivant X (OffsetX) a pour valeur -2 unités.
156 Guide pratique de la modélisation 3D avec WPF 4
Figure 8-18

Copyright 2011 Patrice REY

3
CHAPITRE 8 □ Les géométries 3D personnalisées 157

Figure 8-19

La figure 8-20 montre le résultat final avec le cube texturé et positionné sur le plan
de travail. En faisant tourner la scène, on peut visualiser les textures des différentes
faces du cube.
158 Guide pratique de la modélisation 3D avec WPF 4
Figure 8-20

Copyright 2011 Patrice REY


CHAPITRE 8 □ Les géométries 3D personnalisées 159

5 - La géométrie personnalisée de l’ellipsoïde

La modélisation de l’ellipsoide est le cas général avec 3 rayons différents selon les 3
axes. Le cas de la sphère est particulier puisque ces trois rayons sont égaux.
Dans le projet Geo3d, on ajoute une classe Ellipsoide (fichier Ellipsoide.cs) qui
hérite de la classe UIElement3D. On ajoute une propriété de dépendance Modele
qui stocke le modèle 3D. Le but est de générer une ellipsoïde générique dont le
rayon suivant l’axe X a pour longueur RayonX, dont le rayon suivant l’axe Y a pour
longueur RayonY, et dont le rayon suivant l’axe Z a pour longueur RayonZ. Tous
les points de l’ellipsoïde sont positionnés par rapport à un centre de référence
PositionCentre. Le nombre de division suivant l’horizontale est DivPhi, et suivant la
verticale est DivBeta.
La démarche consiste à inscrire en premier les propriétés de dépendance RayonX,
RayonY, RayonZ (toutes les trois initialisées à la valeur 1, de type double), DivPhi
et DivBeta (les nombres de division initialisés à 20, de type int) et PositionCentre
(propriété initialisée à la valeur (0,0,0) de type Point3D).
Nous devons pouvoir modifier la texture identique appliquée sur chaque facette.
On inscrit donc une propriété de dépendance TextureFace, de type Material,
initialisée à Brushes.DarkGray.
L’implémentation de la propriété RayonX est la suivante (RayonY et RayonZ seront
sur le même principe):

//la propriete RayonX pour l’ellipsoide


private static readonly DependencyProperty PrRayonX =
DependencyProperty.Register(«RayonX»,
typeof(double),
typeof(Ellipsoide),
new PropertyMetadata(1.0, PrModRayonX));
private static void PrModRayonX(DependencyObject d,
DependencyPropertyChangedEventArgs e) {
Ellipsoide ellipsoide = (Ellipsoide)d;
ellipsoide.InvalidateModel();
}
public double RayonX {
get {
return (double)GetValue(PrRayonX);
}
set {
SetValue(PrRayonX, value);}}
160 Guide pratique de la modélisation 3D avec WPF 4
L’implémentation des propriétés DivPhi et DivBeta sont les suivantes:

//la propriete DivPhi pour l’ellipsoide (nombre de division


horizontalement)
private static readonly DependencyProperty PrDivPhi =
DependencyProperty.Register(«DivPhi»,
typeof(int),
typeof(Ellipsoide),
new PropertyMetadata(20, PrModDivPhi));
private static void PrModDivPhi(DependencyObject d,
DependencyPropertyChangedEventArgs e) {
Ellipsoide ellipsoide = (Ellipsoide)d;
ellipsoide.InvalidateModel();
}
public int DivPhi {
get {
return (int)GetValue(PrDivPhi);
}
set {
SetValue(PrDivPhi, value);
}
}
//la propriete DivBeta pour l’ellipsoide (nombre de division
verticalement)
private static readonly DependencyProperty PrDivBeta =
DependencyProperty.Register(«DivBeta»,
typeof(int),
typeof(Ellipsoide),
new PropertyMetadata(20, PrModDivBeta));
private static void PrModDivBeta(DependencyObject d,
DependencyPropertyChangedEventArgs e) {
Ellipsoide ellipsoide = (Ellipsoide)d;
ellipsoide.InvalidateModel();
}
public int DivBeta {
get {
Copyright 2011 Patrice REY

return (int)GetValue(PrDivBeta);
}
set {
SetValue(PrDivBeta, value);
}
}

La redéfinition de la méthode OnUpdateModel permet de modéliser l’ellipsoïde.


CHAPITRE 8 □ Les géométries 3D personnalisées 161
On utilise la même manière que celle employée au chapitre 4, en tenant compte
ici des propriétés RayonX, RayonY, RayonZ, DivPhi et DivBeta.

//redefinition de methode
protected override void OnUpdateModel() {
Model3DGroup ellipsoide = new Model3DGroup();
double angle_phi = 360 / (this.DivPhi - 1);
double angle_beta = 360 / (this.DivBeta - 1);
for (double i = 0; i < 360; i += angle_phi) {
for (double j = -90; j < 90; j += angle_beta) {
Point3D pt_0 = ObtenirPositionEllipsoide(this.RayonX,
this.RayonY, this.RayonZ, i, j);
pt_0 += (Vector3D)this.PositionCentre;
Point3D pt_1 = ObtenirPositionEllipsoide(this.RayonX,
this.RayonY, this.RayonZ, i, j + angle_beta);
pt_1 += (Vector3D)this.PositionCentre;
Point3D pt_2 = ObtenirPositionEllipsoide(this.RayonX,
this.RayonY, this.RayonZ, i + angle_phi, j + angle_beta);
pt_2 += (Vector3D)this.PositionCentre;
Point3D pt_3 = ObtenirPositionEllipsoide(this.RayonX,
this.RayonY, this.RayonZ, i + angle_phi, j);
pt_3 += (Vector3D)this.PositionCentre;
GenererFacette(pt_3, pt_2, pt_1, pt_0, ellipsoide);
}
}
Modele = ellipsoide;
}

//position point sur ellipsoide


private Point3D ObtenirPositionEllipsoide(double rayon_x, double
rayon_y, double rayon_z, double phi, double beta) {
Point3D pt = new Point3D();
pt.X = +rayon_x * Math.Cos(beta * Math.PI / 180) *
Math.Cos(phi * Math.PI / 180);
pt.Y = +rayon_y * Math.Sin(beta * Math.PI / 180);
pt.Z = -rayon_z * Math.Cos(beta * Math.PI / 180) *
Math.Sin(phi * Math.PI / 180);
return pt;
}

//generer la facette rectangulaire


private void GenererFacette(Point3D pt_0, Point3D pt_1, Point3D pt_2,
Point3D pt_3, Model3DGroup modele_sphere) {
162 Guide pratique de la modélisation 3D avec WPF 4
GeometryModel3D facette = new GeometryModel3D();
MeshGeometry3D geometrie = new MeshGeometry3D();
geometrie.Positions.Add(pt_0);
geometrie.Positions.Add(pt_1);
geometrie.Positions.Add(pt_2);
geometrie.Positions.Add(pt_3);
geometrie.TriangleIndices.Add(0);
geometrie.TriangleIndices.Add(1);
geometrie.TriangleIndices.Add(2);
geometrie.TriangleIndices.Add(2);
geometrie.TriangleIndices.Add(3);
geometrie.TriangleIndices.Add(0);
geometrie.TextureCoordinates.Add(new Point(1, 1));
geometrie.TextureCoordinates.Add(new Point(1, 0));
geometrie.TextureCoordinates.Add(new Point(0, 0));
geometrie.TextureCoordinates.Add(new Point(0, 1));
facette.Geometry = geometrie;
facette.Material = this.TextureFace;
facette.BackMaterial = new DiffuseMaterial(Brushes.Yellow);
modele_sphere.Children.Add(facette);
}

Dans le fichier Index08.xaml (figure 8-21), on instancie une sphère nommée x_


sphere (indicateur n°1 de la figure 8-21) et on instancie une ellipsoïde nommée
x_ellipsoide (indicateur n°2 de la figure 8-21). Ces deux objets, de type Geo3d.
Ellipsoide, sont positionnés sur la scène à côté du cube.

<!-- sphere ellipse -->


<objet:Ellipsoide x:Name='x_sphere' PositionCentre='0,0.75,-1'
DivBeta='40' DivPhi='40' RayonX='0.75' RayonY='0.75'
RayonZ='0.75'>
<objet:Ellipsoide.TextureFace>
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<ImageBrush ImageSource='/GuideModelisation3D;
Copyright 2011 Patrice REY

component/chapitre08/image/texture_face_sphere.png' />
</DiffuseMaterial.Brush>
</DiffuseMaterial>
</objet:Ellipsoide.TextureFace>
</objet:Ellipsoide>
<objet:Ellipsoide x:Name='x_ellipsoide' DivBeta='40' DivPhi='40'
RayonX='1' RayonY='0.5' RayonZ='0.75'
PositionCentre='-2,0.5,-2'>
CHAPITRE 8 □ Les géométries 3D personnalisées 163
Figure 8-21

2
164 Guide pratique de la modélisation 3D avec WPF 4
Figure 8-22

Copyright 2011 Patrice REY


CHAPITRE 8 □ Les géométries 3D personnalisées 165
<objet:Ellipsoide.TextureFace>
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<ImageBrush ImageSource='/GuideModelisation3D;
component/chapitre08/image/texture_face_sphere.png' />
</DiffuseMaterial.Brush>
</DiffuseMaterial>
</objet:Ellipsoide.TextureFace>
</objet:Ellipsoide>

La figure 8-22 montre le résultat final avec la sphère texturée et l’ellipsoïde


texturée, positionnées sur le plan de travail. En faisant tourner la scène, on peut
visualiser les objets sous différentes vues.

6 - La géométrie personnalisée du cylindre

Dans le projet Geo3d, on ajoute une classe Cylindre (fichier Cylindre.cs) qui hérite
de la classe UIElement3D. On ajoute une propriété de dépendance Modele qui
stocke le modèle 3D. Le but est de générer un cylindre générique dont le rayon
du cercle externe est RayonExt et dont le rayon du cercle interne est RayonInt. Il
possède une hauteur de cylindre suivant l’axe Y, nommée Hauteur. Tous les points
du cylindre sont positionnés par rapport à un centre de référence PositionCentre.
Le nombre de division suivant l’horizontale est DivPhi.
La démarche consiste à inscrire en premier les propriétés de dépendance RayonExt,
RayonInt (propriétés initialisées à la valeur 1 et 0 respectivement, de type double),
la propriété Hauteur initialisée à 1 (de type double), la propriété DivPhi initialisée
à 20 (de type int) et PositionCentre initialisée à la valeur (0,0,0), de type Point3D.
Nous devons pouvoir modifier la texture identique appliquée sur chaque facette.
On inscrit donc une propriété de dépendance TextureFace, de type Material,
initialisée à Brushes.DarkGray.
L’implémentation des propriétés RayonExt, RayonInt et Hauteur sont les suivantes:

//la propriete RayonExt pour le cylindre


private static readonly DependencyProperty PrRayonExt =
DependencyProperty.Register(«RayonExt»,
typeof(double),
typeof(Cylindre),
new PropertyMetadata(1.0, PrModRayonExt));
private static void PrModRayonExt(DependencyObject d,
166 Guide pratique de la modélisation 3D avec WPF 4
DependencyPropertyChangedEventArgs e) {
Cylindre cylindre = (Cylindre)d;
cylindre.InvalidateModel();
}
public double RayonExt {
get {
return (double)GetValue(PrRayonExt);
}
set {
SetValue(PrRayonExt, value);
}
}

//la propriete RayonInt pour le cylindre


private static readonly DependencyProperty PrRayonInt =
DependencyProperty.Register(«RayonInt»,
typeof(double),
typeof(Cylindre),
new PropertyMetadata(0.0, PrModRayonInt));
private static void PrModRayonInt(DependencyObject d,
DependencyPropertyChangedEventArgs e) {
Cylindre cylindre = (Cylindre)d;
cylindre.InvalidateModel();
}
public double RayonInt {
get {
return (double)GetValue(PrRayonInt);
}
set {
SetValue(PrRayonInt, value);
}
}

//la propriete Hauteur pour le cylindre


private static readonly DependencyProperty PrHauteur =
DependencyProperty.Register(«Hauteur»,
Copyright 2011 Patrice REY

typeof(double),
typeof(Cylindre),
new PropertyMetadata(1.0, PrModHauteur));
private static void PrModHauteur(DependencyObject d,
DependencyPropertyChangedEventArgs e) {
Cylindre cylindre = (Cylindre)d;
cylindre.InvalidateModel();
}
CHAPITRE 8 □ Les géométries 3D personnalisées 167
public double Hauteur {
get {
return (double)GetValue(PrHauteur);
}
set {
SetValue(PrHauteur, value);
}
}

La redéfinition de la méthode OnUpdateModel permet de modéliser le cylindre


générique. La manière employée est la même que celle du chapitre 5, en utilisant
ici les propriétés DivPhi, RayonExt, RayonInt et Hauteur:

//redefinition de methode
protected override void OnUpdateModel() {
Model3DGroup cylindre = new Model3DGroup();
double angle_phi = 360 / (this.DivPhi - 1);
for (double i = 0; i < 360; i += angle_phi) {
//face abcd
Point3D pt_a = ObtenirPositionBasseExterne(this.RayonExt,
i + angle_phi);
pt_a += (Vector3D)this.PositionCentre;
Point3D pt_b = ObtenirPositionHauteExterne(this.RayonExt,
i + angle_phi, this.Hauteur);
pt_b += (Vector3D)this.PositionCentre;
Point3D pt_c = ObtenirPositionHauteExterne(this.RayonExt,
i, this.Hauteur);
pt_c += (Vector3D)this.PositionCentre;
Point3D pt_d = ObtenirPositionBasseExterne(this.RayonExt, i);
pt_d += (Vector3D)this.PositionCentre;
GenererFacette(pt_a, pt_b, pt_c, pt_d, cylindre);
//bfgc
Point3D pt_f = ObtenirPositionHauteInterne(this.RayonInt,
i + angle_phi, this.Hauteur);
pt_f += (Vector3D)this.PositionCentre;
Point3D pt_g = ObtenirPositionHauteInterne(this.RayonInt,
i, this.Hauteur);
pt_g += (Vector3D)this.PositionCentre;
GenererFacette(pt_b, pt_f, pt_g, pt_c, cylindre);
//hgfe
Point3D pt_h = ObtenirPositionBasseInterne(this.RayonInt, i);
pt_h += (Vector3D)this.PositionCentre;
Point3D pt_e = ObtenirPositionBasseInterne(this.RayonInt,
168 Guide pratique de la modélisation 3D avec WPF 4
i + angle_phi);
pt_e += (Vector3D)this.PositionCentre;
GenererFacette(pt_h, pt_g, pt_f, pt_e, cylindre);
//eadh
GenererFacette(pt_e, pt_a, pt_d, pt_h, cylindre);
}
Modele = cylindre;
}

private Point3D ObtenirPositionHauteExterne(double ray_ext, double


phi, double hauteur) {
Point3D pt = new Point3D();
pt.X = +ray_ext * Math.Cos(phi * Math.PI / 180);
pt.Y = hauteur;
pt.Z = -ray_ext * Math.Sin(phi * Math.PI / 180);
return pt;
}
private Point3D ObtenirPositionHauteInterne(double ray_int, double
phi, double hauteur) {
Point3D pt = new Point3D();
pt.X = +ray_int * Math.Cos(phi * Math.PI / 180);
pt.Y = hauteur;
pt.Z = -ray_int * Math.Sin(phi * Math.PI / 180);
return pt;
}
private Point3D ObtenirPositionBasseExterne(double ray_ext, double
phi) {
Point3D pt = new Point3D();
pt.X = +ray_ext * Math.Cos(phi * Math.PI / 180);
pt.Y = 0;
pt.Z = -ray_ext * Math.Sin(phi * Math.PI / 180);
return pt;
}
private Point3D ObtenirPositionBasseInterne(double ray_int, double
phi) {
Point3D pt = new Point3D();
Copyright 2011 Patrice REY

pt.X = +ray_int * Math.Cos(phi * Math.PI / 180);


pt.Y = 0;
pt.Z = -ray_int * Math.Sin(phi * Math.PI / 180);
return pt;
}

Dans le fichier Index08.xaml (figure 8-23), on instancie un cylindre nommé x_


cylindre_plein qui modélise un cylindre plein (indicateur n°1 de la figure 8-23) et
CHAPITRE 8 □ Les géométries 3D personnalisées 169
on instancie un cylindre nommé x_cylindre_creux qui modélise un cylindre creux
(indicateur n°2 de la figure 8-23). Ces deux objets, de type Geo3d.Cylindre, sont
positionnés sur la scène à côté des autres objets déjà présents.

<!-- cylindre plein -->


<objet:Cylindre x:Name='x_cylindre_plein' RayonExt='0.5'>
<objet:Cylindre.TextureFace>
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<ImageBrush ImageSource='/GuideModelisation3D;
component/chapitre08/image/texture_face_sphere.png' />
</DiffuseMaterial.Brush>
</DiffuseMaterial>
</objet:Cylindre.TextureFace>
<objet:Cylindre.Transform>
<TranslateTransform3D OffsetX='2' OffsetZ='-1'>
</TranslateTransform3D>
</objet:Cylindre.Transform>
</objet:Cylindre>
<!-- cylindre creux -->
<objet:Cylindre x:Name='x_cylindre_creux' RayonExt='1'
Hauteur='0.25' RayonInt='0.75' DivPhi='40'>
<objet:Cylindre.TextureFace>
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<ImageBrush ImageSource='/GuideModelisation3D;
component/chapitre08/image/texture_face_sphere.png' />
</DiffuseMaterial.Brush>
</DiffuseMaterial>
</objet:Cylindre.TextureFace>
<objet:Cylindre.Transform>
<TranslateTransform3D OffsetX='2' OffsetZ='-1'>
</TranslateTransform3D>
</objet:Cylindre.Transform>
</objet:Cylindre>

Le concepteur de vues de Visual Studio 2010 permet la mise à jour des modèles
quand on modifie les propriétés de dépendance dans la fenêtre des propriétés.
Si des erreurs sont commises dans l’implémentation des modèles, le concepteur
n’affiche rien. Il faut alors retourner dans la classe de l’objet concerné pour
procéder à la correction des erreurs.
170 Guide pratique de la modélisation 3D avec WPF 4
Figure 8-23

La figure 8-24 montre le résultat final avec les cylindres texturés et positionnés sur
le plan de travail à côté du cube, de la sphère et de l’ellipsoïde.
Copyright 2011 Patrice REY

Le déplacement des objets sur la scène, en vue de leur positionnement, se


réalise facilement en ajoutant une transformation comme une translation (objet
TranslateTransform3D).
En faisant tourner la scène, on peut visualiser les objets sous différentes vues.
CHAPITRE 8 □ Les géométries 3D personnalisées 171
Figure 8-24
172 Guide pratique de la modélisation 3D avec WPF 4

7 - La géométrie personnalisée du cône

Dans le projet Geo3d, on ajoute une classe Cone (fichier Cone.cs) qui hérite de la
classe UIElement3D. On ajoute une propriété de dépendance Modele qui stocke
le modèle 3D. Le but est de générer un cône générique dont le rayon du cercle du
bas est RayonBas et dont le rayon du cercle du haut est RayonHaut. Il possède une
hauteur suivant l’axe Y, nommée Hauteur. Tous les points du cône sont positionnés
par rapport à un centre de référence PositionCentre. Le nombre de division suivant
l’horizontale est DivPhi.
La démarche consiste à inscrire en premier les propriétés de dépendance RayonBas
et RayonHaut (propriétés initialisées à la valeur 1 et 0 respectivement, de type
double), la propriété Hauteur initialisée à 1 (de type double), la propriété DivPhi
initialisée à 20 (de type int) et PositionCentre initialisée à la valeur (0,0,0), de type
Point3D.
Nous devons pouvoir modifier la texture identique appliquée sur chaque facette.
On inscrit donc une propriété de dépendance TextureFace, de type Material,
initialisée à Brushes.DarkGray.

L’implémentation des propriétés RayonBas et RayonHaut sont les suivantes:

//la propriete RayonBas pour le cone


private static readonly DependencyProperty PrRayonBas =
DependencyProperty.Register(«RayonBas»,
typeof(double),
typeof(Cone),
new PropertyMetadata(1.0, PrModRayonBas));
private static void PrModRayonBas(DependencyObject d,
DependencyPropertyChangedEventArgs e) {
Cone cone = (Cone)d;
cone.InvalidateModel();
}
Copyright 2011 Patrice REY

public double RayonBas {


get {
return (double)GetValue(PrRayonBas);
}
set {
SetValue(PrRayonBas, value);
}
}
CHAPITRE 8 □ Les géométries 3D personnalisées 173
//la propriete RayonHaut pour le cone
private static readonly DependencyProperty PrRayonHaut =
DependencyProperty.Register(«RayonHaut»,
typeof(double),
typeof(Cone),
new PropertyMetadata(0.0, PrModRayonHaut));
private static void PrModRayonHaut(DependencyObject d,
DependencyPropertyChangedEventArgs e) {
Cone cone = (Cone)d;
cone.InvalidateModel();
}
public double RayonHaut {
get {
return (double)GetValue(PrRayonHaut);
}
set {
SetValue(PrRayonHaut, value);
}
}

La redéfinition de la méthode OnUpdateModel permet de modéliser le cône


générique. La manière employée est la même que celle du chapitre 6, en utilisant
ici les propriétés DivPhi, RayonBas, RayonHaut et Hauteur:

//redefinition de methode
protected override void OnUpdateModel() {
Model3DGroup cone = new Model3DGroup();
double angle_phi = 360 / (this.DivPhi - 1);
for (double i = 0; i < 360; i += angle_phi) {
//face abcd
Point3D pt_a = ObtenirPositionBasse(this.RayonBas,
i + angle_phi);
pt_a += (Vector3D)this.PositionCentre;
Point3D pt_b = ObtenirPositionHaute(this.RayonHaut,
i + angle_phi, this.Hauteur);
pt_b += (Vector3D)this.PositionCentre;
Point3D pt_c = ObtenirPositionHaute(this.RayonHaut,
i, this.Hauteur);
pt_c += (Vector3D)this.PositionCentre;
Point3D pt_d = ObtenirPositionBasse(this.RayonBas, i);
pt_d += (Vector3D)this.PositionCentre;
GenererFacette(pt_a, pt_b, pt_c, pt_d, cone);
//triangle bec
174 Guide pratique de la modélisation 3D avec WPF 4
Point3D pt_e = new Point3D(0, this.Hauteur, 0);
pt_e += (Vector3D)this.PositionCentre;
GenererTriangle(pt_b, pt_e, pt_c, cone);
//triangle doa
GenererTriangle(pt_d, this.PositionCentre, pt_a, cone);
}
Modele = cone;
}

private Point3D ObtenirPositionHaute(double ray_haut, double phi,


double hauteur) {
Point3D pt = new Point3D();
pt.X = +ray_haut * Math.Cos(phi * Math.PI / 180);
pt.Y = hauteur;
pt.Z = -ray_haut * Math.Sin(phi * Math.PI / 180);
return pt;
}
private Point3D ObtenirPositionBasse(double ray_bas, double phi) {
Point3D pt = new Point3D();
pt.X = +ray_bas * Math.Cos(phi * Math.PI / 180);
pt.Y = 0;
pt.Z = -ray_bas * Math.Sin(phi * Math.PI / 180);
return pt;
}

private void GenererFacette(Point3D pt_0, Point3D pt_1, Point3D pt_2,


Point3D pt_3,
Model3DGroup modele_sphere) {
GeometryModel3D facette = new GeometryModel3D();
MeshGeometry3D geometrie = new MeshGeometry3D();
geometrie.Positions.Add(pt_0);
geometrie.Positions.Add(pt_1);
geometrie.Positions.Add(pt_2);
geometrie.Positions.Add(pt_3);
geometrie.TriangleIndices.Add(0);
geometrie.TriangleIndices.Add(1);
Copyright 2011 Patrice REY

geometrie.TriangleIndices.Add(2);
geometrie.TriangleIndices.Add(2);
geometrie.TriangleIndices.Add(3);
geometrie.TriangleIndices.Add(0);
geometrie.TextureCoordinates.Add(new Point(1, 1));
geometrie.TextureCoordinates.Add(new Point(1, 0));
geometrie.TextureCoordinates.Add(new Point(0, 0));
geometrie.TextureCoordinates.Add(new Point(0, 1));
CHAPITRE 8 □ Les géométries 3D personnalisées 175
facette.Geometry = geometrie;
facette.Material = this.TextureFace;
facette.BackMaterial = new DiffuseMaterial(Brushes.Yellow);
modele_sphere.Children.Add(facette);
}

private void GenererTriangle(Point3D pt_0, Point3D pt_1, Point3D


pt_2, Model3DGroup modele_sphere) {
GeometryModel3D facette = new GeometryModel3D();
MeshGeometry3D geometrie = new MeshGeometry3D();
geometrie.Positions.Add(pt_0);
geometrie.Positions.Add(pt_1);
geometrie.Positions.Add(pt_2);
geometrie.TriangleIndices.Add(0);
geometrie.TriangleIndices.Add(1);
geometrie.TriangleIndices.Add(2);
geometrie.TextureCoordinates.Add(new Point(0, 1));
geometrie.TextureCoordinates.Add(new Point(0, 0));
geometrie.TextureCoordinates.Add(new Point(1, 1));
facette.Geometry = geometrie;
facette.Material = this.TextureFace; ;
facette.BackMaterial = new DiffuseMaterial(Brushes.Yellow);
modele_sphere.Children.Add(facette);
}

private void GenererFacette(Point3D pt_0, Point3D pt_1, Point3D pt_2,


Point3D pt_3,
Model3DGroup modele_sphere) {
GeometryModel3D facette = new GeometryModel3D();
MeshGeometry3D geometrie = new MeshGeometry3D();
geometrie.Positions.Add(pt_0);
geometrie.Positions.Add(pt_1);
geometrie.Positions.Add(pt_2);
geometrie.Positions.Add(pt_3);
geometrie.TriangleIndices.Add(0);
geometrie.TriangleIndices.Add(1);
geometrie.TriangleIndices.Add(2);
geometrie.TriangleIndices.Add(2);
geometrie.TriangleIndices.Add(3);
geometrie.TriangleIndices.Add(0);
geometrie.TextureCoordinates.Add(new Point(1, 1));
geometrie.TextureCoordinates.Add(new Point(1, 0));
geometrie.TextureCoordinates.Add(new Point(0, 0));
geometrie.TextureCoordinates.Add(new Point(0, 1));
176 Guide pratique de la modélisation 3D avec WPF 4
facette.Geometry = geometrie;
facette.Material = this.TextureFace;
facette.BackMaterial = new DiffuseMaterial(Brushes.Yellow);
modele_sphere.Children.Add(facette);
}
Figure 8-25

2 Copyright 2011 Patrice REY

Dans le fichier Index08.xaml (figure 8-25), on instancie un cône nommé x_cone_


plein qui modélise un cône plein (indicateur n°1 de la figure 8-25) et on instancie un
cône nommé x_cone_tronque qui modélise un cône tronqué sur le haut (indicateur
n°2 de la figure 8-25). Ces deux objets, de type Geo3d.Cone, sont positionnés sur la
scène à côté des autres objets déjà présents.
CHAPITRE 8 □ Les géométries 3D personnalisées 177
<!-- cone plein -->
<objet:Cone x:Name='x_cone_plein' RayonBas='0.5'
Hauteur='1.5'>
<objet:Cone.TextureFace>
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<ImageBrush ImageSource='/GuideModelisation3D;
component/chapitre08/image/texture_face_sphere.png' />
</DiffuseMaterial.Brush>
</DiffuseMaterial>
</objet:Cone.TextureFace>
<objet:Cone.Transform>
<TranslateTransform3D OffsetZ=’2’ OffsetX=’-2’>
</TranslateTransform3D>
</objet:Cone.Transform>
</objet:Cone>

<!-- cone tronque -->


<objet:Cone x:Name='x_cone_tronque' RayonBas='0.5'
Hauteur='1' RayonHaut='0.25'>
<objet:Cone.TextureFace>
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<ImageBrush ImageSource=’/GuideModelisation3D;
component/chapitre08/image/texture_face_sphere.png’ />
</DiffuseMaterial.Brush>
</DiffuseMaterial>
</objet:Cone.TextureFace>
<objet:Cone.Transform>
<TranslateTransform3D OffsetZ=’2’ OffsetX=’-0.75’>
</TranslateTransform3D>
</objet:Cone.Transform>
</objet:Cone>

La figure 8-26 montre le résultat final avec les cônes texturés et positionnés sur le
plan de travail.
Le déplacement des objets sur la scène, en vue de leur positionnement, se
réalise facilement en ajoutant une transformation comme une translation (objet
TranslateTransform3D).
En faisant tourner la scène, on peut visualiser les objets sous différentes vues.
178 Guide pratique de la modélisation 3D avec WPF 4
Figure 8-26

Copyright 2011 Patrice REY


CHAPITRE 8 □ Les géométries 3D personnalisées 179

8 - La géométrie personnalisée du tore

Dans le projet Geo3d, on ajoute une classe Tore (fichier Tore.cs) qui hérite de la
classe UIElement3D. On ajoute une propriété de dépendance Modele qui stocke
le modèle 3D. Le but est de générer un tore générique dont le rayon du cercle est
Rayon et dont la distance du cercle à la droite est Distance. Tous les points du tore
sont positionnés par rapport à un centre de référence PositionCentre. Le nombre
de division suivant l’horizontale est DivPhi est suivant la verticale est DivBeta.
La démarche consiste à inscrire en premier les propriétés de dépendance Rayon et
Distance (propriétés initialisées à la valeur 1, de type double), les propriétés DivPhi
et DivBeta initialisées à 20 (de type int), et PositionCentre initialisée à la valeur
(0,0,0), de type Point3D.
Nous devons pouvoir modifier la texture identique appliquée sur chaque facette.
On inscrit donc une propriété de dépendance TextureFace, de type Material,
initialisée à Brushes.DarkGray.
L’implémentation des propriétés Rayon et Distance sont les suivantes:

//la propriete Rayon pour le Tore


private static readonly DependencyProperty PrRayon =
DependencyProperty.Register(«Rayon»,
typeof(double),
typeof(Tore),
new PropertyMetadata(1.0, PrModRayon));
private static void PrModRayon(DependencyObject d,
DependencyPropertyChangedEventArgs e) {
Tore tore = (Tore)d;
tore.InvalidateModel();
}
public double Rayon {
get {
return (double)GetValue(PrRayon);
}
set {
SetValue(PrRayon, value);
}
}

//la propriete Distance pour le Tore


private static readonly DependencyProperty PrDistance =
180 Guide pratique de la modélisation 3D avec WPF 4
DependencyProperty.Register(«Distance»,
typeof(double),
typeof(Tore),
new PropertyMetadata(1.0, PrModDistance));
private static void PrModDistance(DependencyObject d,
DependencyPropertyChangedEventArgs e) {
Tore tore = (Tore)d;
tore.InvalidateModel();
}
public double Distance {
get {
return (double)GetValue(PrDistance);
}
set {
SetValue(PrDistance, value);
}
}

L’implémentation des propriétés de dépendance PositionCentre, DivPhi, DivBeta


et TextureFace sont les mêmes qu’au paragraphe précédent. La redéfinition de
la méthode OnUpdateModel permet de modéliser le tore générique. La manière
employée est la même que celle du chapitre 7, en utilisant ici les propriétés DivPhi,
DivBeta, Rayon, Distance, PositionCentre et TextureFace:

//redefinition de methode
protected override void OnUpdateModel() {
Model3DGroup tore = new Model3DGroup();
double angle_phi = 360 / (this.DivPhi - 1);
double angle_beta = 360 / (this.DivBeta - 1);
for (double i = 0; i < 360; i += angle_phi) {
for (double j = 0; j < 360; j += angle_beta) {
//face abcd
Point3D pt_a = ObtenirPosition(this.Distance, this.Rayon,
i + angle_phi, j);
pt_a += (Vector3D)this.PositionCentre;
Copyright 2011 Patrice REY

Point3D pt_b = ObtenirPosition(this.Distance, this.Rayon,


i + angle_phi, j + angle_beta);
pt_b += (Vector3D)this.PositionCentre;
Point3D pt_c = ObtenirPosition(this.Distance, this.Rayon,
i, j + angle_beta);
pt_c += (Vector3D)this.PositionCentre;
Point3D pt_d = ObtenirPosition(this.Distance, this.Rayon,
i, j);
CHAPITRE 8 □ Les géométries 3D personnalisées 181
pt_d += (Vector3D)this.PositionCentre;
GenererFacette(pt_a, pt_b, pt_c, pt_d, tore);
}
}
Modele = tore;
}

//position des points


private Point3D ObtenirPosition(double dist_r, double ray_cercle,
double phi, double beta) {
Point3D pt = new Point3D();
pt.X = (dist_r + ray_cercle * Math.Cos(beta * Math.PI / 180)) *
Math.Cos(phi * Math.PI / 180);
pt.Y = ray_cercle * Math.Sin(beta * Math.PI / 180);
pt.Z = -(dist_r + ray_cercle * Math.Cos(beta * Math.PI / 180)) *
Math.Sin(phi * Math.PI / 180);
return pt;
}

//generer facette
private void GenererFacette(Point3D pt_0, Point3D pt_1, Point3D pt_2,
Point3D pt_3,
Model3DGroup modele_sphere) {
GeometryModel3D facette = new GeometryModel3D();
MeshGeometry3D geometrie = new MeshGeometry3D();
geometrie.Positions.Add(pt_0);
geometrie.Positions.Add(pt_1);
geometrie.Positions.Add(pt_2);
geometrie.Positions.Add(pt_3);
geometrie.TriangleIndices.Add(0);
geometrie.TriangleIndices.Add(1);
geometrie.TriangleIndices.Add(2);
geometrie.TriangleIndices.Add(2);
geometrie.TriangleIndices.Add(3);
geometrie.TriangleIndices.Add(0);
geometrie.TextureCoordinates.Add(new Point(1, 1));
geometrie.TextureCoordinates.Add(new Point(1, 0));
geometrie.TextureCoordinates.Add(new Point(0, 0));
geometrie.TextureCoordinates.Add(new Point(0, 1));
facette.Geometry = geometrie;
facette.Material = this.TextureFace;
facette.BackMaterial = new DiffuseMaterial(Brushes.Yellow);
modele_sphere.Children.Add(facette);
}
182 Guide pratique de la modélisation 3D avec WPF 4
Dans le fichier Index08.xaml (figure 8-27), on instancie un tore nommé x_tore qui
modélise un tore de type ouvert. Ce tore, de type Geo3d.Tore, est positionné sur la
scène à côté des autres objets déjà présents.
Figure 8-27

<!-- tore -->


<objet:Tore x:Name='x_tore' Rayon='0.25'
PositionCentre='0,0,0' Distance='0.5'>
<objet:Tore.TextureFace>
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<ImageBrush ImageSource='/GuideModelisation3D;
component/chapitre08/image/texture_face_sphere.png' />
</DiffuseMaterial.Brush>
</DiffuseMaterial>
</objet:Tore.TextureFace>
<objet:Tore.Transform>
<TranslateTransform3D OffsetX='1.5' OffsetZ='1.5'>
</TranslateTransform3D>
</objet:Tore.Transform>
Copyright 2011 Patrice REY

</objet:Tore>

La figure 8-28 montre le résultat final avec le tore texturé et positionné sur le plan
de travail. En faisant tourner la scène, on peut visualiser les objets sous différentes
vues.
CHAPITRE 8 □ Les géométries 3D personnalisées 183
Figure 8-28
ANNEXE
Annexe 185
Implémenter un TrackBall

En informatique, un TrackBall est une boule insérée dans un clavier, que l’on
manipule avec les doigts et qui fait office de souris. Dans la modélisation 3D,
reproduire les déplacements de la souris d’un TrackBall avec une incidence sur
le visuel de la zone de rendu, est incontestablement un plus, et cela apporte un
niveau d’intuitivité supplémentaire. Nous allons implémenter ce TrackBall pour le
Viewport3D.
Le TrackBall transforme les mouvements 2D de la souris sur la zone de rendu en
mouvements 3D par des rotations. Cela est possible en projetant la position de la
souris sur une sphère imaginaire positionnée derrière le Viewport3D. Comme le
montre la figure A-1, quand la souris se déplace, la caméra (ou la scène) tourne
en visant le même point sur la sphère positionnée derrière le pointeur de la
souris. Quand la souris bouge horizontalement, une rotation autour de l’axe Y est
nécessaire pour viser le même point. Il en est de même verticalement par une
rotation autour de l’axe X. Le TrackBall fournit une méthode intuitive par laquelle
un modèle 3D peut être manipulé dans toutes les directions en appliquant une
combinaison de rotations.
Pour mettre en place l’implémentation du TrackBall, il faut ajouter les gestionnaires
d’événements MouseLeftButtonDown, MouseMove et MouseLeftButtonUp sur le
Viewport3D.
La démarche consiste à cliquer gauche sur le Viewport3D et à maintenir le clic
en déplaçant la souris, pour provoquer les rotations adéquates de la scène 3D. Le
relâchement du clic met fin aux rotations.
Dans le fichier Index08.xaml, on détermine la position v_pos_souris de départ de
la souris sur le Viewport3D par la méthode GetPosition(..). Puis on démarre la
capture de la souris par cet UIElement par la méthode UIElement.CaptureMouse().

//donnes
private Point v_pos_souris_depart;
private Quaternion v_rotation_delta;
private Quaternion v_rotation;
//evenement MouseLeftButtonDown
private void x_viewport_MouseLeftButtonDown(object sender,
MouseButtonEventArgs e) {
e.Handled = true;
UIElement el = (UIElement)sender;
v_pos_souris_depart = e.MouseDevice.GetPosition(el);
el.CaptureMouse();
186 Annexe
Figure A-1 Viewport3D

modèle 3D

TrackBall

Viewport3D
TrackBall

modèle 3D

axe Y
orientation
originale

Copyright 2011 Patrice REY

nouvelle
orientation
Annexe 187
x_viewport.Cursor = Cursors.SizeAll;
}

Dès que le déplacement de la souris est capturé sur le Viewport3D, on évalue le


vecteur delta qui représente le déplacement de la souris de la position initiale (v_
pos_souris) vers la nouvelle position (e.MouseDevice.GetPosition(el) de la souris).
Le vecteur mouse établit le vecteur avec seulement les composantes X et Y de
delta. Le vecteur axis calcule le produit croisé des structures mouse et de celle de
l’axe Z. La variable v_rotation_delta représente une rotation en trois dimensions,
de type Quaternion, avec axis et len (len est la longueur du vecteur axis). Il ne reste
plus qu’à établir la transformation RotateTransform3D à partir d’une instance
QuaternionRotation3D, et à l’affecter à la propriété Transform de x_scene_3d.

//evenement MouseMove
private void x_viewport_MouseMove(object sender, MouseEventArgs e) {
e.Handled = true;
UIElement el = (UIElement)sender;
if (el.IsMouseCaptured) {
Vector delta = v_pos_souris_depart -
e.MouseDevice.GetPosition(el);
delta /= 2;
Vector3D mouse = new Vector3D(delta.X, -delta.Y, 0);
Vector3D axis = Vector3D.CrossProduct(mouse,
new Vector3D(0, 0, 1));
double len = axis.Length;
if (len < 0.00001) {
v_rotation_delta = new Quaternion(new Vector3D(0, 0, 1), 0);
}
else {
v_rotation_delta = new Quaternion(axis, len);
}
Quaternion q = v_rotation_delta * v_rotation;
RotateTransform3D rotation = new RotateTransform3D();
QuaternionRotation3D quatRotation = new QuaternionRotation3D(q);
rotation.Rotation = quatRotation;
rotation.CenterX = 0;
rotation.CenterY = 0;
x_scene.Transform = rotation;
}
}

Au relâchement du clic gauche de la souris, la capture de cette dernière sur le


188 Annexe
Viewport3D est arrêtée. Les variables sont remises à jour.

//evenement MouseLeftButtonUp
private void x_viewport_MouseLeftButtonUp(object sender,
MouseButtonEventArgs e) {
e.Handled = true;
v_rotation = v_rotation_delta * v_rotation;
UIElement el = (UIElement)sender;
el.ReleaseMouseCapture();
x_viewport.Cursor = Cursors.Arrow;
}

Les figures A-2 et A-3 montrent le résultat obtenu quand le clic gauche est maintenu
sur le Viewport3D avec le déplacement de la souris. L’angle de vue de la scène 3D
est modifié en fonction du positionnement de la souris.
Figure A-2

Copyright 2011 Patrice REY

le maintien du clic gauche


modifie le curseur et l’angle de
vue de la scène change avec les
rotations de la souris
Annexe 189
Figure A-3
INDEX
192 Index

A
Add 12, 17, 23
D
DependencyProperty 134
AmbientColor 44 DependencyProperty.Register 134
AmbientLight 44, 47 Descartes 13
assembly 139 DiffuseMaterial 40, 42, 44
axes de coordonnées 81 direction 14
Direction 49

B
DirectionLight 47
division 95
dll 127
DrawingBrush 45
dynamic link library 127

E
Background 55
BackMaterial 38
Brush 43, 44

C
éclairage de la scène 47
ellipsoïde 97, 160
EmissiveMaterial 44
Equals 21
Camera 32 espace de noms 139
caméra 49

F
capture 185
Children 32, 36
ClipToBounds 55
Color 44
cône 109
cône circulaire droit 111
configuration du projet 127 facette cylindrique 103
ConstantAttenuation 48 facette rectangulaire 60
ContainerUIElement3D 35, 36 facette triangulaire 53
coordonnées sphériques 89 FarPlaneDistance 50
cube 65 FieldOfView 55
cube générique 74 FielOfView 50
cylindre 101, 163 framework .NET 4 11
cylindre circulaire 101
Index 193

G
Matières 43
MatrixCamera 49
MeshGeometry3D 38
Model3D 33
Model3DGroup 33, 35, 37, 133
géométrie personnalisée 132 modèles 3D 53
Geometry 37 modélisation sphérique 91
GeometryModel3D 33, 35, 37, 57 ModelUIElement3D 31
GeometryModel3D.Material 58 ModelUIElement3D.Model 56
GetPosition 185 ModelVisual3D 31, 33
mouse 187

I
MouseDevice 187
MouseLeftButtonDown 58, 185
MouseLeftButtonUp 58, 185
MouseMove 58, 185
Multiply 25

N
ImageBrush 73
InnerConeAngle 49

L
L’ellipsoïde 97
NearPlaneDistance 50
Normalize 27
Normals 39

O
Length 16
LengthSquared 16, 26
Light 47
LinearAttenuation 48
longueur 14
LookDirection 50
objet:Cone 175

M
objet:Cylindre 167
objet:Ellipsoide 163
objet:PlanDeTravail 148
objet:Repere 140
Offset 21
OffsetX 153
Material 37, 43 OnUpdateModel 133
MaterialGroup 44, 45 OrthographicCamera 49, 52
Math.Cos 93 OuterConeAngle 49
Math.Sin 93
194 Index

P
Parse 22
S
scalaire 25
PerspectiveCamera 49 scène 3D 31
plan de travail 81 sens 14
Point3D 11 SolidColorBrush 44, 64
Point3DCollection 12 SpecularMaterial 44
PointLight 48 SpecularPower 46
PointLightBase 48 sphère 91, 160
Position 48, 49 SpotLight 48
Positions 38 Substract 18
PresentationCore 131 surface conique 109
PresentationFramework 131 surface cylindrique 101
ProjectionCamera 49 surface lumineuse 45
PropertyMetadata 134 surface mate 44
pyramide 115 surfaces 43
pyramide tronquée 117

Q T
TextureCoordinates 39
QuadraticAttenuation 48 TileBrush 44, 64
Quaternion 187 tore 119
QuaternionRotation3D 187 tore à collier nul 124
tore croisé 124

R
tore ouvert 124
TrackBall , 185
TranslateTransform3D 153
TriangleIndices 39

U
RadialGradientBrush 67
radians 93
Range 48
readonly 134
réflexion spéculaire 46
RotateTransform3D 187 UIElement3D 33, 35, 132
UIElement.CaptureMouse 185
UpDirection 50
Index 195

V
Z 11

vecteur 13
Vector3D 16
Viewport3D 31, 32, 185
Viewport3D.Children 56
Visual3D 32, 35, 133
Visual3DModel 133

W
Width 52
WindowsBase 131

X
X 11
xmlns 139

Y
Y 11

Z
196 Index
Guide
de
programmation
La programmation graphique 3D de WPF 4
(ISBN 978-2-8106-2086-9)

chapitre 1 : les vecteurs et les matrices en 3D


chapitre 2 : les projections
chapitre 3 : les transformations 3D
chapitre 4 : la scène 3D
chapitre 5 : les modèles 3D basiques
chapitre 6 : les géométries 3D personnalisées
chapitre 7 : les surfaces 3D

En vente sur la boutique en ligne de www.decitre.fr


à l’adresse suivante:

http://www.decitre.fr/livres/La-programmation-graphique-3D-de-wpf-4.
aspx/9782810620869
Initiation au jeu 2D avec Silverlight 4
(ISBN 978-2-8106-1168-3)

chapitre 1 : la vectorisation
chapitre 2 : création du projet
chapitre 3 : boucle de jeu et rendu
chapitre 4 : le déplacement des images
chapitre 5 : la détection des collisions
chapitre 6 : le score et la fin de partie
chapitre 7 : un écran d’accueil
chapitre 8 : la pause et l’arrêt de jeu
chapitre 9 : sonoriser le jeu
chapitre 10 : téléchargement du jeu

En vente sur la boutique en ligne de www.decitre.fr


à l’adresse suivante:

http://www.decitre.fr/livres/Initiation-au-jeu-avec-silverlight-4.aspx/9782810611683
La programmation graphique 2D de WPF 4
(ISBN 978-2-8106-1199-7)

chapitre 1 : les bases du graphisme 2D


chapitre 2 : les transformations 2D
chapitre 3 : les géométries et les tracés 2D
chapitre 4 : les couleurs et les pinceaux
chapitre 5 : les animations
chapitre 6 : les styles
chapitre 7 : les modèles de contrôles

En vente sur la boutique en ligne de www.decitre.fr


à l’adresse suivante:

http://www.decitre.fr/livres/La-programmation-graphique-2D-de-WPF-4.
aspx/9782810611997
Les structures de données
illustrées avec WPF et C#4
(ISBN 978-2-8106-1387-8)

chapitre 1 : la récursivité
chapitre 2 : les piles
chapitre 3 : les files
chapitre 4 : les listes chaînées
chapitre 5 : les arbres
chapitre 6 : les méthodes de tri
chapitre 7 : les recherches
chapitre 8 : les tables

En vente sur la boutique en ligne de www.decitre.fr


à l’adresse suivante:

http://www.decitre.fr/livres/Les-structures-de-donnees.aspx/9782810613878
Guide pratique de la modélisation 3D avec WPF 4

Windows Presentation Foundation (WPF) est une technologie de


développement d’application riche (Rich Desktop Application)
pour la plateforme Windows. Sa version actuelle est la version 4,
celle qui correspond au Framework .NET 4.0.
WPF est un framework managé qui exploite la puissance de
Direct3D pour l’affichage. Cette technologie de développement
d’interface utilisateur permet de moderniser et d’unifier les
techniques de développement visuel, d’exploiter la puissance
graphique des machines modernes, d’intégrer l’infographie dans
Patrice REY est le processus de développement, et de simplifier et sécuriser le
informaticien et formateur déploiement des applications.
indépendant, diplômé en
WPF sépare dans des couches distinctes la programmation des
informatique et certifié
Microsoft MCTS (Client fonctionnalités (au moyen d’un langage .NET tel que le C#) de la
Application Development). présentation visuelle par l’utilisation du langage XAML
Passionné par les (eXtensible Application Markup Language).
technologies Microsoft
Les différents chapitres permettent d’apprendre et de mettre en
Silverlight et WPF, adepte
du langage C#, au travers pratique la modélisation 3D d’une scène avec des objets 3D, des
de cet ouvrage, il vous éclairages, des caméras, des angles de vue différents dans une
fait profiter de son zone de rendu de type Viewport3D.
expertise et vous fait
Le cube, la sphère, l’ellipsoïde, le cylindre, le cône et le tore sont
partager sa passion pour
le développement modélisés en détail au travers d’une centaine d’illustrations
d’applications. pratiques. A partir d’une approche géométrique vectorielle
détaillée, la modélisation devient alors plus intuitive et
interactive.

Patrice
Pattriice
a ce
ce R
REY
EY
Edition
Edit
i iion numé
n
numérique
ériqu
érique
ue Tout le code source du livre est en téléchargement gratuit sur le
www.reypatrice.fr site http://www.reypatrice.fr

ISBN : 978-2-8106-1308-3
Éditeur :
Books on Demand GmbH, 39 €
12/14 rond point des
Champs Élysées,
75008 Paris,
France

Vous aimerez peut-être aussi