Académique Documents
Professionnel Documents
Culture Documents
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.
É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
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
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
Point3D et Vector3D
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
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»
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
A
Copyright 2011 Patrice REY
4
O X
3 vecteur de
l’origine à A(4,3,3)
Z
CHAPITRE 1 □ Point3D et Vector3D 19
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.
Figure 1-9
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
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().
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).
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().
Figure 1-15
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
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
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
//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
//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
3 - La création de modèles 3D
<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>
<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
<ContainerUIElement3D>
<ContainerUIElement3D>
...
Copyright 2011 Patrice REY
</ContainerUIElement3D>
<ContainerUIElement3D>
...
</ContainerUIElement3D>
...
</ContainerUIElement3D>
CHAPITRE 2 □ La scène 3D 39
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
Figure 2-6
sens
antihoraire
indice 0
A(0,3,0)
indice 1
B(4,0,0)
X
indice 2
C(0,0,3)
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>
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.
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
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>
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>
<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
7 - Les caméras
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.
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
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)
(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).
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.
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.
<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
Figure 3-4
62 Guide pratique de la modélisation 3D avec WPF 4
2 - La facette rectangulaire
(0,0,4)
indice 1 (6,0,4)
(0,1) (1,1) indice 2
<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
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.
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
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
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
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>
(0,0) (0,1)
2 (0,1,1) 1 (1,1,1) X
3 (0,0,1) 0 (1,0,1)
(1,0)
(1,1)
<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>
Figure 3-20 Y Y
X X
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
<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>
<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
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>
2 (0,y,z) 1 (x,y,z)
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
(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)
face face
avant dessous
Copyright 2011 Patrice REY
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.
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);
}
//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
...
}
//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 dessus
face droite
face avant
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).
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)
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
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);
}
//
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;
}
Figure 3-28
CHAPITRE 4
La modélisation de la sphère
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
pt2
pt1
β pt3
Z pt0
φ 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;
}
//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
3 - L’ellipsoïde
//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
//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
cas du
cylindre
creux:
A
O
Copyright 2011 Patrice REY
D
X
Z
CHAPITRE 5 □ La modélisation du cylindre 105
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
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
point B:
xb = Rh*cos(φ) = xa
yb = H
zb = -Rh*sin(φ) = za
A
za
O φ
X
xa
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
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;
}
//
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
//
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)
La figure 6-4 visualise la réalisation d’un cône circulaire tronqué avec des vues sur
Copyright 2011 Patrice REY
//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
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
//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
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
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
R
B
r C
β A
point A:
xa = (R + r*cos(β))*cos(φ) D
φ
ya = r*sin(β)
za = -(R+r*cos(β))*sin(φ)
X
//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
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
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
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
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
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
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.
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
namespace Geo3d {
public class Repere : UIElement3D {
...
//redefinition ------------------------------------
protected override void OnUpdateModel() {
...
}
...
}
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
//-------------------------------------------------
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.
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>
<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
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).
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);
}
}
//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;
}
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
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.
//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
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
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):
return (int)GetValue(PrDivBeta);
}
set {
SetValue(PrDivBeta, value);
}
}
//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;
}
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
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:
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);
}
}
//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;
}
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
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.
//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;
}
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);
}
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
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:
//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
//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
</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
nouvelle
orientation
Annexe 187
x_viewport.Cursor = Cursors.SizeAll;
}
//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;
}
}
//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
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)
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
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)
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
http://www.decitre.fr/livres/Les-structures-de-donnees.aspx/9782810613878
Guide pratique de la modélisation 3D avec WPF 4
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