Direct3D基础

最近在公司里实习,有个项目的接合点需要用到三维处理的东西,还是比较麻烦的,虽然之前也学过一点图形学的理论知识,但都是皮毛,研究得也不深入。所以趁现在把一些基本的概念拾起来,开发平台用微软的DirectX框架并结合C#,很多东西都是现学的。下面给出几个基本的概念。

图形卡显卡,计算机和显示器之间的接口。很多图形卡都有自己的处理器,称为GPU图形处理器。GPU是针对图形和图像所需要的计算进行过优化的专用处理器,与CPU并行工作。每个图形卡都有自己的显存,即计算机系统的显卡内存。其实一些桌面版的3D游戏,只是经过处理器进行大量的数学计算,将3D物体转换为具有立体感的2D图形,在计算机显示器屏幕上显示。

计算机通过图形卡控制显示器,图形卡能够控制显示器屏幕每一点的颜色。所采用的方法是,在图形卡的显存中分配一个区域,区域中每一个单元存储的颜色值跟屏幕中每一点的颜色一一对应,即如果程序修改了这个显存区域中一个单元中存储的颜色值,也就修改了和其对应屏幕点的颜色。如果直接修改显存区域中的数据,图像会发生抖动,因为显示器是按照行进行扫描的。为了避免抖动,一般在后备缓存区(back buffer)中修改图像,修改完成后再把后备缓存区中的图像送到屏幕显示区中显示。将3D物体转换为具有立体感的平面图形,实际上是将3D物体投影到XY平面上,Z轴表示3D物体距离观察者的距离。在投影的过程中,前面的物体可能会遮挡后面的物体,也就是说只有在Z轴方向上最靠近观察者的物体才嫩被投影到XY平面上,这里用到一个称为深度缓存区(Z-buffer,depthbuffer,w-buffer)的东西,它的每一个单元记录了每个投影到XY平面的点到观察者的距离。新的3D物体要投影到XY平面,首先要计算该点到观察者的距离,然后和深度缓存区中相应单元的值进行比较,只有小于时,才能进行投影,Direct 3D把这个操作称为深度测试。把3D物体在2D显示器中显示的过程叫渲染

上面的东西都是概念上的,其实从开发者的角度来看,上面所有的东西都是被封装成相应的类、函数、参数等。在Direct 3D中,Device类是所有绘图操作必须使用的类。可以把这个类的对象假想成真实的图形卡。Device类把真实的图形卡从具体的硬件中抽象出来,在类中定义一组通用函数,这些函数直接操作图形卡硬件。通过调用统一标准的Device类可以操作每一种图形卡,这样做的好处就是既保证了应用程序和硬件无关,又能直接控制硬件,加快应用程序的运行速度。下面给出一个Direct3D基本例子,显示蓝色屏幕背景。

安装的.NetFramework为4.0,x86架构,程序配置文件为:

<?xml version="1.0"?>
<configuration>
  <startup useLegacyV2RuntimeActivationPolicy="true">
    <supportedRuntime version="v4.0"/>
  </startup>
</configuration>

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 Direct3D
{
    public partial class Form1 : Form
    {
        private Device device = 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)
        { }

        public void OnResetDevice(object sender, EventArgs e)
        {
            Render();
        }

        public void Render()		//渲染方法,本方法没有任何渲染代码,可认为是渲染方法的框架
        {
            if (device == null) 	//如果未建立设备对象,退出
                return;

            //下边函数将显示区域初始化为蓝色,第1个参数指定要初始化目标窗口包括深度缓冲区
            //第2个参数是我们所要填充的颜色。第3、第4个参数一般为1.0f, 0。
            device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, System.Drawing.Color.Blue, 1.0f, 0);
            device.BeginScene();	//开始渲染
            //渲染代码必须放在device.BeginScene()和device.Present()之间
            device.EndScene();		//渲染结束
            device.Present();		//更新显示区域,把后备缓存的3D图形送到屏幕显示区中显示
        }

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

利用透视图的原理,可以在显示器屏幕上直接绘制具有立体感的平面图形。具体就是预先根据透视原理人工计算出3D物体在计算机显示器屏幕的显示坐标,然后再利用此坐标进行绘制。在Direct 3D中,CustomVertex.TransformedColored结构记录了已经根据透视原理计算后的顶点。

下面绘制一个静止的三角形,过程类似。

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 Triangle
{
    public partial class Form1 : Form
    {
        private Device device = null;
        CustomVertex.TransformedColored[] verts;
        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)
        {
            verts = new CustomVertex.TransformedColored[3];
            verts[0].Position = new Vector4(150.0f, 50.0f, 0.5f, 1.0f);//三角形的第1个顶点坐标
            verts[0].Color = Color.Aqua.ToArgb();				//三角形的第1个顶点颜色
            verts[1].Position = new Vector4(250.0f, 250.0f, 0.5f, 1.0f); //第2个顶点坐标
            verts[1].Color = Color.Brown.ToArgb();
            verts[2].Position = new Vector4(50.0f, 250.0f, 0.5f, 1.0f); //第3个顶点坐标
            verts[2].Color = Color.LightPink.ToArgb();

        }

        public void OnResetDevice(object sender, EventArgs e)
        {
            Render();
        }

        public void Render()		//渲染方法,本方法没有任何渲染代码,可认为是渲染方法的框架
        {
            if (device == null) 	//如果未建立设备对象,退出
                return;
            //下边函数将显示区域初始化为蓝色,第1个参数指定要初始化目标窗口
            //第2个参数是我们所要填充的颜色。第3、第4个参数一般为1.0f, 0。
            device.Clear(ClearFlags.Target | ClearFlags.ZBuffer,
        System.Drawing.Color.Blue, 1.0f, 0);
            device.BeginScene();	//开始渲染
            //渲染代码必须放在device.BeginScene()和device.Present()之间
            device.VertexFormat = CustomVertex.TransformedColored.Format;		 //渲染代码
            device.DrawUserPrimitives(PrimitiveType.TriangleList, 1, verts);
            device.EndScene();		//渲染结束
            device.Present();		//更新显示区域,把后备缓存的3D图形送到图形卡的显存中显示

        }

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

DrawUserPrimitives方法的第一个参数primitiveType可以取不同的值,可以绘制点、线段和三角形。

如果顶点的数组放到图形卡的显存中,将能极大地增加绘制图形的速度。可以用VertexBuffer类为数组申请存储空间,指定顶点数组的存放位置。如果3D程序运行在窗口模式,可能有多个运行程序共同占有计算机的图形卡和显存。窗体改变大小、窗体最小化后再最大化、全屏模式和窗体模式之间的切换等情况发生时,Device对象被重新设置,所以放到图形卡显存中顶点数组的数据可能会丢失,必须恢复VertexBuffer缓存区中的数据。比如说,最小化后程序使用的显存将被其他程序占用,所以在最大化后必须重建VertexBuffer类对象中顶点数组的数据。在需要重建VertexBuffer类对象时,系统产生CreateVertexBuffer事件,通知程序在事件处理函数中重建VertexBuffer类对象中的数据。

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 VertexBufferTest
{
    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.TransformedColored),
            3, dev, 0, CustomVertex.TransformedColored.Format, Pool.Default);
            //事件的预订,指定OnCreateVertexBuffer函数是vertexBuffer.Created事件函数
            vertexBuffer.Created += new System.EventHandler(this.OnCreateVertexBuffer);
            this.OnCreateVertexBuffer(vertexBuffer, null); //创建顶点数组

        }

        public void OnResetDevice(object sender, EventArgs e)
        { }

        public void Render()		//渲染方法,本方法没有任何渲染代码,可认为是渲染方法的框架
        {
            if (device == null) 	//如果未建立设备对象,退出
                return;
            if (pause)
                return;
            device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, System.Drawing.Color.Blue, 1.0f, 0);
            device.BeginScene();	//开始渲染
            device.SetStreamSource(0, vertexBuffer, 0); //使用vertexBuffer中定义的顶点
            device.VertexFormat = CustomVertex.TransformedColored.Format;	//顶点格式
            device.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);
            device.EndScene();		//渲染结束
            device.Present();		//更新显示区域,把后备缓存的D图形送到图形卡的显存中显示

        }

        public void OnCreateVertexBuffer(object sender, EventArgs e)
        {
            CustomVertex.TransformedColored[] verts =
                                (CustomVertex.TransformedColored[])vertexBuffer.Lock(0, 0);
            verts[0].X = 150;
            verts[0].Y = 50; 					//顶点0位置
            verts[0].Z = 0.5f;
            verts[0].Rhw = 1;
            verts[0].Color = System.Drawing.Color.Aqua.ToArgb();		//顶点0颜色
            verts[1].X = 250;
            verts[1].Y = 250;
            verts[1].Z = 0.5f;
            verts[1].Rhw = 1;
            verts[1].Color = System.Drawing.Color.Brown.ToArgb();
            verts[2].X = 50;
            verts[2].Y = 250;
            verts[2].Z = 0.5f;
            verts[2].Rhw = 1;
            verts[2].Color = System.Drawing.Color.LightPink.ToArgb();
            vertexBuffer.Unlock();
        }

        private void Form1_Load(object sender, EventArgs e)//重写Load事件
        {
            InitializeGraphics();
            Show();
            Render();
        }

        private void Form1_Paint(object sender, PaintEventArgs e) //重写Paint事件
        {
            this.Render();
        }

        private void Form1_Resize(object sender, EventArgs e) //重写Resize事件
        {
            pause = ((this.WindowState == FormWindowState.Minimized) || !this.Visible);
        }
    }
}

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.TransformedColored), 18,
            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)
        { }

        public void Render()		//渲染方法,本方法没有任何渲染代码,可认为是渲染方法的框架
        {
            if (device == null) 	//如果未建立设备对象,退出
                return;
            if (pause)
                return;
            device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.LightBlue, 1.0f, 0);
            device.BeginScene();	//开始渲染
            device.SetStreamSource(0, vertexBuffer, 0);
            device.VertexFormat = CustomVertex.TransformedColored.Format;
            device.DrawPrimitives(PrimitiveType.TriangleList, 0, 6);
            device.EndScene();		//渲染结束
            device.Present();		//更新显示区域,把后备缓存的D图形送到图形卡的显存中显示


        }
        public void OnCreateVertexBuffer(object sender, EventArgs e)
        {
            CustomVertex.TransformedColored[] verts =
                        (CustomVertex.TransformedColored[])vertexBuffer.Lock(0, 0);
            verts[0].Position = new Vector4(100.0f, 50.0f, 0.5f, 1.0f);
            verts[0].Color = Color.Red.ToArgb();
            verts[1].Position = new Vector4(200.0f, 50.0f, 0.5f, 1.0f);
            verts[1].Color = Color.Red.ToArgb();
            verts[2].Position = new Vector4(50.0f, 100.0f, 0.5f, 1.0f);
            verts[2].Color = Color.Red.ToArgb();
            verts[3].Position = new Vector4(50.0f, 100.0f, 0.5f, 1.0f);
            verts[3].Color = Color.Red.ToArgb();
            verts[4].Position = new Vector4(200.0f, 50.0f, 0.5f, 1.0f);
            verts[4].Color = Color.Red.ToArgb();
            verts[5].Position = new Vector4(150.0f, 100.0f, 0.5f, 1.0f);
            verts[5].Color = Color.Red.ToArgb();
            verts[6].Position = new Vector4(50.0f, 100.0f, 0.5f, 1.0f);
            verts[6].Color = Color.Green.ToArgb();
            verts[7].Position = new Vector4(150.0f, 100.0f, 0.5f, 1.0f);
            verts[7].Color = Color.Green.ToArgb();
            verts[8].Position = new Vector4(50.0f, 200.0f, 0.5f, 1.0f);
            verts[8].Color = Color.Green.ToArgb();
            verts[9].Position = new Vector4(50.0f, 200.0f, 0.5f, 1.0f);
            verts[9].Color = Color.Green.ToArgb();
            verts[10].Position = new Vector4(150.0f, 100.0f, 0.5f, 1.0f);
            verts[10].Color = Color.Green.ToArgb();
            verts[11].Position = new Vector4(150.0f, 200.0f, 0.5f, 1.0f);
            verts[11].Color = Color.Green.ToArgb();
            verts[12].Position = new Vector4(150.0f, 100.0f, 0.5f, 1.0f);
            verts[12].Color = Color.Yellow.ToArgb();
            verts[13].Position = new Vector4(200.0f, 50.0f, 0.5f, 1.0f);
            verts[13].Color = Color.Yellow.ToArgb();
            verts[14].Position = new Vector4(150.0f, 200.0f, 0.5f, 1.0f);
            verts[14].Color = Color.Yellow.ToArgb();
            verts[15].Position = new Vector4(150.0f, 200.0f, 0.5f, 1.0f);
            verts[15].Color = Color.Yellow.ToArgb();
            verts[16].Position = new Vector4(200.0f, 50.0f, 0.5f, 1.0f);
            verts[16].Color = Color.Yellow.ToArgb();
            verts[17].Position = new Vector4(200.0f, 150.0f, 0.5f, 1.0f);
            verts[17].Color = Color.Yellow.ToArgb();
            vertexBuffer.Unlock();

        }

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

        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);
        }
    }
}


任何一个平面都可以由若干个三角形组成,用三个顶点定义三角形平面,Direct 3D在渲染着两个三角形时,左手笛卡尔坐标系默认情况下按顺时针方向绘制三角形,即只显示按顺时针绘制的三角形,这就是背面剔除。Device属性的RenderState.CullMode控制背面剔除方式。


  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值