Tutorial 6, DirectX using C#


DirectX using C#

Tutorial 6

Camera free look

This tutorial will implement input taking from previous post to move camera using arrow keys and numpad keys (if you are using laptop with no numpad keys, you'll need to reconfigure the function slightly).

Camera class

This class is meant to hold all functions and properties associated with camera and will provide quick reference for camera to developer.

moves the camera by the float value in the looking direction Moves camera by the float value in the specified direction vector Rotates the camera along the vector, by the angle passed (as float) Gets the current looking direction Gets or Sets the position of camera
Hover your mouse over class items to know their details

Controlling camera


public void ControlCamera(float angle, float moveSpeed)
        {
            //form.Text = camerapos.ToString();
            if (keys[Key.Up])
            {
                Camera.Move(moveSpeed);


            } if (keys[Key.Down])
            {
                Camera.Move(-moveSpeed);
            }

            
            if (keys[Key.NumPad6])
            {
                Camera.RotateCamera(UP, angle);
                
            }
            if (keys[Key.NumPad4])
            {
                Camera.RotateCamera(UP, -angle);
            }
            if (keys[Key.NumPad8])
            {
                Vector3 left = LookAt - CameraPosition;
                Vector3 axis = Vector3.Cross(LookAt - CameraPosition, UP);
                Camera.RotateCamera(axis, angle);
                //System.Diagnostics.Debug.Print(axis.ToString());
            }
            if (keys[Key.NumPad2])
            {
                Vector3 left = LookAt - CameraPosition;
                Vector3 axis;
                axis = Vector3.Cross(left, UP);
                Camera.RotateCamera(axis, -angle);


            }
            this.device.Transform.View = Matrix.LookAtLH(CameraPosition, LookAt, UP);
        }

quite self-explaining, requires understanding of 3D co-ordinate geometry and vectors

One-line implementation


protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            X.RenderX();
            X.ControlCamera(0.03f, 0.5f);
        }

Output

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;
using Microsoft.DirectX.DirectInput;
using DI = Microsoft.DirectX.DirectInput;

namespace XBasic
{
    public partial class Form1 : Form
    {
        class cosmicX
        {
            event EventHandler Render;
            #region -FIELDS-
            D3D.Device device;
            DI.Device keyb;
            KeyboardState keys;
            Form form;
            float _AspectRatio, _FieldOfView;
            static cosmicX _CosmicX;
            Vector3 CameraPosition, LookAt;
            Vector3 UP = new Vector3(0, 1, 0);
            camera _Camera = new camera();
#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; }
            }
            public camera Camera
            {
                get { return _Camera; }

            }
#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();
            form.Resize += new EventHandler(form_Resize);
            this.keyb = new DI.Device(SystemGuid.Keyboard);
            this.keyb.SetCooperativeLevel(f, CooperativeLevelFlags.Background | CooperativeLevelFlags.NonExclusive);
            this.keyb.Acquire();

        }

            void form_Resize(object sender, EventArgs e)
            {
                SunLightColor = Color.White;
                AspectRatio = (float)form.Width / (float)form.Height;
                this.device.Transform.Projection = Matrix.PerspectiveFovLH(FieldOfView, AspectRatio, 0.3f, 500f);
            }
        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();
            keys = keyb.GetCurrentKeyboardState();
            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);
        }
        public bool CheckKeyPress(Key k)
        {
            return this.keys[k];
        }
        public void ControlCamera(float angle, float moveSpeed)
        {
            //form.Text = camerapos.ToString();
            if (keys[Key.Up])
            {
                Camera.Move(moveSpeed);


            } if (keys[Key.Down])
            {
                Camera.Move(-moveSpeed);
            }

            
            if (keys[Key.NumPad6])
            {
                Camera.RotateCamera(UP, angle);
                /*Vector4 v = Vector3.Transform(LookAt - CameraPosition, Matrix.RotationY(angle));
                LookAt.X = v.X + CameraPosition.X;
                LookAt.Y = v.Y + CameraPosition.Y;
                LookAt.Z = v.Z + CameraPosition.Z;*/
            }
            if (keys[Key.NumPad4])
            {
                Camera.RotateCamera(UP, -angle);
            }
            if (keys[Key.NumPad8])
            {
                Vector3 left = LookAt - CameraPosition;
                Vector3 axis = Vector3.Cross(LookAt - CameraPosition, UP);
                Camera.RotateCamera(axis, angle);
                //System.Diagnostics.Debug.Print(axis.ToString());
            }
            if (keys[Key.NumPad2])
            {
                Vector3 left = LookAt - CameraPosition;
                Vector3 axis;
                axis = Vector3.Cross(left, UP);
                Camera.RotateCamera(axis, -angle);


            }
            this.device.Transform.View = Matrix.LookAtLH(CameraPosition, LookAt, UP);
        }
            #endregion
        public class camera
        {
            public float X
            {
                get { return CosmicX.CameraPosition.X; }
                set
                {
                    float x = CosmicX.LookAt.X - CosmicX.CameraPosition.X;
                    CosmicX.CameraPosition.X = value;
                    CosmicX.LookAt.X = value + x;

                }
            }
            public float Y
            {
                get { return CosmicX.CameraPosition.Y; }
                set
                {
                    float y = CosmicX.LookAt.Y - CosmicX.CameraPosition.Y;
                    CosmicX.CameraPosition.Y = value;
                    CosmicX.LookAt.Y = value + y;

                }
            }
            public float Z
            {
                get { return CosmicX.CameraPosition.X; }
                set
                {
                    float z = CosmicX.LookAt.Z - CosmicX.CameraPosition.Z;
                    CosmicX.CameraPosition.Z = value;
                    CosmicX.LookAt.Z = value + z;
                }
            }
            public void Move(float distance)
            {
                Vector3 v = CosmicX.LookAt - CosmicX.CameraPosition;
                v.Multiply(distance / v.Length());
                CosmicX.CameraPosition += v;
                CosmicX.LookAt += v;
            }
            public void Move(float distance, Vector3 along)
            {
                along.Multiply(distance / along.Length());
                Vector3 dirn = CosmicX.LookAt - CosmicX.CameraPosition;
                Position += along;
                CosmicX.LookAt = Position + dirn;
            }
            public void RotateCamera(Vector3 axis, float angle)
            {
                Vector4 v = Vector3.Transform(CosmicX.LookAt - CosmicX.CameraPosition, Matrix.RotationAxis(axis, angle));
                CosmicX.LookAt.X = v.X + CosmicX.CameraPosition.X;
                CosmicX.LookAt.Y = v.Y + CosmicX.CameraPosition.Y;
                CosmicX.LookAt.Z = v.Z + CosmicX.CameraPosition.Z;
            }
            public Vector3 Position
            {
                get { return CosmicX.CameraPosition; }
                set { X = value.X; Y = value.Y; Z = value.Z; }
            }
            public Vector3 Direction
            {
                get { return -CosmicX.LookAt + CosmicX.CameraPosition; }

            }
        }
        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();
            //this.Size = new Size(800, 800);
            SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.Opaque, true);
            X = new cosmicX(this);
            truck = new cosmicX.Object("slam\\slam.x", 1);
            X.Stare(truck, 10, 4);
            Resize += new EventHandler(Form1_Resize);
            
        }

        void Form1_Resize(object sender, EventArgs e)
        {
            X.Stare(truck, 10, 4);
        }
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            X.RenderX();
            X.ControlCamera(0.03f, 0.5f);
        }
    }
}

Comments

Post a Comment

Popular Posts