Retourner au sommaire des cours
Il est maintenant temps d'afficher quelque chose à l'écran.
Le but de ce tutorial est de nous apprendre à dessiner à l'écran en 3D à l'aide de Vertices, et de commencer à assimiler la notion d'effet. Il s'agit là d'un cours primordial dans la mesure où un développeur de jeux XNA aura toujours à faire à ces deux notions, et ce, dans n'importe quel projet qu'il réalisera. Il convient donc de bien assimiler ce que nous allons réaliser ici (où bien de me contacter le cas échéant). Nous allons réaliser ici l'affichage d'un triangle coloré.
Le vertex
Si en 2D afficher un objet revient à "plaquer" une image à l'écran, en 3D la done est tout autre. Les objets ne sont pas dessinées à partir d'une image mais plutot a partir de vertices (un vertex, des vertices). Un vertex peut être vu comme un point dans l'espace auquel on associe des propriétés (couleur, position ...). Le pipeline 3D va relier ces points pour former un objet. Le développeur a pour tache de bien placer ces points et d'indiquer au device comment les relier.
L'image suivante illustre cela. Nous voyons un tube et un cube en trois dimension. On remarque qu'ils sont tout simplement formés à partir de points qui sont reliés entre eux.

La forme géométrique la plus simple en 3D est le triangle. Trois vertices sont nécessaires pour la former. Toute forme géométrique en 3D est formée de triangles. C’est à dire d’une multitude de vertices qui, reliés, permettent de donner une apparence à certains objets. La encore, l'image ci dessus le montre très bien.
Plusieurs solutions existent pour relier les vertices entre eux afin de former des objets 3D. Chaque solution possède ses propres avantages en fonction la forme de l’objet . C'est pourquoi il convient d’utiliser le celle qui s'avère la plus adapté dans un seul but : réduire au maximum le nombre de vertices. L’association de plusieurs vertices entre eux permet à XNA de former des triangles (assimilables à des surfaces). L’association de ces surfaces permet alors de former des objets dans l’espace. XNA résonne en ternaire ; Il lui faut trois point pour former la plus petit figure géométrique possible : le triangle.
Lorsqu'on place des points dans l'espace il est donc nécessaire de spécifier à la carte graphique la manière dont il faut relier ces points afin de créer une forme 3D. Les différentes manières possibles sont les suivantes :
Triangle List
Le mode de liaison de vertex le plus simple. Celui-ci lit les points trois par trois afin de former des triangles qu’il affiche. On comprendra donc il est nécessaire de créer un nombre de vertices multiple de trois. Les trois premiers vertices représenteront le premier triangle, les trois suivant le second triangle et ainsi de suite... C’est le mode de définition le plus simple ... mais aussi le plus coûteux.
Triangle Fan
Ce mode (comme le suivant) est plus intelligent ; il réutilise des vertices déjà utilisé pour les liaisons. On gagne ainsi de précieux octets en mémoire libérant ainsi le pipeline 3D. Dans ce mode le premier vertex est relié à tous les autres. Là aussi, les possibilités sont limités ; on ne peut faire que des formes rectangulaires et/ou cylindrique comme le montre le schéma ci-contre.
Triangle Strip
Ce troisième mode est un chouïa plus compliqué. On relie ici aussi les vertices par trois. Mais en considérant que le dernier vertex créé doit être relié aux deux précédents. Le gain de place en mémoire est très important, mais la difficulté de créer des formes complexes est multipliée.
Primitive indexée
Nous verrons dans quelques pages la création de primitives indexées. Ce mode de liaison de vertices est la solution à tous les problèmes précédemment listés pour créer des formes complexes en créant un minimum de vertices.
L'image ci-dessus tente de montrer les différences que l'on peut trouver avec les trois premier modes pour l'affichage de triangles :

a) Triangle List :
3 triangles : Vertices (0, 1, 2) puis Vertices (3, 4, 5), puis Vertices (6 7, 8) : 9 vertices pour afficher 3 triangles.
b) Triangle Fan :
3 triangles : Vertices (0, 1, 2) puis Vertices (0, 2, 3), puis Vertices (0, 3, 4) : 5 vertices pour afficher 3 triangles.
c) Triangle Strip :
6 triangles : Vertices (0, 1, 2) puis Vertices (1, 2, 3), puis Vertices (2, 3, 4), puis Vertices (3, 4, 5), puis Vertices (4, 5, 6), puis Vertices (5, 6, 7) : 8 vertices pour afficher 6 triangles.
Au vu de cette image on remarque bien les différences entre les types de reliaisons. D'autres reliaisons sont possible :
Point qui ne fait aucune liaison et laisse les points tels quels (très utile pour les effets de particules),
LineList qui relies les points deux à deux (utile pour dessiner des lignes)
LineStrip qui relie un point à son prédécesseur.
En C#, c'est l'énumération PrimitiveType qui contient les différents types d'énumérations possibles.
Rappelons que nous avons pour but d'afficher un triangle dans ce tutorial, il faudra donc créer 3 vertices, leur donner une position et, au moment de l'affichage spécifier la meilleure méthode de liaison.
Les effets
La première grande différence entre l'API DirectX et le Framework XNA auquel on est confronté vient de l'obligation d'associer un effet à toute opération de rendu. Si vous n'avez jamais développé à l'aide de DirectX vous devez vous demander ce qu'est un effet.
Nous venons de voir que les objets sont présentés sous la formes de triangles (surface élémentaire). Nous spécifions par l'intermédiaire de notre code la position des points du triangle et d'autres informations comme la couleur de ces points. Un effet accompagne ces informations en indiquant à la carte graphique comment afficher ces triangles. Il peut être vu comme un ensemble de technique qui peuvent être appliquées (ou non) au rendu d'une surface. Par techniques on peut entendre instructions données à la carte graphique pour lui "expliquer" de quel manière l'objet, situé dans un espace 3D, doit être rendu sur l'écran 2D du joueur.
Il s'agit là, il ne faut pas se le cacher, d'une technique encore trop complexe pour être abordée à ce stade de notre apprentissage. Nous utiliserons donc un fichier effet basique fourni par Microsoft et nous ne l'aborderons que succintement.
Modification du code source
Nous allons continuer sur notre lancée et modifier notre précédent programme nommé "PremierProjet". Nous appliquerons au projet de cet article nommé à juste titre "SecondProjet" les modifications et evolutions apportées dans le précédent tutorial.
La première étape consiste à ajouter un fichier effet au projet et à le gérer dans le code.
Pour ce faire cliquez droit sur le répertoire Content du projet (destiné à gérer les ressources du jeu). Selectionnez Ajouter -> Nouvel Element.

Dans la fenêtre qui s'ouvre alors selectionnez Effect File et donnez le nom Effect.fx au fichier à ajouter :

Validez. Le fichier se trouve alors ajouté au répertoire Content.
Si vous double cliquez dessus vous pourrez voir le code suivant :
float4x4 World;
float4x4 View;
float4x4 Projection;
// TODO: add effect parameters here.
struct VertexShaderInput
{
float4 Position : POSITION0;
// TODO: add input channels such as texture
// coordinates and vertex colors here.
};
struct VertexShaderOutput
{
float4 Position : POSITION0;
// TODO: add vertex shader outputs such as colors and texture
// coordinates here. These values will automatically be interpolated
// over the triangle, and provided as input to your pixel shader.
};
VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
VertexShaderOutput output;
float4 worldPosition = mul(input.Position, World);
float4 viewPosition = mul(worldPosition, View);
output.Position = mul(viewPosition, Projection);
// TODO: add your vertex shader code here.
return output;
}
float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
// TODO: add your pixel shader code here.
return float4(1, 0, 0, 1);
}
technique Technique1
{
pass Pass1
{
// TODO: set renderstates here.
VertexShader = compile vs_1_1 VertexShaderFunction();
PixelShader = compile ps_1_1 PixelShaderFunction();
}
}
Nous reviendrons sur sa signification plus tard. Pour l'heure nous allons charger l'effet en mémoire à l'intérieur d'un object C# pour pouvoir l'utiliser. Ajoutez pour celà le membre suivant à la classe Game1 :
Effect effect;
Ajoutez l'instruction suivante à la méthode Load de la classe Game1 :
this.effect = Content.Load<Effect>("Effect");
Cette instruction va utiliser la méthode Load de l'objet content pour charger la ressource nommée "Effect". La ressource renvoyée sera de type Effect et affectée au handle effect. Pour rappel, il est spécifié par défaut dans le constructeur que le répertoire où trouver les ressources est Content :
Content.RootDirectory = "Content";
L'objet Content, utilisé dans l'instruction précédente correspond au Content Manager, c'est à dire un objet dont le rôle est de gérer les ressources associées au projet. Sa méthode Load permet de charger une ressource dans un objet dont les membres vous nous permettre d'exploiter la dite ressource dans notre code. Ici on peut voir que notre fichier d'effet est manipulé maintenant par l'intermédiaire d'une instance de la classe Effect.
La string "Effect" est un identifier de ressource qui a été automatiquement associé à notre effet lorsque nous l'avons ajouté au projet. Selectionnez le fichier Effect.fx et appuyez sur F4. La fenêtre de propriété apparait alors :

Vous pouvez y voir que l'une des propriété se nomme AssetName et correspond à cette string. Vous êtes bien evidemment libre de modifier cette propriété pour lui donner la valeur de votre choix. Toutefois il est préférable de laisser le Xna Game Studio et Visual Studio effectuer ces choix à votre place.
Modifiez ensuite la méthode Draw pour lui ajouter de nouvelles instructions :
this.effect.CurrentTechnique = effect.Techniques["Technique1"];
this.effect.Begin();
foreach (EffectPass pass in this.effect.CurrentTechnique.Passes)
{
pass.Begin();
pass.End();
}
this.effect.End();
La première instruction sélectionne une technique nommée "Technique1" parmi celles contenues dans l'effet. Nous utilisons cet identifier tel quel en tant qu'index dans le tableau de technique. Notons juste qu'il s'agit là d'un code très mauvais ; il aurait été préférable d'utiliser une constante de type int. Trouver un objet à l'aide d'un indexeur de type string est toujours plus long qu'avec un indexeur de type int (la comparaison de deux int est plus rapide que deux strings). Or perdre du temps dans la méthode Draw est vraiment la dernière chose à faire. Il y'a une explication à celà : je trouve le code plus lisible ainsi pour les débutants :).
Alors qu'est ce qu'une technique ? Un fichier effet peut contenir une ou plusieurs technique qui s'apparentent à un ensemble d'affichage possible pour une forme 3D.L'appel à la méthode Begin indique que l'effet de la technique "Technique1" commence à partir de ce point et s'applique à l'affichage de tous les objets jusqu'à ce que la méthode End soit rencontrée. Entre ceux deux méthodes tout affichage sera soumi à la technique "Technique1".
Enfin, on a jamais vu quelqu'un peindre un chef d'oeuvre d'un seul coup de pinceau ; Appliquer un effet peut demander plusieurs couches ou "passes". Là encore une méthode Begin et End indiquent la zone de code où l'effet de la passe courante est pris en compte. C'est entre ces deux méthodes que nous effectuerons l'affichage de notre triangle. Vous pouvez au passage revenir sur le code contenu dans le fichier Effect.fx. Vous trouverez à la fin de celui-ci :
technique Technique1
{
pass Pass1
{
// TODO: set renderstates here.
VertexShader = compile vs_1_1 VertexShaderFunction();
PixelShader = compile ps_1_1 PixelShaderFunction();
}
}
On y trouve la définition de la technique et on peut voir qu'elle se compose d'une passe redirigeant vers deux fonctions. Nous aborderons le HLSL plus tard, ne vous inquietez pas si le code de ce fichier vous parait obscur.
Nous sommes justement maintenant prets à afficher notre première forme 3D !
Première forme 3D !
Nous avons vu au tout début de ce cours qu'un vertex était un point dans l'espace auquel on associait un ensemble d'information liées à son affichage dans l'espace. Le but de ce tutorial est d'afficher un triangle coloré à l'écran. Chaque point dans l'espace (vertex) doit donc être associé à une position et un couleur donc. Cerise sur le gateau nous n'aurons pas besoin de créer une structure de Vertex pour encapsuler ces deux informations : XNA en possède une qui répond à nos besoins : la structure VertexPositionColor.
Un triangle est composé de trois points, il faut donc créer un tableau de trois cases de type VertexPositionColor. Ajoutez la déclaration suivante en début de classe :
VertexPositionColor[] vertices;
Puis, dans la méthode Initialize nous allons créer trois vertices et l'affecter aux trois cases de ce tableau.
vertices = new VertexPositionColor[3];
vertices[2].Position = new Vector3(-0.5f, -0.5f, 0f);
vertices[2].Color = Color.Red;
vertices[1].Position = new Vector3(0, 0.5f, 0f);
vertices[1].Color = Color.Green;
vertices[0].Position = new Vector3(0.5f, -0.5f, 0f);
vertices[0].Color = Color.Yellow;
Ici le code est plutot simple : trois vertices sont créés. Chacun deux se voit affecter une position et une couleur. Nous sommes dans l'espace 3D. Une position correspond donc à trois composantes X, Y, Z (repère euclidien orthonormé dans l'espace). Le constructeur de Vector3 accepte en paramètre ces trois composantes.Reste maintenant l'affichage dudit triangle. La méthode Draw possède deux nouvelles instructions.
this.graphics.GraphicsDevice.VertexDeclaration = new VertexDeclaration(this.graphics.GraphicsDevice, VertexPositionColor.VertexElements);
this.graphics.GraphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleList, vertices, 0, 1);
Dans la première ins truction nous précisions la structure des vertices qui sont passés au device graphique. la structure VertexPositionColor contient un membre statique nommé VertexElements qui précise que la structure contient une information de position, et une information de couleur. De cette manière, la carte graphique optimise la gestion mémoire en vue de l’arrivée dans le pipeline d’un flux de vertices contenant ce type de données.
Dans la seconde instruction justement, nous passons à la carte graphique une instruction de dessin en précisant, la manière dont on va relier les vertices, le flux de vertices, l’index du premier vertex à lire dans le flux et le nombre de primitives (triangles) à afficher. Ici nous utilisons la technique TriangleList, nous donnons un flux de trois vertices (le tableau que nous venons d'initialiser), nous lisons le flux à partir du premier vertex, et nous n'affichons qu'un seul triangle.
Si vous lancez le code vous obtenez la fenêtre :

A priori on s’attendait à avoir un triangle affiché et non un écran bleu. Il est en effet nécessairede spécifier la façon dont on veut afficher la scène 3D à l’écran.
L’affichage d’un objet 3D à l’écran se réalise généralement par l’intermédiaire de trois matrices. Une matrice est une « boite magique » mathématique qui permet de réaliser des équations linéaires avec peu de traitements. Elles sont utilisées en 3D pour réaliser de nombreux calculs fastidieux de manière extremement rapide et efficaces. Ces trois matrices sont les suivantes :
1. La première matrice est la matrice World, elle spécifie où placer un objet dans un repère 3D (translation), son orientation (rotation), et sa taille (homothetie).
2. La matrice View précise la façon dont est « filmé » la scène. On parle alors de caméra.
3. La troisième matrice, nommée Projection donne les caractéristiques de la caméra, comme l’angle d’ouverture, la taille de l’écran, etc.
Ajoutez ces trois instructions à la méthode Draw, juste avant le premier appel à Begin :
this.effect.Parameters["World"].SetValue(Matrix.Identity);
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, 100f));
La propriété Parameters de la classe Effect permet d'accéder aux variables présentes dans le fichier effet et de leur affecter une valeur ou bien de la lire. Le fichier effet expose, comme on va le voir bientôt trois variables, World, View et Projection. Nous leur donnons ici, à chacune, la valeur d'une matrice.
Pour la matrice World, nous indiquons qu'il n'y aura pas de transformation, la valeur Identité de la matrice (matrice n'effectuant aucun calcul) est est ainsi passé à cette variable.
Pour la matrice View nous utilisons la méthode CreateLookAt de la classe Matrix afin de préciser la position de la caméra (ici la caméra est simplement reculée de deux unités en profondeur), l'endroit vers lequel on regarde (ici on regarde vers l'origine (0, 0, 0) ) et l'angle de la caméra avec l'horizontale (ici angle droit).
Enfin la matrice Projection spécifie un angle d'ouverture de 45° (PI/4), le ratio (largeur de l'écran sur sa hauteur), et enfin deux valeurs importantes : la distance à la caméra à partir de la quelle on peut voir un objet, et la distance au delà de laquelle un objet n'est plus visible (front plane et far plane). Là encore une méthode de la classe Matrix nommée CreatePerspectiveFieldOfView permet de créer une matrice facilement. Le ratio permet de garder un aspect cohérent pour notre scène en cours d'affichage quelque soit la taille de la zone d'affichage.
Ces trois matrices sont multipliées entre elles afin de passer d'une scène 3D à un écran 2D. C'est la carte graphique qui s'occupe de celà. On peut donc voir ces calculs comme le moyen de passer d'une position dans l'espace (X, Y Z) avec des propriétés de couleur, de texturing, d'illumination à une position à l'écran (X, Y) d'un pixel coloré.
Si vous relancez le programme maintenant vous obtenez l'écran suivant :

Mieux, mais toujours insuffisant ! A priori nous devions avoir un triangle avec plusieurs couleurs, or là, seul le rouge est visible. Il va nous falloir, pour aboutir à ce résultat, étudier et comprendre le code du fichier effet afin de pouvoir le modifier.
Courage ! Ouvrez donc maintenant le fichier effect.fx en double cliquant dessus. Vous devriez tomber sur le code précédemment affiché dans cet article. A première vue le code semble assez proche du language C. C’est enfait du HLSL (High Level Shader Language). Il est donc assez "lisible", mais nous allons tout de même l'expliciter. Etudions le.
Au tout début du fichier se trouve les déclarations de variables globales du fichier effet. On y retrouve justement les trois déclarations de matrices que nous avons affecté précédemment :
float4x4 World;
float4x4 View;
float4x4 Projection;
On affecte des valeurs ou on récupere la valeur d'une de ces variables à l'aide de la propriété Parameters de l'objet effect :
this.effect.Parameters["View"].SetValue(Matrix.CreateLookAt(new Vector3(0, 0, -2), Vector3.Zero, Vector3.Up));
Passons à la suite du fichier. On trouve après ces trois variables la déclaration de deux structures :
struct VertexShaderInput
{
float4 Position : POSITION0;
// TODO: add input channels such as texture
// coordinates and vertex colors here.
};
struct VertexShaderOutput
{
float4 Position : POSITION0;
// TODO: add vertex shader outputs such as colors and texture
// coordinates here. These values will automatically be interpolated
// over the triangle, and provided as input to your pixel shader.
};
Généralement, un effet réalise l'affichage d'un objet auquel il est lié en deux étapes. La première étape, consiste à manipuler les vertices de l'objet à leur appliquer une suite de transformations et de calculs afin de pouvoir passer de la représentation 3D de l'objet à un écran 2D. Cette étape correspond à ce qu'on appelle le vertex shader. Dans une seconde étape, nommée Pixel Shader chaque triangle de la scène est convertie en pixels et chaque pixels est coloré à sa juste valeur. A priori, si notre problème vient de la couleur du triangle, c'est sur le pixel shader qu'il va faloir travailler. A quoi servent donc les deux structures ci-dessus ? Elle permettent de réaliser plusieurs types d'échanges de données :
-
D'abord entre l'extérieur (notre programme C#) vers le premier shader de l'effet (le vertex shader)
-
Puis entre le vertex shader et le pixel shader
-
Et enfin entre le pixel shader et la carte graphique pour l'affichage final.
La première structure, nommée à juste titre VertexShaderInput permet à l'effet de recevoir tous les vertices que nous avons passé à l'aide de la méthode DrawUserPrimitives. Il ne recevra ici qu'une information de Position :
struct VertexShaderInput
{
float4 Position : POSITION0;
// TODO: add input channels such as texture
// coordinates and vertex colors here.
};
On remarque donc ici un premier problème : il n'y a pas de membre pour stocker la couleur du vertex ! La seconde struture nommée VertexShaderOutput est la structure de donnée échangée entre le Vertex Shader et le Pixel Shader.
Un shader dans un effet peut donc être vu comme une fonction qui, renvoie ou reçoit une structure (comme celles que nous venons de décrire) effectue des traitement sur les données de celle-ci, et renvoie une autre structure de données contenant le resultat de ces traitements.
Etudions la première fonction :
VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
VertexShaderOutput output;
float4 worldPosition = mul(input.Position, World);
float4 viewPosition = mul(worldPosition, View);
output.Position = mul(viewPosition, Projection);
// TODO: add your vertex shader code here.
return output;
}
Elle prend en entrée une valeur de type VertexShaderInput et renvoie une valeur de type VertexShaderOutput. La première instruction de la fonction vise à créer une variable nommée ouput de type VertexShaderOutput. Elle multiplie ensuite à l'aide la méthode mul la position du vertex courant (reçu directement depuis le flux envoyé par la méthode Draw) par la matrice Word afin de placer le vertex dans le monde 3D. Elle multiplie ensuite le resultat de cette opération par la matrice View afin d'avoir la représentation du vertex dans l'espace depuis notre "camera". Enfin une multiplication est réalisée avec la matrice Projection pour passer du monde 3D à l'écran 2D. La valeur obtenue est affecté à un des membre de la variable ouput qui est elle-même renvoyée.
La seconde méthode se présente comme ceci :
float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
// TODO: add your pixel shader code here.
return float4(1, 0, 0, 1);
}
Elle prend une valeur de type VertexShaderOuput (reçue depuis la fonction précédente) et renvoie un tableau de 4 flottants. Nous reviendrons sur la signification exacte du type float4 plus tard. Quoi qu’il en soit à ce stade nous pouvons dire que les 4 flottants correspondent aux composantes RGBA (rouge, vert, bleu, alpha) de la couleur à attribuer au pixel. 1 correspondant à la valeur maximale de la composante et 0 à la minimale. Ici la couleur renvoyée est donc le rouge. On remarque donc ici un second problème : tout pixel sera rouge !
Enfin le fichier se termine par la définition de la technique :
technique Technique1
{
pass Pass1
{
// TODO: set renderstates here.
VertexShader = compile vs_1_1 VertexShaderFunction();
PixelShader = compile ps_1_1 PixelShaderFunction();
}
}
Le fichier ne contient donc qu’une seule technique nommée Technique1. Celle-ci réalise son affichage en une seul passe nommée Pass1.
La passe se caractérise par un vertex shader et un pixel shader. On retrouve un pointeur vers nos deux méthodes. Les mots clés "compile vs_1_1" et "compile ps_1_1" indiquent que les shaders doivent être compilés dans la version 1.1 du language.
Pas d’inquiétudes s’il reste des zones d’ombre, nous avons parcouru le fichier très rapidement sans nous attader sur certaines spécificités syntaxiques. Revenons à notre problème : le triangle rouge.
Premier soucis, la structure en entrée ne contient qu’une information de Position. Or la structure que nous manipulons dans le programme C# contient Position et Couleur. Modifiez la structure ainsi :
struct VertexShaderInput
{
float4 Position : POSITION0;
float4 Color : COLOR0;
// TODO: add input channels such as texture
// coordinates and vertex colors here.
};
Nous avons rajouté un nouveau champs nommé Color de type COLOR0. Réalisez la même opération avec la structure de sortie :
struct VertexShaderOutput
{
float4 Position : POSITION0;
float4 Color : COLOR0;
// TODO: add vertex shader outputs such as colors and texture
// coordinates here. These values will automatically be interpolated
// over the triangle, and provided as input to your pixel shader.
};
Reste maintenant à modifier les shaders. Commencez par le vertex shader. Nous avons juste ici à ajouter une ligne d’affection pour récupérer la couleur du vertex entrant et la passer à la valeur envoyée en sortie de méthode :
VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
VertexShaderOutput output;
float4 worldPosition = mul(input.Position, World);
float4 viewPosition = mul(worldPosition, View);
output.Position = mul(viewPosition, Projection);
output.Color = input.Color;
// TODO: add your vertex shader code here.
return output;
}
Reste le pixel shader. Nous n’avons plus à renvoyer la couleur rouge mais plutôt à renvoyer celle de la valeur en entrée qui est la sortie de la méthode précédente :
float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
// TODO: add your pixel shader code here.
return input.Color;
}
Relancez le programme. Nous obtenons enfin la sortie voulue :

Conclusion
De nombreuses choses auraient pu être vues ici : les effets plus en profondeurs, un peu de mathématiques 3D, les différentes méthodes d'affichage du Device... Tout cela sera en fait assimilé au fil des tutoriaux. Pas d'inquiétudes à avoir donc. Pour l'heure nous pouvons être fier : nous savons créer un effet, l'appliquer. Nous sommes capable de créer une forme et de l'afficher (avec couleurs s'il vous plait !). Comme exercice en attendant de lire le prochain tutorial, essayez d'afficher un carré et une maison. Essayez de même de reproduire le carré avec les méthodes TriangleFan et TriangleStrip.
Pas d’inquiétude à avoir si il vous reste de nombreuses zones d’ombre sur les effets et le code qu’ils contiennent, nous apprendrons au cours d’un long tutorial à maitriser le HLSL.
Vous pouvez télécharger le sample et les correction des exercices ici.
Retourner au sommaire des cours