DirectX 3D圖形

前面的一篇文章Direct 3D基礎介紹了一些基本概念,敘述瞭如何在顯示器上直接繪製具有立體感的2D圖形。上面的方法是不現實的,因爲預先根據透視原理人工計算出3D物體在顯示屏幕上顯示的座標然後再繪製的這種方式如果涉及從不同角度觀察的3D物體的話,需要計算的次數會很多。Direct 3D實現3D所採用的方法是首先設計一個仿真真實3D物體的立體模型,然後由計算機根據透視原理計算出每一個角度模型顯示在計算機顯示器屏幕上的座標和每個面的顏色,然後顯示出來。

把3D場景中的所有3D物體在2D顯示器上顯示出來的過程叫做渲染。這一過程與使用照相機照相類似。最終將3D物體的3D座標轉化爲2D顯示器平面座標及顏色在平面顯示器顯示出來。渲染過程將對3D場景中的所有3D物體進行世界、觀察和投影座標變換,最終將3D物體的3D座標變換爲2D顯示器平面座標及顏色在平面顯示器顯示出來。三個座標變換中的每個變換都可以用一個Matrix結構中的4行4列仿射矩陣來表示,記錄3D場景中的所有3D物體的平移、縮放、旋轉等操作。渲染前需要進行建模,即製作被渲染的3D物體模型,用來搭建3D場景。一個3D物體一般包括若干曲面,任意曲面都可以由若干三角形平面組成,一個三角形平面由三角形的三個頂點確定。所以3D物體模型就是用頂點定義的3D物體。在建模階段需要定義3D物體所有頂點的位置以及屬性。建模可以在程序中完成,也可以用專用軟件比如說3D Max完成後再導進去。每個模型都有自己的座標系統,稱爲建模座標系統,座標系統所代表空間稱爲建模空間。建模必須首先定義3D模型以及建模座標所表示的頂點座標,這些頂點經過三個變換,最終轉換爲平面顯示器座標,同時,還可能定義3D模型的其他元素,比如說顏色、面的法線等。

世界變換:使用建模創建的3D模型搭建3D場景。觀察變換:也稱爲取景變換,從場景的世界空間中取得感興趣的部分場景。投影變換:將攝像機空間中的3D模型轉換爲能夠在顯示器屏幕上顯示的具有立體感的平面圖形。

要在屏幕中顯示一個三角形,三角形的三個頂點必須要經過三個變換——世界、觀察和投影變換。當3D程序的運行狀態發生變化時,比如說窗口狀態和全屏狀態切換,Device類對象的參數必然要發生變化,這些參數必須被重新設置。一般情況下,可以在OnResetDevice和Render方法中修改Device類對象的參數。在程序中不改變的Device類對象的參數一般在OnResetDevice方法中修改;在程序中需要改變的Device類對象的參數一般要在Render方法中修改,這樣做可以加快渲染的速度。爲了使三角形旋轉,每次渲染三角形之前,必須根據三角形在世界空間中的新位置爲其指定新的世界變換矩陣。

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;

namespace 顯示三角形
{
    public partial class Form1 : Form
    {
        private Device device = null;
        bool pause = false;
        VertexBuffer vertexBuffer = null;
        float Angle = 0, ViewZ = -6.0f;
        public Form1()
        {
            InitializeComponent();
        }

        public bool InitializeGraphics()
        {
            try
            {
                PresentParameters presentParams = new PresentParameters();
                presentParams.Windowed = true;				//不是全屏顯示,在一個窗口顯示
                presentParams.SwapEffect = SwapEffect.Discard;		 //後備緩存交換的方式
                presentParams.EnableAutoDepthStencil = true;			 //允許使用自動深度模板測試
                //深度緩衝區單元爲16位二進制數
                presentParams.AutoDepthStencilFormat = DepthFormat.D16;
                device = new Device(0, DeviceType.Hardware, this, 	 //建立設備類對象
          CreateFlags.SoftwareVertexProcessing, presentParams);
                //設置設備重置事件(device.DeviceReset)事件函數爲this.OnResetDevice
                device.DeviceReset += new System.EventHandler(this.OnResetDevice);
                this.OnCreateDevice(device, null);//自定義方法,初始化Device的工作放到這個方法中
                this.OnResetDevice(device, null);//調用設備重置事件(device.DeviceReset)事件函數
            }		//設備重置事件函數要設置Device參數,初始函數中必須調用該函數
            catch (DirectXException)
            {
                return false;
            }
            return true;
        }

        public void OnCreateDevice(object sender, EventArgs e)
        {
            Device dev = (Device)sender;
            vertexBuffer = new VertexBuffer(typeof(CustomVertex.PositionColored), 3,
            dev, 0, CustomVertex.TransformedColored.Format, Pool.Default);
            vertexBuffer.Created += new System.EventHandler(this.OnCreateVertexBuffer);
            this.OnCreateVertexBuffer(vertexBuffer, null);

        }

        public void OnResetDevice(object sender, EventArgs e)
        {
            Device dev = (Device)sender;
            dev.RenderState.CullMode = Cull.None;		//取消背面剔除
            dev.RenderState.Lighting = false;			//取消燈光
            SetupMatrices();		//在程序運行期間,Device的3個變換不改變,因此放在此處

        }

        public void Render()		//渲染方法,本方法沒有任何渲染代碼,可認爲是渲染方法的框架
        {
            if (device == null) //如果未建立設備對象,退出
                return;
            if (pause)
                return;
            device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.Blue, 1.0f, 0);
            device.BeginScene();	//開始渲染		
            SetupMatrices();		//在程序運行期間,Device的2個變換參數要改變,因此放在此處
            device.SetStreamSource(0, vertexBuffer, 0);
            device.VertexFormat = CustomVertex.PositionColored.Format;
            device.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);
            device.EndScene();		//渲染結束
            device.Present();		//更新顯示區域,把後備緩存的圖形送到圖形卡的顯存中顯示


        }

        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            this.Render();
        }

        private void Form1_Resize(object sender, EventArgs e)
        {
            pause = ((this.WindowState == FormWindowState.Minimized) || !this.Visible);
        }

        public void OnCreateVertexBuffer(object sender, EventArgs e)
        {
            CustomVertex.PositionColored[] verts =			   //建模
                        (CustomVertex.PositionColored[])vertexBuffer.Lock(0, 0);
            verts[0].Position = new Vector3(-1.0f, -1.0f, 0.0f);   //頂點0位置,注意爲Vector3
            verts[0].Color = System.Drawing.Color.Aqua.ToArgb();   //頂點0顏色
            verts[1].Position = new Vector3(1.0f, -1.0f, 0.0f);	   //頂點1位置
            verts[1].Color = System.Drawing.Color.Brown.ToArgb();
            verts[2].Position = new Vector3(0.0f, 1.0f, 0.0f);	   //頂點2位置
            verts[2].Color = System.Drawing.Color.LightPink.ToArgb();
            vertexBuffer.Unlock();
        }

        private void SetupMatrices()		//修改Device的3個變換
        {
            int iTime = Environment.TickCount % 1000;
            Angle = iTime * (2.0f * (float)Math.PI) / 1000.0f;
            device.Transform.World = Matrix.RotationY(Angle);
            device.Transform.View = Matrix.LookAtLH(new Vector3(0.0f, 3.0f, ViewZ),
                            new Vector3(0.0f, 0.0f, 0.0f), new Vector3(0.0f, 1.0f, 0.0f));
            device.Transform.Projection = Matrix.PerspectiveFovLH((float)Math.PI / 4,
                            1.0f, 1.0f, 100.0f);
        }

        private void Form1_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.KeyCode)				//e.KeyCode是鍵盤每個鍵的編號
            {
                case Keys.Left:			//Keys.Left是左箭頭鍵編號,三角形沿Y軸左轉
                    Angle += 0.1F;
                    break;
                case Keys.Right:			//三角形沿Y軸右轉
                    Angle -= 0.1F;
                    break;
                case Keys.Down:			//三角形離觀察者越來越遠
                    ViewZ += 0.1F;
                    break;
                case Keys.Up:				//三角形離觀察者越來越近
                    ViewZ -= 0.1F;
                    break;
            }

        }

        private void Form1_Load(object sender, EventArgs e)
        {
            InitializeGraphics();
            Show();
            Render();
        }
    }
}

顯示立方體,首先創建立方體模型,設置8個頂點的座標,首先創建立方體的一個面,其他的面用世界變換將第一個面變換到立方體的相應位置,最終實現立方體。

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;

namespace 顯示立方體
{
    public partial class Form1 : Form
    {
        private Device device = null;
        bool pause = false;
        VertexBuffer vertexBuffer = null;
        float Angle = 0, ViewZ = -6.0f;

        public Form1()
        {
            InitializeComponent();
        }

        public bool InitializeGraphics()
        {
            try
            {
                PresentParameters presentParams = new PresentParameters();
                presentParams.Windowed = true;				//不是全屏顯示,在一個窗口顯示
                presentParams.SwapEffect = SwapEffect.Discard;		 //後備緩存交換的方式
                presentParams.EnableAutoDepthStencil = true;			 //允許使用自動深度模板測試
                //深度緩衝區單元爲16位二進制數
                presentParams.AutoDepthStencilFormat = DepthFormat.D16;
                device = new Device(0, DeviceType.Hardware, this, 	 //建立設備類對象
          CreateFlags.SoftwareVertexProcessing, presentParams);
                //設置設備重置事件(device.DeviceReset)事件函數爲this.OnResetDevice
                device.DeviceReset += new System.EventHandler(this.OnResetDevice);
                this.OnCreateDevice(device, null);//自定義方法,初始化Device的工作放到這個方法中
                this.OnResetDevice(device, null);//調用設備重置事件(device.DeviceReset)事件函數
            }		//設備重置事件函數要設置Device參數,初始函數中必須調用該函數
            catch (DirectXException)
            {
                return false;
            }
            return true;
        }

        public void OnCreateDevice(object sender, EventArgs e)
        {
            Device dev = (Device)sender;		//陰影部分是所作修改,正方形有6個頂點
            vertexBuffer = new VertexBuffer(typeof(CustomVertex.PositionColored), 6,
            dev, 0, CustomVertex.TransformedColored.Format, Pool.Default);
            vertexBuffer.Created += new System.EventHandler(this.OnCreateVertexBuffer);
            this.OnCreateVertexBuffer(vertexBuffer, null);

        }

        public void OnResetDevice(object sender, EventArgs e)
        {
            Device dev = (Device)sender;
            //背面剔除方式爲只顯示順時針三角形,因爲正方體應該只看到外表面
            dev.RenderState.CullMode = Cull.CounterClockwise;
            dev.RenderState.Lighting = false;				//取消燈光

        }

        public void Render()		//渲染方法,本方法沒有任何渲染代碼,可認爲是渲染方法的框架
        {
            if (device == null) 						//如果未建立設備對象,退出
                return;
            if (pause)
                return;
            device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.LightBlue, 1.0f, 0);
            device.BeginScene();						//開始渲染
            SetupMatrices();
            device.SetStreamSource(0, vertexBuffer, 0);
            device.VertexFormat = CustomVertex.PositionColored.Format;
            device.Transform.World = Matrix.Translation(0, 0, -1);//沿Z軸向觀察者方向移動1個單位
            device.DrawPrimitives(PrimitiveType.TriangleList, 0, 2);    //繪製正前面
            //旋轉180度是爲了從外側看,按順時針方向繪製三角形,因背面剔除打開,內側不被看到
            device.Transform.World = Matrix.RotationY((float)Math.PI) * Matrix.Translation(0, 0, 1);
            device.DrawPrimitives(PrimitiveType.TriangleList, 0, 2);    //繪製正後面
            device.Transform.World =
            Matrix.RotationY(-(float)Math.PI / 2) * Matrix.Translation(1, 0, 0);
            device.DrawPrimitives(PrimitiveType.TriangleList, 0, 2);		//繪製右側面
            device.Transform.World =
        Matrix.RotationY((float)Math.PI / 2) * Matrix.Translation(-1, 0, 0);
            device.DrawPrimitives(PrimitiveType.TriangleList, 0, 2);		//繪製左側面
            device.Transform.World =
        Matrix.RotationX((float)Math.PI / 2) * Matrix.Translation(0, 1, 0);
            device.DrawPrimitives(PrimitiveType.TriangleList, 0, 2);		//繪製下面
            device.Transform.World =
        Matrix.RotationX(-(float)Math.PI / 2) * Matrix.Translation(0, -1, 0);
            device.DrawPrimitives(PrimitiveType.TriangleList, 0, 2);   	//繪製上面
            device.EndScene();										//渲染結束
            device.Present();	//更新顯示區域,把後備緩存的D圖形送到圖形卡的顯存中顯示
        }

        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            this.Render();
        }

        private void Form1_Resize(object sender, EventArgs e)
        {
            pause = ((this.WindowState == FormWindowState.Minimized) || !this.Visible);
        }

        public void OnCreateVertexBuffer(object sender, EventArgs e)
        {
            CustomVertex.PositionColored[] verts =
                    (CustomVertex.PositionColored[])vertexBuffer.Lock(0, 0);
            verts[0].Position = new Vector3(-1.0f, -1.0f, 0.0f);  //頂點0位置,注意爲Vector3
            verts[0].Color = System.Drawing.Color.Aqua.ToArgb();    	  //頂點0顏色
            verts[1].Position = new Vector3(1.0f, 1.0f, 0.0f);	  	  //頂點1位置
            verts[1].Color = System.Drawing.Color.Brown.ToArgb();
            verts[2].Position = new Vector3(1.0f, -1.0f, 0.0f);	      //頂點2位置
            verts[2].Color = System.Drawing.Color.LightPink.ToArgb();
            verts[3].Position = new Vector3(-1.0f, -1.0f, 0.0f);	  //頂點3位置
            verts[3].Color = System.Drawing.Color.Aqua.ToArgb();    	  //頂點3顏色
            verts[4].Position = new Vector3(-1.0f, 1.0f, 0.0f);	  	  //頂點4位置
            verts[4].Color = System.Drawing.Color.Red.ToArgb();
            verts[5].Position = new Vector3(1.0f, 1.0f, 0.0f);	      //頂點5位置
            verts[5].Color = System.Drawing.Color.Brown.ToArgb();
            vertexBuffer.Unlock();

        }

        private void SetupMatrices()		//修改Device的3個變換
        {
            device.Transform.World = Matrix.RotationY(Angle);	//世界變換矩陣,沿Y軸旋轉
            device.Transform.View = Matrix.LookAtLH(new Vector3(0.0f, 3.0f, ViewZ),//觀察變換矩陣
                        new Vector3(0.0f, 0.0f, 0.0f), new Vector3(0.0f, 1.0f, 0.0f));
            device.Transform.Projection = Matrix.PerspectiveFovLH((float)Math.PI / 4,
                        1.0f, 1.0f, 100.0f);		//投影變換語句仍可以放到OnResetDevice方法中
        }

        private void Form1_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.KeyCode)				//e.KeyCode是鍵盤每個鍵的編號
            {
                case Keys.Left:			//Keys.Left是左箭頭鍵編號,三角形沿Y軸左轉
                    Angle += 0.1F;
                    break;
                case Keys.Right:			//三角形沿Y軸右轉
                    Angle -= 0.1F;
                    break;
                case Keys.Down:			//三角形離觀察者越來越遠
                    ViewZ += 0.1F;
                    break;
                case Keys.Up:				//三角形離觀察者越來越近
                    ViewZ -= 0.1F;
                    break;
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            InitializeGraphics();
            this.Show();
            Render();
        }
    }
}


也可以使用頂點索引來繪製立方體,可以極大地簡化程序設計。

首先定義八個頂點,由於每個面要用兩個三角形進行渲染,所以應該用12個三角形進行渲染立方體,在渲染每個面的正方形時,應該保證從每個面的外側看,渲染這個面的兩個三角形應該是順時針方向。比如說,立方體前面的正方形,A、B、C、D四個點,渲染的順序是ABC和CBD。


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;

namespace 頂點索引
{
    public partial class Form1 : Form
    {
        private Device device = null;
        bool pause = false;
        VertexBuffer vertexBuffer = null;
        float Angle = 0, ViewZ = -6.0f;
        IndexBuffer indexBuffer = null;

        public Form1()
        {
            InitializeComponent();
        }

        public bool InitializeGraphics()
        {
            try
            {
                PresentParameters presentParams = new PresentParameters();
                presentParams.Windowed = true;				//不是全屏顯示,在一個窗口顯示
                presentParams.SwapEffect = SwapEffect.Discard;		 //後備緩存交換的方式
                presentParams.EnableAutoDepthStencil = true;			 //允許使用自動深度模板測試
                //深度緩衝區單元爲16位二進制數
                presentParams.AutoDepthStencilFormat = DepthFormat.D16;
                device = new Device(0, DeviceType.Hardware, this, 	 //建立設備類對象
          CreateFlags.SoftwareVertexProcessing, presentParams);
                //設置設備重置事件(device.DeviceReset)事件函數爲this.OnResetDevice
                device.DeviceReset += new System.EventHandler(this.OnResetDevice);
                this.OnCreateDevice(device, null);//自定義方法,初始化Device的工作放到這個方法中
                this.OnResetDevice(device, null);//調用設備重置事件(device.DeviceReset)事件函數
            }		//設備重置事件函數要設置Device參數,初始函數中必須調用該函數
            catch (DirectXException)
            {
                return false;
            }
            return true;
        }

        public void OnCreateDevice(object sender, EventArgs e)
        {
            Device dev = (Device)sender;		//陰影部分是所作修改,正方體有8個頂點
            vertexBuffer = new VertexBuffer(typeof(CustomVertex.PositionColored), 8,
            dev, 0, CustomVertex.TransformedColored.Format, Pool.Default);
            indexBuffer = new IndexBuffer(typeof(int), 36, dev, 0, Pool.Default);  //頂點索引
            vertexBuffer.Created += new System.EventHandler(this.OnCreateVertexBuffer);
            indexBuffer.Created += new EventHandler(indexBuffer_Created);
            this.OnCreateVertexBuffer(vertexBuffer, null);
            this.indexBuffer_Created(indexBuffer, null);


        }

        public void OnResetDevice(object sender, EventArgs e)
        {
            Device dev = (Device)sender;
            //背面剔除方式爲只顯示順時針三角形,因爲正方體應該只看到外表面
            dev.RenderState.CullMode = Cull.CounterClockwise;
            dev.RenderState.Lighting = false;				//取消燈光

        }

        public void Render()		//渲染方法,本方法沒有任何渲染代碼,可認爲是渲染方法的框架
        {
            if (device == null) 			//如果未建立設備對象,退出
                return;
            if (pause)
                return;
            device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.Blue, 1.0f, 0);
            device.BeginScene();			//開始渲染
            SetupMatrices();
            device.SetStreamSource(0, vertexBuffer, 0);
            device.VertexFormat = CustomVertex.PositionColored.Format;
            device.Indices = indexBuffer;
            device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, 8, 0, 12);
            device.EndScene();				//渲染結束
            device.Present();//更新顯示區域,把後備緩存的D圖形送到圖形卡的顯存中顯示


        }

        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            this.Render();
        }

        private void Form1_Resize(object sender, EventArgs e)
        {
            pause = ((this.WindowState == FormWindowState.Minimized) || !this.Visible);
        }

        public void OnCreateVertexBuffer(object sender, EventArgs e)
        {
            CustomVertex.PositionColored[] verts =
(CustomVertex.PositionColored[])vertexBuffer.Lock(0, 0);
            verts[0].Position = new Vector3(-1.0f, 1.0f, 1.0f);	 //頂點0位置,注意爲Vector3
            verts[0].Color = System.Drawing.Color.Aqua.ToArgb();    	  	//頂點0顏色
            verts[1].Position = new Vector3(1.0f, 1.0f, 1.0f);	  	  		//頂點1位置
            verts[1].Color = System.Drawing.Color.Brown.ToArgb();
            verts[2].Position = new Vector3(-1.0f, -1.0f, 1.0f);	      	//頂點2位置
            verts[2].Color = System.Drawing.Color.LightPink.ToArgb();
            verts[3].Position = new Vector3(1.0f, -1.0f, 1.0f);	  		//頂點3位置
            verts[3].Color = System.Drawing.Color.Red.ToArgb();    	  		//頂點3顏色
            verts[4].Position = new Vector3(-1.0f, 1.0f, -1.0f);	  	  	//頂點4位置
            verts[4].Color = System.Drawing.Color.Green.ToArgb();
            verts[5].Position = new Vector3(1.0f, 1.0f, -1.0f);	      	//頂點5位置
            verts[5].Color = System.Drawing.Color.Black.ToArgb();
            verts[6].Position = new Vector3(-1.0f, -1.0f, -1.0f);	  	  	//頂點6位置
            verts[6].Color = System.Drawing.Color.LightPink.ToArgb();
            verts[7].Position = new Vector3(1.0f, -1.0f, -1.0f);	      	//頂點7位置
            verts[7].Color = System.Drawing.Color.Red.ToArgb();
            vertexBuffer.Unlock();
        }

        private void SetupMatrices()		//修改Device的3個變換
        {
            device.Transform.World = Matrix.RotationY(0);	//世界變換
            Vector3 v1 = new Vector3(0.0f, 0.0f, -5.0f);		//下句使v1點分別沿Y軸和X軸旋轉
            v1.TransformCoordinate(Matrix.RotationYawPitchRoll(Angle, ViewZ, 0));
            device.Transform.View = Matrix.LookAtLH(v1, new Vector3(0.0f, 0.0f, 0.0f),
        new Vector3(0.0f, 1.0f, 0.0f));	//觀察變換
            device.Transform.Projection = 				//透視變換
            Matrix.PerspectiveFovLH((float)Math.PI / 4, 1.0f, 1.0f, 100.0f);


        }

        private void Form1_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.KeyCode)				//e.KeyCode是鍵盤每個鍵的編號
            {
                case Keys.Left:			//Keys.Left是左箭頭鍵編號,三角形沿Y軸左轉
                    Angle += 0.1F;
                    break;
                case Keys.Right:			//三角形沿Y軸右轉
                    Angle -= 0.1F;
                    break;
                case Keys.Down:			//三角形離觀察者越來越遠
                    ViewZ += 0.1F;
                    break;
                case Keys.Up:				//三角形離觀察者越來越近
                    ViewZ -= 0.1F;
                    break;
            }

        }

        void indexBuffer_Created(object sender, EventArgs e)
        {    //下面數組每3個數表示一個三角形的索引,每2個三角形繪製1個面,
            int[] index =		//按順序分別繪製前面、右面、上面、左面、後面和下面
            { 4, 5, 6, 5, 7, 6, 5, 1, 7, 7, 1, 3, 4, 0, 1, 4, 1, 5, 2, 0, 4, 2, 4, 6, 3, 1, 0, 3, 0, 2, 2, 6, 7, 2, 7, 3 };
            int[] indexV = (int[])indexBuffer.Lock(0, 0);
            for (int i = 0; i < 36; i++)
            {
                indexV[i] = index[i];
            }
            indexBuffer.Unlock();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            InitializeGraphics();
            this.Show();
            Render();
        }
    }
}


任意複雜的曲面都可以由若干三角形定義的平面組成。創建一個空心圓柱體,可以考慮這樣分解,將上下兩個圓形底面的周長進行n等分,上下相對應的等分點用線連接,將空心圓柱體外表面劃分爲n個小矩形,每個小矩形由兩個三角形平面組成。其實,可以利用建模工具比如說3D Max,創建複雜的立體模型,然後轉換爲Direct 3D能夠識別的.x文件,並將其顯示在顯示器屏幕上。假設空心圓柱體的兩個圓形底面和建模座標系的XZ平面平行,兩個圓形底面的圓心連線和建模座標的Y軸重合,圓心連線的中點在建模座標原點,兩個圓形底面的Y座標分別爲1和-1。空心圓柱體的柱表面可以近似認爲是由若干正方形組成,將兩個圓形底面的圓心角平分爲50份,那麼就可以用50個正方形來近似這個立體空心圓柱體。

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;

namespace 旋轉空心園柱
{
    public partial class Form1 : Form
    {
        private Device device = null;
        bool pause = false;
        VertexBuffer vertexBuffer = null;
        public Form1()
        {
            InitializeComponent();
        }

        public bool InitializeGraphics()
        {
            try
            {
                PresentParameters presentParams = new PresentParameters();
                presentParams.Windowed = true;				//不是全屏顯示,在一個窗口顯示
                presentParams.SwapEffect = SwapEffect.Discard;		 //後備緩存交換的方式
                presentParams.EnableAutoDepthStencil = true;			 //允許使用自動深度模板測試
                //深度緩衝區單元爲16位二進制數
                presentParams.AutoDepthStencilFormat = DepthFormat.D16;
                device = new Device(0, DeviceType.Hardware, this, 	 //建立設備類對象
          CreateFlags.SoftwareVertexProcessing, presentParams);
                //設置設備重置事件(device.DeviceReset)事件函數爲this.OnResetDevice
                device.DeviceReset += new System.EventHandler(this.OnResetDevice);
                this.OnCreateDevice(device, null);//自定義方法,初始化Device的工作放到這個方法中
                this.OnResetDevice(device, null);//調用設備重置事件(device.DeviceReset)事件函數
            }		//設備重置事件函數要設置Device參數,初始函數中必須調用該函數
            catch (DirectXException)
            {
                return false;
            }
            return true;
        }

        public void OnCreateDevice(object sender, EventArgs e)
        {
            Device dev = (Device)sender;
            vertexBuffer = new VertexBuffer(typeof(CustomVertex.PositionColored), 100, dev,
            Usage.WriteOnly, CustomVertex.TransformedColored.Format, Pool.Default);
            vertexBuffer.Created += new System.EventHandler(this.OnCreateVertexBuffer);
            this.OnCreateVertexBuffer(vertexBuffer, null);

        }

        public void OnResetDevice(object sender, EventArgs e)
        {
            Device dev = (Device)sender;
            dev.RenderState.CullMode = Cull.None;		//取消背面剔除
            dev.RenderState.Lighting = false;			//取消燈光

        }

        public void Render()		//渲染方法,本方法沒有任何渲染代碼,可認爲是渲染方法的框架
        {
            if (device == null) //如果未建立設備對象,退出
                return;
            if (pause)
                return;
            device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.WhiteSmoke, 1.0f, 0);
            device.BeginScene();//開始渲染
            SetupMatrices();			//
            device.SetStreamSource(0, vertexBuffer, 0);
            device.VertexFormat = CustomVertex.PositionColored.Format;
            device.DrawPrimitives(PrimitiveType.TriangleStrip, 0, (4 * 25) - 2);
            device.EndScene();//渲染結束
            device.Present();//更新顯示區域,把後備緩存的D圖形送到圖形卡的顯存中顯示

        }

        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            this.Render();
        }

        private void Form1_Resize(object sender, EventArgs e)
        {
            pause = ((this.WindowState == FormWindowState.Minimized) || !this.Visible);
        }

        public void OnCreateVertexBuffer(object sender, EventArgs e)
        {
            CustomVertex.PositionColored[] verts =
            (CustomVertex.PositionColored[])vertexBuffer.Lock(0, 0);
            for (int i = 0; i < 50; i++)
            {
                float theta = (float)(2 * Math.PI * i) / 49;
                verts[2 * i].Position = new Vector3((float)Math.Sin(theta), -1, (float)Math.Cos(theta));
                verts[2 * i].Color = System.Drawing.Color.LightPink.ToArgb();
                verts[2 * i + 1].Position = new Vector3((float)Math.Sin(theta), 1, (float)Math.Cos(theta));
                verts[2 * i + 1].Color = System.Drawing.Color.LightPink.ToArgb();
            }
            vertexBuffer.Unlock();
        }

        private void SetupMatrices()
        {
            device.Transform.World = Matrix.RotationAxis(new Vector3((float)Math.Cos(Environment.TickCount / 250.0f), 1, (float)Math.Sin(Environment.TickCount / 250.0f)), Environment.TickCount / 3000.0f);
            device.Transform.View = Matrix.LookAtLH(new Vector3(0.0f, 3.0f, -5.0f), new Vector3(0.0f, 0.0f, 0.0f), new Vector3(0.0f, 1.0f, 0.0f));
            device.Transform.Projection = Matrix.PerspectiveFovLH((float)Math.PI / 4, 1.0f, 1.0f, 100.0f);
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            InitializeGraphics();
            Show();
            Render();
        }

    }
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章