in

MSMVPS.COM

The Ultimate Destination for Blogs by Current and Former Microsoft Most Valuable Professionals.

Graphic Stream

Blog about .Net, Managed DirectX, XNA and C#

XNA Tutorial 4 : Les matrices

Retourner au sommaire des cours  

Le précédent programme que nous avons réalisé était rudimentaire. Nous n'affichions qu'un triangle en utilisant des coordonnées prétransformées (relatives à l'écran). Il faut bien avouer que nous pourrions obtenir le même résultat sous PowerPoint ... L'objet de ce tutorial va nous repositionner pleinement dans le monde 3D. Nous continuerons à afficher un triangle mais cette fois si dans un réel espace monde en 3D et nous utiliserons les matrices afin de le faire tourner.

Nous seront donc amené à étudier un peu de géométrie dans l'espace, les matrices et la caméra.

Repère 3D

Le monde de jeu se trouve dans un espace 3D orthonormé. A l'intérieur de celui-ci tout point est situé par l'intermédiaire de trois composantes : sa position par rapport à l'abscisse X, sa position par rapport à l'ordonnée Y, sa position par rapport à la côte Z. En repère 2D X et Y sont facilement identifiables : l'axe X est horizontal et Y vertical. En 3D "XNA" son se base plutot par rapport à un repère dit de "main droite". L'image ci-dessous montre un repère main droite.

Ce nom vient du fait que vous pouvez reproduire ce repère à l'aide de votre main droite. Le pouce représente l'axe X, l'index l'axe Y et le majeure l'axe Z. A l'intérieur du  monde de jeu ou World Space nous placerons désormais nos objets en utilisant des coordonnées 3D liées à cette représentation. Y croît avec la distance, Z croit avec la hauteur et X permet de se déplacer sur l'horizontale.

Notre programme

Comme à l'accoutumé j'ai repris le précédent projet nommé "SecondProjet" et je l'ai renommé en "TroisièmeProjet". Jusqu'à présent nous utilisions des coordonnées pré transformée. Cela avait pour conséquence de placer tous les objets par rapport à l'écran de jeu et non par rapport au monde de jeu. Nos premières modifications porterons sur ce point. Le triangle affiché précédemment sera maintenant placé dans un World Space.

Nous n'utiliserons donc plus la technique "Pretransformed" mais la technique "Colored".

this.effect.CurrentTechnique = effect.Techniques["Colored"];

De même la méthode Initialize spécifie de nouvelles coordonnées pour les trois points du triangle.

vertices[0].Position = new Vector3(-10f, 5f, 0f);vertices[0].Color = Color.Green;vertices[1].Position = new Vector3(7, 8f, 10f);vertices[1].Color = Color.Red;vertices[2].Position = new Vector3(2f, -7f, 3f);vertices[2].Color = Color.Yellow;

Si vous lancez l'application à ce stade vous obtiendrez une fenêtre avec un fond bleu ... mais aucune trace de triangle. Pourquoi ? La réponse est toute simple : Nous visualisons une scène 3D sur un écran ... 2D. Il y'a donc forcement une étape de transformation qui vise à passer pour chaque point dans l'espace monde d'une coordonnée 3D à une coordonnée 2D. Jusqu'ici avec le Pretransformed les objets étaint plaqués face à l'écran. Aucun besoin de transformation donc : nous avions déjà un affichage sur une surface plane. Maintenant que nous plaçons nos objets n'importe où dans l'espace nous sommes obligés de nous placer de manière à les voir. Se placer cela implique donner une position d'où regarder une scène mais aussi un point vers lequel regarder (si possible regarder dans la direction de l'objet à afficher). C'est grâce à la position et la direction que nous aurons spécifié que chaque coordonnées 3D dans le monde va être transformé en une coordonnée 2D. C'est les matrices qui vont permettre ces transformations.

 Matrice

Une matrice peut être vu comme une boite noire paramétrée qui effectue une transformation. Si vous multipliez un vecteur 3D ou une position dans l'espace par une matrice vous obtenez en retour un vecteur ou une position transformée. Cette boite peut être paramétrée afin d'effectuer plusieurs sorte de transformations : une translation (déplacement), une homothétie (redimentionnement) et/ou une rotation. Une matrice peut aussi représenter un ensemble de calculs mathématiques comme une série de transformations ou bien, ce qui nous interesse ici, les propriétés d'une caméra (position, direction, angle de vision, distance de vision ...).

 Deux nouvelles instructions vont être ajoutées à notre méthode Initialize :

Matrix viewMatrix = Matrix.CreateLookAt(new Vector3(0, 10f, -40f), new Vector3(0, 0, 0), new Vector3(0, 0, 1));Matrix projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, this.Window.ClientBounds.Width / this.Window.ClientBounds.Height, 1.0f, 45.0f);

Ici nous créons deux matrices nommées viewMatrix et projectionMatrix.

La première matrice va contenir une information à propos de la position de la caméra, le point vers lequel elle regarde et enfin l'angle qu'elle effectue avec l'horizontale. La méthode CreateLookAtstatic de la classe Matrix permet cela. Le premier paramètre correspond à la position. Nous nous plaçons à une hauteur de 10 unités (Y = 10), en et nous reculons de 40 unités (Z = 40). Le second paramètre correspond au point vers lequel regarde la caméra (ici vers l'origine (0, 0, 0)). Enfin la caméra est tenue droite (le Y = 1 indique que la perpendiculaire de la caméra se confond avec l'axe Y).

La seconde matrice paramètre la caméra. Nous spécifions tout d'abord par l'intermédiaire de la méthode CreatePerspectiveFieldOfView de la classe Matrix que la caméra à un angle d'ouverture de PI/4. Nous donnons ensuite l'aspect ratio. Il s'agit du rapport de la largeur sur la hauteur de la zone d'affichage. Cela permet d'éviter de voir les objets affinés ou grossis si la taille de la zone d'affichage n'est pas carrée. Les deux derniers paramètres sont le near plane et le far plane. C'est à dire la plus proche position visible à l'écran et la plus éloignée.

Ces deux matrices étant définies il faut les affecter pour qu'elles soient prises en compte. Nous ferons cela par l'intermédiaire de notre effet. Intialize contient pour cela les instructions suivantes :

effect.Parameters["xWorld"].SetValue(Matrix.Identity);            effect.Parameters["xView"].SetValue(viewMatrix);effect.Parameters["xProjection"].SetValue(projectionMatrix);

D'une manière générale l'instruction :

effect.Parameters["variable"]

donne accès à une variable déclarée dans un fichier effet. La méthode SetValue permet d'affecter une valeur à une variable. Nous affectons donc ici trois matrices à trois variables : xWorldxView et xProjection. Ces trois variables correspondent aux trois variables majeures qui régissent l'affichage des objets en trois dimension. Nous connaissons déjà l'utilité de View et Projection. World permet de placer les objets dans le monde. Nous reviendons sur son utilisation plus tard. Pour l'heure nous lui affectons la valeur Matrix.Identity. C'est la valeur identité pour les matrices (comme le 1 pour lamultiplication ou le 0 pour l'addition). 

Si vous lancez le programme à ce stade vous obtenez l'affichage suivant :

Maintenant notre triangle s'affiche dans un réel espace 3D !

 

Transformations

Nous sommes bientôt au bout de notre périple. La prochaine étape consiste à faire tourner ce triangle sur lui-même. Là encore c'est les matrices qui vont nous aider. Nous allons faire coincider le taux de rotation du triangle en fonction du temps écoulé depuis la dernière frame affichée. De cette façon le triangle tournera toujours à la même vitesse, quelque soit la puissance de la machine où l'activité de son CPU. Ajoutez le code suivant à la méthode Update :

Matrix world = effect.Parameters["xWorld"].GetValueMatrix() * Matrix.CreateRotationY(MathHelper.Pi/1000f*gameTime.ElapsedGameTime.Milliseconds);effect.Parameters["xWorld"].SetValue(world);           

 

La première instruction rappatrie la valeur de la variable xWorld (de type matrice) du fichier effet . Elle la multiplie par une matrice effectuant une rotation sur l'axe Y. Nous effectuons une rotation d'un angle de Pi/1000 que nous multiplions que le temps écoulé depuis le dernier affichage.

Affecter une matrice à World va affecter tous les objets qui seront affichés par la suite. Ici nous n'affichons qu'un triangle. A l'exécution nous l'allons le voir tourner sur lui-même. Pourtant le programme comporte un problème : régulièrement le triangle disparait. Ce problème qui n'en est pas un est du au "back face culling". 

Backface Culling

 Le back face culling est un algorithme intelligent intégré à XNA qui permet d'enelver de l'affichage les faces (triangles) qui ne sont pas visible depuis la position de la caméra parceque situées dernière l'objet. Si vous regardez quelqu'un dans les yeux, nous ne voyez pas l'arrière de sa tête. Ici c'est le même principe. Comment XNA sait-il qu'une face n'est pas visible ? En fait c'est le développeur qui le lui indique au moment ou il créé le tableau de vertices. Si un triangle doit être affiché par l'intermédiaire de trois vertices placé dans l'ordre des aiguilles d'une montre alors il est visible, dans le cas contraire XNA ne l'affiche pas. Reciproquement si un triangle ne s'affiche pas c'est que les vertices qui le forment sont lues dans le sens inverse des aiguilles d'une montre. Auquel cas si vous placez la caméra de l'autre coté du triangle celui-ci sera visible. Nous n'allons évidemment pas déplacer continuellement la caméra. Il est plus simple de désactiver le culling. Ajoutez le code suivant à la méthode Initialize :

this.graphics.GraphicsDevice.RenderState.CullMode = CullMode.None;

Le device possède un membre RenderState qui gère les propriétés d'affichage 3D dynamiques et notamment le culling employé. L'énumération CullMode permet d'indiquer si nous ne voulons pas de culling (None), si nous voulons cachée les faces dont le svertices sont lu dans le sens des aiguilles d'une montre (CullClockwiseFace) ou bien dans le sens inverse (CullCounterClockwiseFace).

 Nous voyons à l'exécution notre triangle tourner complètement. Il reste toutefois un léger problème. Lorque le triangle, du fait de sa rotation, s'éloigne, il semble être tronqué (voir image ci-dessous).

 Le triangle est coupé 

 Ceci est du à notre far plane. Le triangle lorsqu'il est tourné de 90 dégré dépasse en profondeur la distance maximale de vision que nous avons indiqué dans la matrice de Projection. Remplacez l'instruction

Matrix projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, this.Window.ClientBounds.Width / this.Window.ClientBounds.Height, 1.0f, 45.0f);

par

Matrix projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, this.Window.ClientBounds.Width / this.Window.ClientBounds.Height, 1.0f, 100.0f);

cette fois-ci, le programme marche parfaitement.

Conclusion

Nos sommes maintenant prets à aborder les choses sérieuses. A partir de la nos connaissances sont suffisantes pour répondre à un grand nombre de problématiques : nous savons afficher des formes, les déplacer et placer une caméra. Essayez comme exercice de positionner la caméra à un autre endroit de la scène. De même, essayez d'autres transformations (faites un redimensionnement, une translation, les deux ...).

Le prochain article sera consacré aux indices, un type de reliaison de vertices très performants. A partir de la nous seront capable d'aborder les lumières, l'affichage de modèles 3D et la création de terrains.

 

telecharger Vous pouvez télécharger le sample ici.   

 

A bientôt sur ce Blog !

Valentin Billotte

Retourner au sommaire des cours 

Only published comments... Jan 14 2007, 12:13 PM by valentin

Comments

 

benm said:

Merci pour ce trés bon tutorial, ca serait sympa que tu le soumette dans http://tutmarks.com :)

January 15, 2007 3:51 AM
 

valentin said:

de rien :)

merci à toi.

il est sur tutmark :)

January 15, 2007 7:33 AM
 

Zorglub said:

Merci pour ces 4 tutoriaux. Ce sont les plus explicites que j'ai trouvés jusque maintenant.

Félicitations.... et on attend les suivants avec impatience.

January 17, 2007 7:51 AM
 

valentin said:

marrant tu as posté ca quand je publiais un nouveau tutorial :)

January 17, 2007 9:54 AM
 

SangJun said:

Très bon tutoriaux.

Pour pinailler, je noterai juste les petites fautes

"La première instruction rappatrie la valeur de la variable xWorld (de type matrice) du fichier effet . Elle la multiplie par une matrice effectuant une rotation sur l'axe Y. Nous effectuons une rotation d'un angle de Pi/1000 que nous multiplions PAR le temps écoulé depuis le dernier affichage."

"Matrix viewMatrix = Matrix.CreateLookAt(new Vector3(0, 0f, -40f), new Vector3(0, 0, 0), new Vector3(0, 1, 0));

Matrix projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, this.Window.ClientBounds.Width / this.Window.ClientBounds.Height, 1.0f, 45.0f);

Ici nous créons deux matrices nommées viewMatrix et projectionMatrix.

La première matrice va contenir une information à propos de la position de la caméra, le point vers lequel elle regarde et enfin l'angle qu'elle effectue avec l'horizontale. La méthode CreateLookAtstatic de la classe Matrix permet cela. Le premier paramètre correspond à la position. Nous nous plaçons à une hauteur de 10 unités (Y = 10), en et nous reculons de 40 unités (Z = 40). Le second paramètre correspond au point vers lequel regarde la caméra (ici vers l'origine (0, 0, 0)). Enfin la caméra est tenue droite (le Y = 1 indique que la perpendiculaire de la caméra se confond avec l'axe Y)."

donc ce serait plutôt :

Matrix viewMatrix = Matrix.CreateLookAt(new Vector3(0, 10f, 40f), new Vector3(0, 0, 0), new Vector3(0, 1, 0));

Voilà, loin de moi l'idée de vouloir mettre le doigt sur les problèmes, c'est juste pour aider que je note ça

March 2, 2007 9:19 AM
 

valentin said:

ah non au contraire, pinaille pinaille j'adore

ca permet d'améliorer les cours :)

merci à toi pour l'info je corrige de suite :)

March 3, 2007 11:01 AM
 

Aniketos said:

Cool}Cool!

April 8, 2007 9:13 PM
 

Romain said:

Mais moi je vais encore pinailler lol. Enfaite la correction est fausse enfin pour moi SangJun à mit "donc ce serait plutôt :

Matrix viewMatrix = Matrix.CreateLookAt(new Vector3(0, 10f, 40f), new Vector3(0, 0, 0), new Vector3(0, 1, 0));"

Mais c'est là qu'il y a eureur il a fait une bonne est mauvaise correction le "-40" qui devient "40" c'est juste mais il a laissé le "10" comme il était avant alors que c'est sensé être "0" (en tout cas dans le téléchargement).

Voilas pour l'info.

June 1, 2007 1:17 PM
 

Math said:

Salut !

Je suis actuellement tes tutoriaux, et, en arrivant sur celui-ci, j'ai une erreur à la compilation :

The method call is invalid.

Sur la méthode

this.graphics.GraphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleList, vertices, 0, 1);

dans Draw.

Y'a-t-il une erreur dans le code, ou je n'ai pas bien compris quelque chose ?

June 6, 2007 6:36 AM
 

valentin said:

bonjour

tu reprend mon code tel quel ou tu as modifié qq chose ?

June 6, 2007 9:16 AM
 

LuCiFeR said:

Salut,

tu as laissé -40 et new Vector3(0, 0, 1) au lieu de new Vector3(0, 0, 1). De plus l'image du début laisse supposer que y correspond à la profondeur, pour moi c'est Z non ? Qui croire ? :p

July 24, 2007 12:54 PM
 

@NOTIZ@ said:

Bonjour,

J'ai 13 ans et je te remercie énormement pour ces tutoriaux qui mon permis d'apprendre plein de chose !

Bien que j'avais fait un peu de C++ (vraiment un peu) je suis content de pouvoir faire sa...

Mais j'aurais une petite question:

XNA est également fait pour Xbox, alors est-ce qu'il y a une différence de programmation pour Xbox ou pas ?

J'aimerais être éclairé, avoir plus de détail sur sa (quelque nuance du langage ?, faut-il refaire un

autre code, ...)

Bref peut être bête comme question,

Merci d'avance.

@NOTIZ@

July 26, 2007 5:56 AM
 

valentin said:

Merci Lucifer, pour le -40 j'ai pas trop compris si tu peux m'expliquer :)

Pour la main, c'est à toi de voir les axes comme tu le veux, si je pivote la main, y devient la hauteur et Z la profondeur :)

Salut Notiz

il n'y a pas de différence dans la manière de développer entre une appli Xna sous Windows et une appli Xna sous XBox : c'est le même langage.

Seules une petite partie des fonctionnalités seront différentes (pour certains appels de méthodes des paramètres sont facultatifs/nécessaire suivant la plateforme (je pense à la spécification de résolution qui est propre au monde fenêtre et donc Windows). De même sous Windows tu as accès a des fonctionnalités qui n'existent pas ou partiellement sous Xna (System.Windows.Form, System.Thread ...)

Les projets Xna Xbox ou Xna Windows de VS Express limitent heureusement le choix des assembly que tu peux utiliser pour t'éviter tout probleme.

October 17, 2007 10:43 AM

Leave a Comment

(required)  
(optional)
(required)  
Add


Copyright © is the original authors. Blog site is an independent site not sponsored by Microsoft. The Yoda blog server and the Brianna SQL server would like to thank www.ownwebnow.com and www.exchangedefender.com. They wouldn't be here and broadcasting without the generosity of Vlad Mazek and his companies.

Powered by Community Server (Commercial Edition), by Telligent Systems