David Catuhe
Utilisation de la technologie DirectX Managed, Partie 5/9
Ce chapitre va nous permettre de mettre en place un éclairage réaliste sur nos objets afin de simuler un environnement cohérent.
Par David Catuhe publié le 02/10/2005 à 22:27, lu 9846 fois, 2 pages
 2 | Mise en oeuvre
Téléchargez le code source - 47 Kb
Mise en oeuvre
Création de la lumière
Nous allons commencer par créer une classe Light qui se chargera de nous fournir les informations nécessaires pour l'éclairage. Pour ce faire nous lui associerons deux propriétés : une pour sa couleur et une pour sa position. De plus, nous allons développer une méthode Activate (comme pour la caméra) afin d'affecter toutes ces propriétés à Direct3D.
using System;
using System.Drawing;

namespace InteriorWise
{
    public class Light : Entity
    {
        Color color = Color.White;

        public Light(string name) : base(name)
        {
        }

        public Color Color
        {
            get
            {
                return color;
            }
            set
            {
                color = value;
            }
        }

        public void Activate(int id)
        {
            Microsoft.DirectX.Direct3D.Light dxLight = new Microsoft.DirectX.Direct3D.Light();

            dxLight.Diffuse = color;
            dxLight.Type = Microsoft.DirectX.Direct3D.LightType.Point;
            dxLight.Position = Position;
            dxLight.Range = 200.0f;

            DirectXCore.device3D.Lights[id].FromLight(dxLight);
            DirectXCore.device3D.Lights[id].Enabled = true;
            DirectXCore.device3D.Lights[id].Update();
        }
    }
}

Notons dans cette méthode Activate qu'en plus d'affecter nos propriétés, nous assignons également la propriété Range qui définit la distance au-delà de laquelle la lumière n'est plus calculée. L'activation d'une lumière se fait dans une collection de DirectX et il sera important de veiller à ne pas avoir plus de 8 lumières actives en simultanée.
Affectation d'un matériau
Pour que notre objet possède un matériau, nous allons lui ajouter une propriété Color qui définira sa couleur propre. De plus, dans sa méthode Render nous allons ajouter le code suivant juste avant le mesh.DrawSubset :
            Material mat = new Material();
            mat.Diffuse = color;

            DirectXCore.device3D.Material = mat;

Génération des normales
Pour générer nos normales aux points, nous allons faire appel à une fonction des meshs de DirectX. Mais pour cela nous devons générer des meshs avec la place nécessaire à un vecteur supplémentaire par point.La fonction de chargement d'un objet devient donc :
    public void LoadFromXml(string file)
    {
        XmlDocument xmlDoc = new XmlDocument();

        xmlDoc.Load(file);

        XmlNode obj = xmlDoc.SelectSingleNode("/object");

        if (obj != null)
        {
            wireFrame = bool.Parse(obj.Attributes["wireFrame"].Value);
            culling = bool.Parse(obj.Attributes["culling"].Value);
            name = obj.Attributes["name"].Value;

            position.X = float.Parse(obj.Attributes["x"].Value);
            position.Y = float.Parse(obj.Attributes["y"].Value);
            position.Z = float.Parse(obj.Attributes["z"].Value);

            localTexture = Texture.FromBitmap(DirectXCore.device3D, 
                (Bitmap)Bitmap.FromFile(obj.Attributes["texture"].Value), Usage.AutoGenerateMipMap, Pool.Managed);
            
            XmlNode vertices = xmlDoc.SelectSingleNode("/object/vertices");
            XmlNode faces = xmlDoc.SelectSingleNode("/object/faces");

            mesh = new Mesh(faces.ChildNodes.Count, vertices.ChildNodes.Count, 
                MeshFlags.Managed, CustomVertex.PositionNormalTextured.Format, DirectXCore.device3D);

            GraphicsStream data = mesh.LockIndexBuffer(LockFlags.None);

            foreach (XmlNode face in faces.ChildNodes)
            {
                data.Write(short.Parse(face.Attributes["a"].Value));
                data.Write(short.Parse(face.Attributes["b"].Value));
                data.Write(short.Parse(face.Attributes["c"].Value));
            }

            mesh.UnlockIndexBuffer();

            data = mesh.LockVertexBuffer(LockFlags.None);

            foreach (XmlNode vertex in vertices.ChildNodes)
            {
                data.Write(float.Parse(vertex.Attributes["x"].Value));
                data.Write(float.Parse(vertex.Attributes["y"].Value));
                data.Write(float.Parse(vertex.Attributes["z"].Value));
                data.Write(0);
                data.Write(0);
                data.Write(0);
                data.Write(float.Parse(vertex.Attributes["u"].Value));
                data.Write(float.Parse(vertex.Attributes["v"].Value));
            }

            mesh.UnlockVertexBuffer();
        }

        mesh.ComputeNormals();
    }

Intégration de la lumière dans le rendu
Au niveau de la scène elle-même, nous allons donc rajouter une collection de lumières qui sera parcouru lors du rendu pour effectuer leur activation.
    ArrayList lights = new ArrayList();

    public void AddLight(Light light)
    {
        lights.Add(light);
    }

La fonction de rendu de la scène se trouve donc être modifiée pour devenir :
    public void Render()
    {
        if (camera == null)
            return;

        camera.Activate();

        int index = 0;
        foreach (Light l in lights)
        {
            l.Activate(index++);
        }

        foreach (Object3D obj in objects)
        {
            obj.Render();
        }
    }

Activation du calcul lumineux
Finalement, le calcul lumineux s'active en affectant à vrai la propriété Lighting sur notre DirectXCore.
 
» Démarrer une discussion