Tutorial 3


DirectX using C#

Tutorial 3

Camera Setup
this.device.Transform.Projection = Matrix.PerspectiveFovLH(FieldOfView, AspectRatio, 0.3f, 500f);
Its important to know how directX camera works. Imagine yourself looking at straight road, there is certain limit to your view. Field of view(FOV) of Human eye is ~ 95 degrees. And there will be 2 planes bounding your FOV, one is called Near point and the other Far point. Similar is the functioning of DirectX camera.

  • Field Of View - Angle in radians
  • AspectRatio - ratio of width to height
  • zNearPlane - Near point
  • zFarPlane - Far point

this.device.Transform.View = Matrix.LookAtLH(CameraPosition, LookAt, UP);
this is for positioning our camera and setting its view direction

  • CameraPosition - Vector3 for position
  • LookAt - point where it is staring
  • UP - direction vector to decide camera orientation [direction of the yellow Triangle arrow, see fig.]

Local Axis of Object

Global coordinates
Local coordinates




Local Vs Global system







Suppose you want to move a car model forward, then you must advance its position in the direction of your car or local z-axis of the car. Now, every time you want to move the car, you have to add the position vector with a vector in direction of local axis to get new position vector. This can be only done if you can know the global equivalent of the local axis.

LocalToGlobal()

Object.orientation is a Vector3 and to understand it, see this code chunk under Object.Render()
CosmicX.device.Transform.World = Matrix.Scaling(Scaling.X, Scaling.Y, Scaling.Z) * Matrix.RotationX(Orientation.X) * Matrix.RotationZ(Orientation.Z) * Matrix.RotationY(Orientation.Y) * Matrix.Translation(Position);
Every time before rendering each object, world is transformed according to the transformation of object. Suppose the orientation of car is (0, 90, 0), it means that car is to be rotated 0° about x-axis; 90° about y-axis; 0° about z-axis.
Function Vector3 Object.LocalToGlobal() actually rotates the local axis of object wrt its orientation to get desired Global axis.

Staring an object

        public void Stare(Object o, float distance, float height)
        {
            CameraPosition = LookAt = o.Position;
            LookAt.Y += 1;
            Vector3 v = o.LocalToGlobal();
            v.Multiply(distance / v.Length());
            CameraPosition += v;
            CameraPosition.Y = o.Position.Y + height;
            this.device.Transform.View = Matrix.LookAtLH(CameraPosition, LookAt, UP);
        }
This is similar to moving the object. Instead of moving the object, we placed the LookAt point over the object and moved our camera backwards

Lightening

Two category of lights is featured by DirectX
  1. Ambient light - present everywhere, low intense, non-directional
  2. Direct light - directional, varying intensity
public Color SunLightColor //Ambient light
            {
                get { return Device.RenderState.Ambient; }
                set { Device.RenderState.Ambient = value; }
            }

Direct light
            this.device.Lights[0].Type = LightType.Directional;
            this.device.Lights[0].Diffuse = Color.White;
            this.device.Lights[0].Direction = new Vector3(1, 1, -1);
Furthermore, there are 3 types under direct light. Learn more

Complete code

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
using D3D = Microsoft.DirectX.Direct3D;

namespace XBasic
{
    public partial class Form1 : Form
    {
        class cosmicX
        {
            event EventHandler Render;
            #region -FIELDS-
            D3D.Device device;
            Form form;
            float _AspectRatio, _FieldOfView;
            static cosmicX _CosmicX;
            Vector3 CameraPosition, LookAt;
            Vector3 UP = new Vector3(0, 1, 0);
        
#endregion
            #region -Properties-
            public D3D.Device Device
            {
                get { return device; }
                set { device = value; }
            }
            public static cosmicX CosmicX
            {
                get { return cosmicX._CosmicX; }
                set { cosmicX._CosmicX = value; }
            }
            public float FieldOfView
            {
                get { return _FieldOfView; }
                set { _FieldOfView = value; }
            }
            public float AspectRatio
            {
                get { return _AspectRatio; }
                set { _AspectRatio = value; }
            }
            public Color SunLightColor
            {
                get { return Device.RenderState.Ambient; }
                set { Device.RenderState.Ambient = value; }
            }
#endregion
            #region -Methods-
            public cosmicX(Form f)
        {
            CosmicX = this;
            this.form = f;
            D3D.PresentParameters presentParams = new D3D.PresentParameters();
            presentParams.Windowed = true;
            presentParams.SwapEffect = SwapEffect.Discard;
            presentParams.AutoDepthStencilFormat = DepthFormat.D16;
            presentParams.EnableAutoDepthStencil = true;
            this.Device = new D3D.Device(0, D3D.DeviceType.Hardware, f, CreateFlags.SoftwareVertexProcessing, presentParams);
            SetUp();
        }
        void SetUp()
        {
            this.device.RenderState.Lighting = true;
            this.device.Lights[0].Type = LightType.Directional;
            this.device.Lights[0].Diffuse = Color.White;
            this.device.Lights[0].Direction = new Vector3(1, 1, -1);
            this.device.Lights[0].Update();
            this.device.Lights[0].Enabled = true;
            this.device.Lights[1].Type = LightType.Directional;
            this.device.Lights[1].Diffuse = Color.White;
            this.device.Lights[1].Direction = new Vector3(-1, -1, -1);
            this.device.Lights[1].Update();
            this.device.Lights[1].Enabled = true;
            SunLightColor = Color.White;
            FieldOfView = 3.14f / 4;
            AspectRatio = (float)form.Width / (float)form.Height;
            this.device.Transform.Projection = Matrix.PerspectiveFovLH(FieldOfView, AspectRatio,0.3f, 500f);
        }
        public void RenderX()
        {
            this.device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.DarkSlateBlue, 1.0f, 0);
            this.device.BeginScene();
            if (Render != null)
                Render(this, null);
            this.device.EndScene();
            this.device.Present();
            this.form.Invalidate();
        }
        public void Stare(Object o, float distance, float height)
        {
            CameraPosition = LookAt = o.Position;
            LookAt.Y += 1;
            Vector3 v = o.LocalToGlobal();
            v.Multiply(distance / v.Length());
            CameraPosition += v;
            CameraPosition.Y = o.Position.Y + height;
            this.device.Transform.View = Matrix.LookAtLH(CameraPosition, LookAt, UP);
        }

            #endregion
        public class Object
        {
            private Mesh mesh;
            private Material[] materials;
            private Texture[] textures;
            object _Tag;
            public object Tag
            {
                get { return _Tag; }
                set { _Tag = value; }
            }
            private float radius;
            public Vector3 Position, centre, Orientation, LocalAxis, Scaling;
            public Object(string Filename, float scaling)
                : this(Filename, scaling, true)
            {

            }
            public Object(string Filename, float scaling, bool renderable)
            {
                Scaling = new Vector3(scaling, scaling, scaling);
                LoadMesh(Filename, ref mesh, ref materials, ref textures, ref radius, scaling, out centre);
                Position = new Vector3(0, 0, 0);
                if (renderable)
                    CosmicX.Render += new EventHandler(_CosmicX_Render);
                Orientation = new Vector3(0, 0, 0);
                LocalAxis = new Vector3(0, 0, 1);
            }
            public void LoadMesh(string filename, ref Mesh mesh, ref Material[] meshmaterials, ref Texture[] meshtextures, ref float meshradius, float scaling, out Vector3 meshcenter)
            {
                if (!System.IO.File.Exists(filename))
                { throw new Exception("File not found " + filename); }
                ExtendedMaterial[] materialarray;
                mesh = Mesh.FromFile(filename, MeshFlags.Managed, CosmicX.device, out materialarray);

                if ((materialarray != null) && (materialarray.Length > 0))
                {
                    meshmaterials = new Material[materialarray.Length];
                    meshtextures = new Texture[materialarray.Length];

                    for (int i = 0; i < materialarray.Length; i++)
                    {
                        meshmaterials[i] = materialarray[i].Material3D;
                        meshmaterials[i].Ambient = meshmaterials[i].Diffuse;

                        if ((materialarray[i].TextureFilename != null) && (materialarray[i].TextureFilename != string.Empty))
                        {
                            System.IO.FileInfo fi = new System.IO.FileInfo(filename);
                            if (System.IO.File.Exists(fi.DirectoryName + "\\" + materialarray[i].TextureFilename))
                            {
                                meshtextures[i] = TextureLoader.FromFile(CosmicX.device, fi.DirectoryName + "\\" + materialarray[i].TextureFilename);
                            }
                            else System.Diagnostics.Debug.Print("File not found: " + materialarray[i].TextureFilename + " !");
                        }
                    }
                }

                mesh = mesh.Clone(mesh.Options.Value, CustomVertex.PositionNormalTextured.Format, CosmicX.device);
                mesh.ComputeNormals();

                VertexBuffer vertices = mesh.VertexBuffer;
                GraphicsStream stream = vertices.Lock(0, 0, LockFlags.None);
                meshradius = Geometry.ComputeBoundingSphere(stream, mesh.NumberVertices, mesh.VertexFormat, out meshcenter) * scaling;

            }
            public Vector3 LocalToGlobal()
            {
                Vector4 v = Vector3.Transform(LocalAxis, Matrix.RotationY(Orientation.Y) * Matrix.RotationX(Orientation.X) * Matrix.RotationZ(Orientation.Z));
                return new Vector3(v.X, v.Y, v.Z);
            }
            
            public void DrawMesh()
            {
                for (int i = 0; i < materials.Length; i++)
                {
                    CosmicX.device.Material = materials[i];
                    CosmicX.device.SetTexture(0, textures[i]);
                    mesh.DrawSubset(i);
                }
            }
            void _CosmicX_Render(object sender, EventArgs e)
            {
                Render();
            }
            public void Render()
            {
                CosmicX.device.Transform.World = Matrix.Scaling(Scaling.X, Scaling.Y, Scaling.Z) * Matrix.RotationX(Orientation.X) * Matrix.RotationZ(Orientation.Z) * Matrix.RotationY(Orientation.Y) * Matrix.Translation(Position);
                DrawMesh();
            }
            public void Dispose()
            {
                CosmicX.Render -= _CosmicX_Render;
                mesh = null;
                materials = null;
                textures = null;
                System.GC.SuppressFinalize(this);
            }

        }
        
        }
        cosmicX X;
        cosmicX.Object truck;
        public Form1()
        {
            InitializeComponent();
            SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.Opaque, true);
            X = new cosmicX(this);
            truck = new cosmicX.Object("slam\\slam.x", 1);
            X.Stare(truck, 10, 5);
        }
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            X.RenderX();
        }
    }
}

Comments

Popular Posts