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… Il faut bien avouer que nous pourrions obtenir le même résultat sous PowerPoint ou en Winform. L’objet de ce tutorial va nous repositionner pleinement dans le monde 3D. Nous continuerons à afficher un triangle mais cette fois-ci nous utiliserons les matrices afin de l’animer.


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. Ainsi Z croît lorsqu’il se rapproche de l’observateur. L’axe X est orienté vers la droite, enfin l’axe Y croît avec la hauteur. Ainsi nous pourrions définir les vecteurs cardinaux Up, Down, Foarward, Backward, Left, Right de cette manière :


up = new Vector3(0f, 1f, 0f);
down = new Vector3(0f, -1f, 0f);
right = new Vector3(1f, 0f, 0f);
left = new Vector3(-1f, 0f, 0f);
forward = new Vector3(0f, 0f, -1f);
backward = new Vector3(0f, 0f, 1f);


Notre programme


Comme à l’accoutumé le programme du tutorial précédent va être repris et évolué pour prendre en compte les nouveautés de ce chapitre. Il sera renommé en “TroisièmeProjet”.


Le but de cet article est donc de faire tourner le 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. Nous avons vu précédemment que c’est la matrice World qui s’occupe de “réaliser” les transformations à effectuer sur un objet. Par transformation nous entendons translation, scale et … rotation. Ecrire “à la main” une matrice pour qu’elle réalise une transformation n’est pas forcement très simple. Heureusement la classe Matrix possède un ensemble de membre statique (comme nous l’avons déjà vu) qui permettent de créer des instances très facilement.


Remplacez l’instruction d’affectation de la matrice World de l’effet à l’intérieur de la méthode Draw par cette ligne :


 this.effect.Parameters[“World”].SetValue(Matrix.CreateRotationY( (float)gameTime.TotalGameTime.TotalSeconds));


Nous appellons ici la méthode statique CreateRotationY qui renvoie une matrice configurée pour réaliser une rotation autour de l’axe Y. Le fichier effet auquel nous donnons la matrice va multiplier celle-ci par tous les vertices présent dans le flux envoyé à la carte graphique par l’intermédiaire de la méthode Draw. Les vertices ainsi multipliés vont voir leur position modifiée et vont donner l’impression d’être en rotation. Tout objet affiché entre les méthode Begin et End de l’effet seront ainsi soumis à cette transformation. Nous donnons à la méthode CreateRotationY le temps total écoulé depuis le lancement du jeu. Nous aurions pu donner une valeur constante type PI/4. Mais le triangle n’aurait pas été animé. Il aurait juste été legerement pivoté. Le fait d’utiliser le temps total écouté fait que notre triangle tourne à vitesse constante.


A l’exécution nous l’allons le voir tourner effectivement 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 sur lequel repose la carte graphique pour réaliser ses rendu. Il 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 la carte graphique sait-elle 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 lus 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).


Amélioration du code


Nous plaçons à l’intérieur de la méthode Draw des instructions qui ne sont pas directement liées à l’affichage : les trois affectations des matrices World, View et Projection. Déplacez ainsi les instructions : 


this.effect.Parameters[“World”].SetValue(Matrix.CreateRotationY( (float)gameTime.TotalGameTime.TotalSeconds));


A l’intérieur de la méthode Update et les deux instructions :


this.effect.Parameters[“View”].SetValue(Matrix.CreateLookAt(new Vector3(0, 0, -2), Vector3.Zero, Vector3.Up));


this.effect.Parameters[“Projection”].SetValue(Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, this.GraphicsDevice.Viewport.AspectRatio, 0.1f, 2.1f));


dans Load.


Tout simplement parceque la matrice World doit être mise à jour à chaque frame alors que les propriétés et caractéristiques de la caméra ne changent pas. 


Pour terminer, et pour améliorer notre culture, modifiez le farPlaneDistance (dernier paramètre de la méthode CreatePerspectiveFieldOfView) qui définit la distance au delà de laquelle un objet n’est plus visible. Il est pour l’heure de 100f. Changez la valeur a 2.1f. Nous voyons à l’exécution notre triangle tourner complètement mais du fait de sa rotation, les vertices de sa base s’éloignent, et disparaissent au gré de la rotation (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. Remettez la valeur 100 pour que le programme marche parfaitement.


Autre élément important : modifiez la taille de la fenêtre affichant le triangle. Après cette action vous devriez à nouveau être soumis au back-face culling. Ceci est simplement du au fait que le device a été reinitialité lors de cette action. Il reprend donc ses valeurs par défaut. Il est donc nécessaire de lui respecifier le culling à appliquer. A ce niveau de nos connaissances nous pourrions parer ce problème qu’en mettant l’instruction concernée dans la méthode Update qui est appellée à chaque frame. Ce ne serait pas très propre ni optimisé… Heureusement le device offre un ensemble d’evenements qui permettent de parer àc ette eventualité. Enregistrez vous sur l’événement reset dans le constructeur de cette manière :


graphics.DeviceReset += new EventHandler(graphics_DeviceReset);


On mettre alors à l’intérieur de la méthode graphics_DeviceReset tout ce qui est nécessaire à la configuration du device :


void graphics_DeviceReset(object sender, EventArgs e)
{
     this.graphics.GraphicsDevice.RenderState.CullMode = CullMode.None;
}



Conclusion


Nos sommes maintenant prets à aborder les choses sérieuses. A partir de là 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.


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


[Soon]


Valentin Billotte


Retourner au sommaire des cours 


 

29 thoughts on “XNA Tutorial 4 : Les matrices”

  1. 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.

  2. 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

  3. ah non au contraire, pinaille pinaille j’adore
    ca permet d’améliorer les cours :)
    merci à toi pour l’info je corrige de suite :)

  4. 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.

  5. 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 ?

  6. 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

  7. 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@

  8. 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.

  9. Qu est ce que t as technique “colored” ?? Le debut de ce tuto est pas du tout clair , je pense qu il me manque cette nouvelle technique dans mon fichier effect.fx ou alors elle est ailleurs .

  10. les images de ton sites ne s’affichent pas, pourquoi ?

    j’aimerai connaître d’utiliser tout les effects de fichier .fx
    en fait, quand on multiplient une matrice dans autre matrice via la fonction mul ou autre … qu’est ce qu’on vois comme résultat?

    pourquoi on multiplient ses matrices, on peut fixé le caméra sur le cois qu’on veut et c’est tout le role et jouer !!! pas besoin de casser la tete avec les multiplication dont je pige rien, non ?

    merci d’avoir nous explique, et d’avoir nous donnes encore et encore des tutorial en francais sur le fichier .fx

  11. Il faut trois matrices pour réaliser un affichage :

    La matrice World
    La matrice View
    La matrice Projection

    World permet de placer un objet dans l’espace 3D (Par place j’entend Translation, Rotation, Scale).
    View precise les propriétés de la “caméra” avec laquelle on visionne la scène (position de la caméra, l’endroit vers lequel on regarde …)
    Projection spécifié les caractéristiques de l’affichage (ration de l’écran, distance maximale de visibilité, angle d’ouverture, etc.)

    Ces trois matrices permettent de passer d’un monde en 3 dimensions à un écran en deux dimensions. Inutile pour cela de réaliser un enchainement de milliers de calculs mathématique. Il existe une boite noire, nommée Matrix qui permet de réaliser facilemetn et rapidement ce genre de calculs.

    Voilà pourquoi on les multiplie entre elles.

    Un vertex multiplié par ces trois matrices devient une position 2D à l’écran de ton ordinateur.

  12. Bonjour,

    Je voudrais juste savoir à partir de quand les images seront mit à jour ?

    Parce qu’il est difficile de savoir si nous avons la bonne chose à l’écran !

    Merci

  13. Salut, j’ai un problème (hey oui…)

    Après avoir changé les coordonnés dans la méthode initialize j’ai essayé de démarrer la fenêtre d’affichage du projet, mais ça plante et ça m’indique un erreur sur cette ligne

    this.effect.CurrentTechnique = effect.Techniques[“Colored”];

    qui dit :”This method does not accept null for this parameter.
    Nom du paramètre : value”

    Je n’ai aucune idée de ce que ça veut dire j’ai suivit ce début de tuto à la lettre(bah, faut croire que non finalement lol).

    Autres choses: Fallait-il enlevé les lignes matrices (view, world et projection)qu’on avait placé dans le précédent tutoriel pour que ça fonctionne (J’ai essayé, mais même chose) ?

    En cherchant pourquoi cet erreur j’ai trouvé ceci:

    vertices[1].Position = new Vector3(7, 8f, 10f);

    Or, il manque à la première coordonné (X je crois) un “f” après le 7, c’est normal ?

    C’est tout je crois.

  14. Salut !

    j’ai un message d’erreur lorsque je lance la fenêtre d’affichage : “This method does not accept null for this parameter.
    Nom du paramètre : value”

    Cette ligne: “this.effect.CurrentTechnique = effect.Techniques[“Colored”];”
    est encadré en jaune

    J’en suis à l’étape juste avant l’introduction aux matrices où je suis supposé voir un écran bleu.

    Merci

  15. ok oublie le dernier message, je croyais ça ne fonctionnais pas (apparemment y’a un délai d’une journée avant que les messages apparaissent). Merci.

  16. Pour demandeuranonyme, j’ai le même problème, c’est normal puisque nous sommes en XNA 3.0 (si j’ai bien compris) on va devoir attendre l’update le l’article…

  17. Oui, j’espère l’update pret pour demain
    J’ai terminé aujourd’hui la mise à jour des trois premiers pour la sortie de la 3.1.

  18. Merci pour les premiers tuto’, mais j’ai rencontré un problème lors de ma compilation par rapport à :
    this.effect.Parameters[“World”].SetValue(Matrix.CreateRotationY( (float)gameTime.TotalGameTime.TotalSeconds));

    En effet, on m’indique l’erreur suivante :
    Erreur 1 Une référence d’objet est requise pour la propriété, la méthode ou le champ non statique ‘Microsoft.Xna.Framework.GameTime.TotalGameTime.get’ ..\Visual Studio 2008\Projects\Essai\Essai\Game1.cs

    Que faire ??

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>