Plus....

Beginning Game Development

Partie III –DirectX II

Traduit par Valentin BILLOTTE

Consultez cet article en anglais  

Cet article n’a pas été traduit par Microsoft. Il n’a pas été relu ou vérifié par Microsoft.

Sur cette page

Introduction Introduction
Dessiner une mire Dessiner une mire
Un Model Un Model
Dessiner des primitives Dessiner des primitives
BEGIN SCENE/END SCENE BEGIN SCENE/END SCENE
LIGHTS, CAMERA, ACTION LIGHTS, CAMERA, ACTION

Introduction

Bienvenue dans la troisième partie de cette série consacrée à l’apprentissage du développement de jeu. Dans cet article nous allons entrer plus en profondeur dans l’univers de DirectX en abordant des principes comme les transformations, les matrices, le culling et le clipping.

NETTOYAGE DU CODE

Les modifications qui suivent ont dors et déjà été prises en compte dans les projets.

  1. Dans le précédent article nous avons mis la création de la fenêtre en mode fenêtré sous la condition d’être en mode « debug ». Pour être dans ce mode, entrez dans les propriétés du projet et ajoutez cette option :
    • Cliquez droit sur le projet the BattleTank2005 et sélectionnez Properties.
    • Sélectionnez l’onglet Build.
    • Dans la section principale, cochez l’option Define DEBUG.
  2. Changez la couleur dans l’appel à la méthode device.Clear de DarkBlue à Black.
  3. Ajoutez le code suivant à la fin du constructeur de GameEngine pour donner à la fenêtre une taille standard.

    Visual C#

    // force the window to a standard size
    // the provides the correct aspect ratio of 1.33
    this.Size = new Size ( 800, 600 );

    Visual Basic

    'force the window to a standard size
    ' the provides the correct aspect ratio of 1.33
    Me.Size = New Size(800, 600)
  4. Changez la propriété Startup de la fenêtre principale à CenterScreen.
    • Cliquez droit que la fenêtre GameEngine et sélectionnez View Designer.
    • Dans les propriétés changez la propriété StartPosition à CenterScreen

Maintenant, nous pouvons prêt à dessiner un contenu à l’écran et nous pouvons commencer à créer notre jeu.

Haut de page Haut de page

Dessiner une mire

Dans BattleTank 2005 nous nous trouvons à l’intérieur d’un tank et sommes en mesure de regarder l’extérieur par l’intermédiaire d’une petite fente situé à l’avant. Nous allons utiliser une mire placée sur cet espace afin d’aider le joueur lorsqu’il visera un ennemi. En réalité, la mire est située directement sur le canon.

Deux moyens s’offrent à nous pour afficher une mire à l’écran.

  1. Dessiner directement au centre de l’écran, en utilisant les coordonnées de l’écran.
  2. Dessiner en utilisant les coordonnées du monde 3D en s’assurant que le point de vision est situé de manière à ce qu’il soit visible et centre à l’écran.

Le choix à faire ici porté sur la rapidité et l’extensibilité. Si nous choisissons la première option, nous n’aurons pas à transformer les coordonnées à partir du moment où nous sommes déjà dans l’univers 2D puisque nous travaillons au niveau de l’écran. Cette première option est donc à priori la plus rapide. Pourtant cette vue ne sera utile qu’à l’intérieur d’un tank. Impossible d’imaginer une extension au jeu ou le joueur pourra sortir de son tank ; la mire le suivrait partout … La seconde option demande d’ajuster les coordonnées 3D en coordonnées 2D. Mais le code sera bien plus facile à faire évoluer suivant les besoins dans le futur.

Nous utiliserons donc la seconde option parce que plus flexible. Inutile de passer du temps à essayer de rendre le jeu plus rapide sans savoir ce qui le ralenti. Lorsque vous réaliserez vos propres jeux, vous serez souvent confrontés à ce genre de dilemme. Il convient de réfléchir posément à la meilleure solution.

Avant d’aller plus en avant, continuons à expliciter de nouveaux termes et définitions liés à DirectX qui nous seront utile bientôt.

Haut de page Haut de page

Un Model

Imaginez une pièce vide. Je décide que l’origine des axes X, Y et Z est situé dans le coin a gauche en face de moi. Cette pièce représente maintenant l’espace de mon monde.

Espace monde ou World Space: Un système cartésien en trois dimensions ou il est possible de placer un objet à n’importe quelle position.

Imaginons maintenant que je place une chaise à un emplacement spécifique. Chaque point sur la chaise peut être décrit en utilisant une coordonnée cartésienne (X, Y, Z) plus des informations optionnelles sur sa couleur (Color) ou sur sa texture (Tu, Tv). C’est là, la définition que nous avions donné au vertex (voir article précédent). Une chaise contient donc de nombreux vertices. Nous allons les stocker dans un tableau de vertices. Lorsque ce tableau est chargé en mémoire, il devient un buffer de vertex (vertex buffer).

Vertex buffer

Les vertex buffer ont été « inventé » spécifiquement pour les transformations complexes que permet DirectX. DirectX fourni un ensemble de types de vertex prédéfinit qui représentent les formats les plus rencontrés. Ces types sont définis en tant que structure dans la classe CustomVertex.

Nous utiliserons les vertices PositionColored pour la mire. Ce type de vertex fournit les propriétés X, Y, Z une propriété Color, ce qui correspond en tout point à ce que nous recherchons.

Ajoutez les méthodes suivantes à la suite de la méthode OnPaint dans la classe GameEngine.

Visual C#

private CustomVertex.PositionColored[]
CreateCrossHairVertexArrayTop ( ) {
CustomVertex.PositionColored[]
crossHairs = new CustomVertex.PositionColored[7];
float zval = 0f;
// top of targeting crosshairs crossHairs[0].Position = new Vector3 ( -1f, 1f, zval );
crossHairs[1].Position = new Vector3 ( -1f, 2f, zval );
crossHairs[2].Position = new Vector3 ( 0f, 2f, zval );
crossHairs[3].Position = new Vector3 ( 0f, 3f, zval );
crossHairs[4].Position = new Vector3 ( 0f, 2f, zval );
crossHairs[5].Position = new Vector3 ( 1f, 2f, zval );
crossHairs[6].Position = new Vector3 ( 1f, 1f, zval );
crossHairs[0].Color = Color.Green.ToArgb ( );
crossHairs[1].Color = Color.Green.ToArgb ( );
crossHairs[2].Color = Color.Green.ToArgb ( );
crossHairs[3].Color = Color.Green.ToArgb ( );
crossHairs[4].Color = Color.Green.ToArgb ( );
crossHairs[5].Color = Color.Green.ToArgb ( );
crossHairs[6].Color = Color.Green.ToArgb ( );
return crossHairs;
}
private CustomVertex.PositionColored[]
CreateCrossHairVertexArrayBottom ( ) {
CustomVertex.PositionColored[]
crossHairs = new CustomVertex.PositionColored[7];
// bottom of targeting crosshairs float zval = 0f;
// bottom of targeting crosshairs
crossHairs[0].Position = new Vector3 ( 1f, -1f, zval );
crossHairs[1].Position = new Vector3 ( 1f, -2f, zval );
crossHairs[2].Position = new Vector3 ( 0f, -2f, zval );
crossHairs[3].Position = new Vector3 ( 0f, -3f, zval );
crossHairs[4].Position = new Vector3 ( 0f, -2f, zval );
crossHairs[5].Position = new Vector3 ( -1f, -2f, zval );
crossHairs[6].Position = new Vector3 ( -1f, -1f, zval );
crossHairs[0].Color = Color.Green.ToArgb ( );
crossHairs[1].Color = Color.Green.ToArgb ( );
crossHairs[2].Color = Color.Green.ToArgb ( );
crossHairs[3].Color = Color.Green.ToArgb ( );
crossHairs[4].Color = Color.Green.ToArgb ( );
crossHairs[5].Color = Color.Green.ToArgb ( );
rossHairs[6].Color = Color.Green.ToArgb ( );
return crossHairs;
}

Visual Basic

Private Function
CreateCrossHairVertexArrayTop() As CustomVertex.PositionColored()
Dim crossHairs(7) As CustomVertex.PositionColored
Dim zval As Single = 0.0F
' top of targeting crosshairs
crossHairs(0).Position = New Vector3(-1.0F, 1.0F, zval)
crossHairs(1).Position = New Vector3(-1.0F, 2.0F, zval)
crossHairs(2).Position = New Vector3(0.0F, 2.0F, zval)
crossHairs(3).Position = New Vector3(0.0F, 3.0F, zval)
crossHairs(4).Position = New Vector3(0.0F, 2.0F, zval)
crossHairs(5).Position = New Vector3(1.0F, 2.0F, zval)
crossHairs(6).Position = New Vector3(1.0F, 1.0F, zval)
crossHairs(0).Color = Color.Green.ToArgb()
crossHairs(1).Color = Color.Green.ToArgb()
crossHairs(2).Color = Color.Green.ToArgb()
crossHairs(3).Color = Color.Green.ToArgb()
crossHairs(4).Color = Color.Green.ToArgb()
crossHairs(5).Color = Color.Green.ToArgb()
crossHairs(6).Color = Color.Green.ToArgb()
Return crossHairs
End Function

Private Function
CreateCrossHairVertexArrayBottom() As CustomVertex.PositionColored()
Dim crossHairs(7) As CustomVertex.PositionColored
' bottom of targeting crosshairs
Dim zval As Single = 0.0F
' bottom of targeting crosshairs
crossHairs(0).Position = New Vector3(1.0F, -1.0F, zval)
crossHairs(1).Position = New Vector3(1.0F, -2.0F, zval)
crossHairs(2).Position = New Vector3(0.0F, -2.0F, zval)
crossHairs(3).Position = New Vector3(0.0F, -3.0F, zval)
crossHairs(4).Position = New Vector3(0.0F, -2.0F, zval)
crossHairs(5).Position = New Vector3(-1.0F, -2.0F, zval)
crossHairs(6).Position = New Vector3(-1.0F, -1.0F, zval)
crossHairs(0).Color = Color.Green.ToArgb()
crossHairs(1).Color = Color.Green.ToArgb()
crossHairs(2).Color = Color.Green.ToArgb()
crossHairs(3).Color = Color.Green.ToArgb()
crossHairs(4).Color = Color.Green.ToArgb()
crossHairs(5).Color = Color.Green.ToArgb()
crossHairs(6).Color = Color.Green.ToArgb()
Return crossHairs
End Function

Souvenez vous que les coordonnées pour la propriété Position de chaque vertex se réfèrent aux coordonnées de l’espace monde. Nous allons effectuer une transformation pour les adapter à l’affichage 2D de l’écran dans un moment.

Avant de continuer nous avons besoin de spécifier au device le type de vertex que nous allons utiliser. C’est la propriété VertexFormat du device qui va nous permettre de faire cela par l’intermédiaire du champ Format du vertex utilisé. Elle permet au device de connaître la nature des vertices manipulés : Ici, ils possèdent une position et une couleur.

A l’intérieur de la méthode OnPaint, immédiatement après l’instruction device.Clear ajoutez le code suivant :

Visual C#

device.VertexFormat = CustomVertex.PositionColored.Format;

Visual Basic

device.VertexFormat = CustomVertex.PositionColored.Format

La mire définie, nous devons demander au device de l’afficher à l’écran par l’intermédiaire de sa description contenue dans le vertex buffer. C’est la méthode DrawUserPrimitives qui va nous permettre cela. Qu’est qu’une Primitive ?

Haut de page Haut de page

Dessiner des primitives

Les primitives sont des ensembles de vertices qui définissent un unique objet 3D. Il y’a six type de primitives possible liés par l’énumération PrimitiveType.

  • Line List: Souvent utilisé pour ajouter des informations en surimpression à l’écran (Heads-up Display ou HUD). Le nombre de primitives est égal au nombre de points divisé par deux. Le nombre de point doit d’ailleurs être pair.
  • Line Strip: Identique à Line List mais n’affiche qu’une simple ligne continue (à la manière des jeux « relier les points pour afficher un objet »). Le nombre de primitives est égal au nombre de vertices -1.
  • Point List: Principalement utilise pour afficher des simples points pour des effets de particules comme des explosions ou des étoiles dans la nuit. Le nombre de primitives est égal aux nombre de vertices dans le vertexbuffer.
  • Triangle Fan: Utile lorsqu’on a à afficher un objet aux formes ovales.
  • Triangle List: C’est le type de primitives le plus couramment utilise. Le nombre de primitive est égale au nombre de vertices divisé par trois.
  • Triangle Strip: Très utile pour afficher les objets aux formes rectangulaires.

Dans notre cas nous allons utiliser le type LineStrip pour afficher la mire à l’écran. A l’intérieur de la méthode OnPaint, immédiatement après l’instruction device.Clear ajoutez le code suivant :

Visual C#

device.DrawUserPrimitives (PrimitiveType.LineStrip, 6,
CreateCrossHairVertexArrayTop ( ) );
device.DrawUserPrimitives (PrimitiveType.LineStrip, 6,
CreateCrossHairVertexArrayBottom ( ) );

Visual Basic

device.DrawUserPrimitives(PrimitiveType.LineStrip, 6,
CreateCrossHairVertexArrayTop())
device.DrawUserPrimitives(PrimitiveType.LineStrip, 6,
CreateCrossHairVertexArrayBottom())

La méthode DrawUserPrimitives demande un paramètre de type PrimitiveType, le nombre de primitives à afficher et les données vertex pour l’objet à afficher. A partir du moment où nous utilisons le type LineStrip, les 7 points de chaque vertex buffer créent six lignes.

A ce point nous n’avons pas encore dessiné quoi que ce soit à l’écran, juste effacé son contenu à l’aide de la méthode Clear. Nous devons demander au device d’effectuer un rendu. C’est la méthode BeginScene qui effectue cette tâche.

Haut de page Haut de page

BEGIN SCENE/END SCENE

Il y’a beaucoup de points commun entre le développement DirectX et la direction d’un tournage de film. Nous avons ainsi déjà parlé d’images par secondes, de frame, de caméra, de scènes.

Nous utilisons les méthodes BeginScene et EndScene du device pour définir le point de début et de fin d’une scène. La méthode BeginScene prépare le device pour les actions qui vont suivre en verrouillant le back buffer. La méthode EndScene indique au device que nous avons terminé et déverrouille le back buffer. L’appel à la méthode EndScene doit toujours se faire après celui à BeginScene autrement le back buffer restera verrouillé. Ces deux méthodes travaillent de manière couplée avec la méthode Present dans la manipulation du back buffer ; si une de ces méthodes échoue dans son travail, les autres suivront.

A l’intérieur de la méthode OnPaint de la classe GameEngine, ajoutez les appels à BeginScene et EndScene. L’appel à BeginScene intervient directement après l’appel à la méthode Clear.

Visual C#

device.Clear ( ClearFlags.Target, Color.Black, 1.0f, 0 );
// Tell DirectX we are about to draw something
device.BeginScene ( );

Visual Basic

device.Clear(ClearFlags.Target, Color.Black, 1.0F, 0) '
Tell DirectX we are about to draw something
device.BeginScene()

Et l’appel à EndScene doit se faire juste avant l’appel à la méthode Present.

Visual C#

// Tell DirectX that we are done drawing
device.EndScene ( );
// Flip the back buffer to the front
device.Present ( );

Visual Basic

' Tell DirectX that we are done drawing
device.EndScene()
' Flip the back buffer to the front
device.Present()

Le travail est terminé. La dernière étape consiste à transformer les coordonnées 3D en coordonnées comptable avec un affichage à l’écran.

Nous avons abordé un grand nombre de terme lies à DirectX dans le précédent article. Il est désormais temps d’en aborder une nouvelle série afin d’afficher un monde 3D de manière parfaite et maitrisée.

Haut de page Haut de page

LIGHTS, CAMERA, ACTION

Revenons à notre exemple de chaise placée dans un modèle cartésien 3D. Nous avons à ce stade définit tous points de la chaise en utilisant les coordonnées cartésienne et une couleur et en les plaçant dans un vertex buffer. Pourtant DirectX ne peut toujours pas afficher cet objet. Pourquoi ? Les données manquantes pour cela sont notre location dans la scène et la direction où nous regardons. Ces deux données sont primordiales pour transformer une scène 3D en une image 2D affichée à l’écran.

C’est la matrice View (vue) qui détermine la position de la caméra (le point à partir duquel on regarde la scène). A partir de maintenant, nous pouvons considérer que les termes de view et camera sont synonymes.

Les caméras représentent un outil très puissant en DirectX si bien utilisées ; il est possible d’attacher une caméra à un objet mobile pour donner l’impression de se retrouver à la place de ce dernier, ou de la placer légèrement en arrière pour donner une vue « embusquée ». D’une manière générale la position de la caméra contribue énormément à l’ambiance d’un jeu. Il est souvient bien utile de placer plusieurs caméra dans son monde pour voir l’action en cours sous plusieurs angles (utile pour les jeux de sports).

Tous les traitements participants à la conversion des coordonnées 3D en 2D utilisent une matrice. Ces traitements sont appelés transformations. Ils constituent le plus gros des traitements effectués par DirectX dans l’affichage d’une scène.

Transformations : Les Transformations sont des traitements appliqués à des coordonnées 3D basés sur la View, sur le type de projection (similaire au Lens d’une caméra) et/ou sur la transformation courante appliqué au monde. Ces transformations sont réalisées par l’intermédiaire de matrices 4x4.

Matrice () : Une table de nombre très efficace dans les transformations.

Nous pourrions passer beaucoup de temps à comprendre en détails le fonctionnement des transformations à l’aide des matrices. Comprendre leur fonctionnement est important, mais nous n’aurons pas à réaliser les transformations nous même. La classe Matrix contient la plupart des méthodes les plus utiles et communes pour la manipulation de matrices.

La première étape vise à placer et à orienter la camera dans notre monde 3D.

Transformation View (position et orientation de la camera)

La matrice view définit la location de notre caméra et son orientation (en spécifiant un point où « regarder »).

Cette matrice permet aussi de spécifier où se trouve l’axe verticale (généralement l’axe Y). Les méthodes Matrix.LookAtLH et Matrix.LookAtRH permettent de générer une telle matrice. Etant donné que nous utilisons le repère main gauche c’est la première méthode que nous utilisera (LH pour Left Handed). Si aucune matrice de vue n’est spécifiée DirectX en utilisera une par défaut.

A l’intérieur de la méthode OnPaint de la class GameEngine, ajoutez le code suivant immédiatement après l’instruction device.Clear.

Visual C#

device.Transform.View = Matrix.LookAtLH ( new Vector3 ( 0, 0, 5f ),
new Vector3 ( 0, 0, 0 ), new Vector3 ( 0, 1, 0 ) );

Visual Basic

device.Transform.View = Matrix.LookAtLH(New Vector3(0, 0, 5.0F),
New Vector3(0, 0, 0), New Vector3(0, 1, 0))

Dans Battle Tank 2005 nous plaçons la camera à l’origine (0,0,0) et face à l’axe Z (0,0,5). Nous spécifions que la haut se trouve sur la valeur positive de l’axe Y.

  • Le point vers lequel nous regardons est le (0,0,5).
  • Le point sur lequel nous nous trouvons est le (0,0,0)
  • La verticale de la caméra et plus Y est grand, plus grande est la hauteur.

Maintenant que la camera est placée et orientée, nous pouvons mettre en place la matrice de projection.

Transformation de Projection

Dans DirectX on trouve deux type de projections :

La projection en perspective est la plus couramment utilisée. Elle donne une vision proche de celle de l’œil humain. Les objets voient leur taille diminuer en fonction de la distance à laquelle ils se trouvent par rapport à la caméra.

La projection orthogonale ignore la distance (valeur Z) et garde la taille des objets quelque soit leur taille.

Nous utiliserons bien entendue une projection en perspective dans BattleTank 2005. La projection détermine comment les vertices d’un objet sont transformés dans le frustum de vision (http://en.wikipedia.org/wiki/Viewing_frustum). Le frustum de vision définit un espace 3D à l’intérieur duquel les objets sont visibles de la caméra. Il s’agit en fait d’un cône (ou plutôt d’une pyramide) avec au sommet la caméra. Le sommet représente ce qu’on appel le near plane (plan proche) et la base le far plane (plan éloigné). Plus la base est large, plus la vision est large (un œil peut voir a 180° le monde qui l’entoure par exemple). La transformation doit ainsi spécifier 4 propriétés :

  1. Field of View (FoV): Généralement 45 dégrés ou Math.PI / 4. En réduisant le FoV on peut donner l’impression de Zoomer vers l’extérieur sur la scène. Une valeur supérieur à 45 degrés donnera l’impression d’une vue de lapin.
  2. Aspect Ratio: Malheureusement la zone d’affichage 2D ou est généré la scène n’est pas souvent carrée. Pour respecter les proportions de la scène suivant la largeur/hauteur de cette zone on spécifie ici le ratio qui consiste a diviser la largeur par la hauteur. Pour une zone en 1024*768 on spécifiera 1.33 (écran en 4/3).
  3. Near Clipping Plane: Les objets plus proches de la camera que ce plan ne seront pas affichés.
  4. Far Clipping Plane: Les objets situés au delà de se plan éloignés ne seront pas affichés.

    Radians: Dans DirectX les angles sont exprimés en Radians. Pour convertir un angle en degrés vers son équivalent en radians, multipliez simplement la valeur en degrés par PI/180… ou utilisez les méthodes utilitaires de la classe Geometry

En utilisant ces matrices DirectX va être en mesure de transformer les vertices de chaque objet pour pouvoir afficher un rendu 2D à l’écran.

A l’intérieur de la méthode OnPaint de la classe GameEngine, ajoutez le code suivant immédiatement après l’appel à l’instruction device.Transform.View.

Visual C#

device.Transform.Projection = Matrix.PerspectiveFovLH (
(float)Math.PI / 4, this.Width / this.Height, 1.0f, 100.0f );

Visual Basic

device.Transform.Projection = Matrix.PerspectiveFovLH(CType
(Math.PI / 4, Single), Me.Width / Me.Height, 1.0F, 100.0F)

Pour BattleTank 2005 nous avons utilises un FoV classique de 45 degrés. Nous avons spécifié un ratio d’aspect se basant sur la taille de la fenêtre où est affichée la scène puis nous avons spécifié le frustum de vision entre 1 et 100. Cet espace de 100 unités peut représenter tout et n’importe quoi. Pour BattleTank 2005 nous partirons du principe qu’une unité représente 10 mètres. Nous voyons donc ici à 1 kilomètre de distance.

Il faut savoir à ce point raison garder. Nous pourrions très bien, par folie des grandeurs spécifier qu’une unité représente une kilomètre. Donnant une distance de vue portant à 100 kilomètres. Si nous donnons au tank leur taille réelle, nous ne pourrons plus les voir passer un certain nombre de kilomètres de distance. Pourquoi alors perdre des ressources à les afficher au loin si nous ne pouvons pas les voir ?

Alors que la matrice de view et de projection définissent la caméra et sa propriété Lens, la matrice de transformation de monde (ou World) converti l’espace 3D associés à chaque objet en coordonnées dans l’espace monde. Ces coordonnées sont alors transformées pour être affichées à l’écran par l’intermédiaire des matrices View et Projection.

Transformation World

La dernière transformation est une transformation appliquée au monde. Elle place les objets 3D que nous avons créés dans la scène 3D.

Dans une transformation de type monde, nous pouvons déplacer, faire tourner et agrandir/réduire chaque objet. Une transformation sur le monde s’applique à tous les objets affichés jusqu’à ce qu’une nouvelle transformation monde soit spécifiée.

Nous n’utiliserons pas de transformations de monde pour BattleTank 2005 à ce point de notre apprentissage. Pour vous aider un cube de test a toutefois été ajouté afin de vous permettre d’expérimenter ces trios transformations. Essayez pour tester de modifier leurs propriétés afin de déterminer les modifications que cela impacte à l’écran. C’est le moyen le plus simple et le plus rapide de bien comprendre le principe de ces transformations.

Lights (lumières)

DirectX utilise l’éclairage pour déterminer la couleur de chaque pixel. A partir du moment où nous n’avons pas spécifié de source de lumières, nous pouvons simplement désactiver l’éclairage pour laisser à DirectX la gestion de la lumière. Si nous ne faisons pas cela, DirectX partirai du principe qu’il n’y a aucune lumière et affiche tous les pixels en noir. A l’intérieur de la méthode OnPaint de la classe GameEngine, ajoutez le code suivant immédiatement après l’instruction device.Transform.Projection.

Visual C#

// turn off the light source
device.RenderState.Lighting = false;

Visual Basic

' turn off the light source
device.RenderState.Lighting = False

En plus du contrôle de la luminosité, RenderState permet de contrôler le Culling.

Culling

Le Culling représente une opération qui supprime des objets en entier (à la différence du clipping qui ne supprime qu’une partie) de la scène à partir du moment où ils ne se trouvent pas dans le frustum. Le but principal du culling est bien entendu de rendre l’affichage des objets visibles plus rapide.

Clipping: Le Clipping élimine les portions non visibles à l’écran des objets 3D affichés. Le Clipping est géré par DirectX et ne demande aucune intervention de la part du développeur.

Lorsque DirectX affiche un objet 3D, il ne dessine pas les primitives (triangles) qui se trouvent sur les faces qui ne sont pas visibles depuis la caméra. On appelle cette technique le back face culling.

DirectX détermine quelle partie d’un objet est face à la camera en utilisant l’ordre des vertices dans le vertex buffer. Si les trois points qui composent un triangle sont dessinés dans le sens des aiguilles d’une montre alors le triangle (primitive) est visible. Dans lecas cnotraire il n’est pas affiché. Il est possible de choisir entre le sens des aiguilles d’une montre, le sens inverse, ou aucun des deux et d’afficher la face avant et arrière d’un objet en même temps. Le mode par défaut c’est le sens inverse. Il faut donc bien veiller à créer ses vertices dans le sens des aiguilles d’une montre.

Les options de cilling se spécifient dans le RenderState en passant une valeur de l’énumération Cull a la device.RenderState.CullMode.

A l’intérieur de la méthode OnPaint de la classe GameEngine, ajoutez le code suivant juste après l’instruction device.RenderState.Lighting.

Visual C#

// Turn off backface culling
device.RenderState.CullMode = Cull.None;

Visual Basic

' Turn off backface culling
device.RenderState.CullMode = Cull.None

Dans le code accompagnant cet article ont trouvera d’autres spécifications que vous pourrez manipuler afin de tester les différentes possibilités offertes par le RenderState.

Experimentation

Pour supprimer l’affichage de la mire commentez les lignes 122 et 123 (en VB.NET 92 et 93).

Vous pouvez afficher un cube tournant en dé-commentant les 98, 101, 120 et en commentant la 95 (VB.NET: 68, 71, 87, 90 et 65). N’hésitez pas à modifier les matrices de transformation pour simplement voir les modifications que cela apporte à l’écran.

Ces trois premiers articles nous ont permis de couvrir des notions très importantes en 3D avec DirectX. Nous avons vu les fondements du développement 3D. Aucune application Direct3D ne peut passer outre les notions que nous avons acquises dans cet article. Nous savons désormais comment créer un device, comment l’associer à une fenêtre et créer une boucle de jeu à l’aide des méthodes OnPaint et Invalidate. Vous êtes capable de créer votre propre objet 3D à l’aide des vertex buffer et de la méthode DrawUserPrimitives. Enfin vous êtes capable de paramétrer une camera et de mettre en place dans transformations dans l’espace du monde de jeu.

Si quelque chose vous semble encore obscur dans ce que nous venons de voir, reportez vous aux liens que j’ai spécifié au cours de cet article et tentez de modifier le programme en jouant sur les propriétés et paramètres pour observer l’effet résultat.

Dans le prochain article nous continuerons sur Direct3D et nous aborderons les classes importantes du namespace DirectInput.

D’ici là, joyeux développements !

Haut de page Haut de page Précédent 3 sur 7 Suivant