1 Introduction
Nous continuons notre visite au pays de DirectX Managed avec aujourd’hui la mise en place de notre modèle objet et du premier rendu graphique.
2 Vision d’ensemble
Afin d’avoir une vision facilement compréhensible de notre système, nous allons nous inspirer du monde réel pour définir les principaux acteurs du moteur graphique.
Ainsi, nous allons nous tourner vers le cinéma qui représente une bonne abstraction d’un rendu 3D. En effet, le film projeté sur écran a été capturé via la lentille d’une caméra qui filmait à ce moment là une scène. Ce cheminement est le même dans le cadre de la 3D : Une caméra virtuelle (nous, notre œil) va « filmer » une scène dans laquelle évolue des objets.
Le schéma de notre système est donc tout tracé :
Un objet général, la scène, contiendra une collection d’objets qui seront les acteurs de notre rendu. Pour simuler le point de vue de l’utilisateur, nous aurons une classe caméra qui se chargera d’être notre avatar dans le monde virtuel.
Les objets comme les caméras seront des entités du monde et auront de ce fait des propriétés en commun (ce qui se traduira par un héritage depuis une classe mère).
Le formulaire principal se chargera lors de chaque rendu de demander à la scène de dessiner les objets qu’elle contient.
3 Les entités
Une entité est l’élément de base de notre monde. Elle est caractérisée par un nom et une position dans l’espace.
4 Les objets
Un objet est une entité qui est capable d’offrir une représentation lors du rendu de la scène.
Dans un premier temps, un objet sera défini comme une entité qui possède une rotation sur chacun des axes et qui a des attributs d’affichage graphique.
Pour représenter la structure géométrique d’un objet, nous allons utiliser une classe de DirectX Managed qui est le Mesh. Cette dernière encapsule tout ce dont a besoin la carte graphique pour afficher un objet 3D.
De même, nous allons définir deux booléens qui permettront respectivement de dessiner l’objet en filaire et de désactiver l’élimination des faces cachées.
Pour pouvoir construire un premier objet simplement, nous allons faire appel à une fonctionnalité de DirectX Managed qui va nous permettre de créer simplement un cube :
public void CreateAsCube(float width, float height, float depth)
{
mesh = Mesh.Box(DirectXCore.device3D, width, height, depth);
}
A partir de cet instant, l’instance de la classe Mesh contient une liste de points et de faces qui permettront au système de dessiner l’objet 3D.
Finalement, nous allons doter notre classe Objet3D d’une méthode pour effectuer son affichage et pour paramétrer la carte graphique :
public void Render()
{
if (mesh == null)
return;
Matrix world = Matrix.RotationYawPitchRoll(rotation.Y, rotation.X, rotation.Z);
world = world * Matrix.Translation(Position);
DirectXCore.device3D.Transform.World = world;
if (wireFrame)
DirectXCore.device3D.RenderState.FillMode = FillMode.WireFrame;
else
DirectXCore.device3D.RenderState.FillMode = FillMode.Solid;
if (culling)
DirectXCore.device3D.RenderState.CullMode = Cull.CounterClockwise;
else
DirectXCore.device3D.RenderState.CullMode = Cull.None;
mesh.DrawSubset(0);
}
La première étape consiste à fournir une matrice à la carte graphique afin de définir la position et l’orientation de l’objet. Pour ce faire nous multiplions deux matrices : une pour la rotation (RotationYawPitchRoll) et une pour la position (Translation).
La deuxième étape consiste à mettre en place les options pour le filaire et pour l’élimination des faces cachées via les propriétés de device3D.RenderState

Avec élimination des faces cachées

Sans élimination des faces cachées
Finalement, il ne reste plus qu’à demander au mesh de se dessiner avec la méthode DrawSubset.
5 La caméra
La camera va nous fournir une abstraction pour définir la matrice qui servira à visualiser le monde depuis le bon point de vue.
Dans les faits, il s’agit d’une entité qui possède une cible qu’elle regarde.
Ainsi, la scène qui est liée à une caméra pourra demander à cette dernière de mettre en place la matrice de vue. La caméra positionnera également la matrice de projection qui se chargera de transformer le monde 3D en 2D afin d’être affiché à l’écran.
public void Activate()
{
Matrix view = Matrix.LookAtLH(Position, Target, new Vector3(0, 1.0f, 0));
DirectXCore.device3D.Transform.View = view;
DirectXCore.device3D.Transform.Projection = Matrix.PerspectiveFovLH((float)Math.PI / 4, 1.0f, 1.0f, 1000000.0f);
}
Grâce à DirectX Managed, la complexité mathématique est masquée pour faire place à des appels de méthodes au sein de la classe Matrix.
6 La scène
La scène est le container qui contiendra la liste des objets ainsi qu’une caméra. Elle fournit les méthodes pour faire le dessin d’une image et les méthodes pour ajouter des objets et définir la caméra.
Sa principale méthode est la fonction Render :
public void Render()
{
if (camera == null)
return;
camera.Activate();
foreach (Object3D obj in objects)
{
obj.Render();
}
}
7 Intégration au formulaire
Au niveau du formulaire, il nous suffit de modifier la boucle de rendu pour appeler la méthode Render d’une scène que nous avons construite au préalable.
Cette scène contiendra une seule caméra et un seul objet :
Scene scene = new Scene("Scène 01");
Camera camera = new Camera("Principale");
Object3D objet = new Object3D("cube");
camera.Position = new Vector3(0, 0, -4.0f);
scene.Camera = camera;
objet.CreateAsCube(1.0f, 1.0f, 1.0f);
scene.AddObject3D(objet);
Nous allons également rajouter des gestionnaires d’événements qui vont nous permettre de pouvoir faire tourner un objet dans la scène :
private void pctBox_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
Vector3 rotation = objet.Rotation;
rotation.Y -= ((float)(e.X - mouseX)) / 100.0f;
rotation.X -= ((float)(e.Y - mouseY)) / 100.0f;
objet.Rotation = rotation;
mouseX = e.X;
mouseY = e.Y;
}
}
private void pctBox_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
mouseX = e.X;
mouseY = e.Y;
}
Ainsi, via deux données d’instance (mouseX, mouseY) nous récupérons les mouvements de la souris lorsque l’utilisateur maintient le bouton gauche enfoncé et nous affectons ces mouvements à la rotation de notre objet.
8 Conclusion
Encore une fois, la mise en œuvre est extrêmement simplifiée par l’encapsulation fournie par DirectX Managed.
Après avoir mis en œuvre toute l’infrastructure de notre système, la prochaine étape consistera à charger nos objets depuis des fichiers et à les habiller.