Visual C# 的DirectX开发系列二了解摄像机

这里借助部分网上的文字和图片说明,让大家更清楚的了解DirectX中的摄像机。(部分内容源于肖泽云老师书中内容,最终目的是让大家更清楚了解C#中的DirectX开发)

在使用摄像机前先来了解三个概念:世界空间(world space)、摄像机空间(cameraspace)和模型空间(model space)。世界空间(world space)可以认为是客观世界空间,所有对象都位于这个世界空间中。摄像机空间(camera space)用于展示显示区域,类似于人的眼睛。模型空间(model space)为模型自身的空间坐标系,如导入某个模型之前在建模时就具有的空间。

下面再介绍三个概念:View Transformation、World Transformation 和ProjectionTransformation。View Transformation(视图变换)是表示观察者位于世界空间,也称摄像机变换,把顶点转换成摄像机空间中的点。World Transformation(世界变换)是用于从模型空间转换坐标到世界坐标。Projection Transformation(投影变换)可以认为是用来控制摄像机的,有点类似于设置摄像机镜头,这也是这三种变换形式中最复杂的。其中定义视图变换和投影变换是模拟摄像机必须的,若不指定世界矩阵,默认情况下它为一个四阶单位矩阵。三维空间中的坐标,经过世界变换、视图变换(摄像机变换)、投影变换和屏幕转换,才得到二维屏幕上的坐标,其过程如下图所示:

Visual C# 的DirectX开发系列二了解摄像机

首先我们定义视图变换:可以使用Matrix.LookAtLH 或Matrix.LookAtRH 来创建一个视图矩阵,用于表示摄像机位置和摄像机目标位置,其中Matrix.LookAtLH 用于创建左手法则的视图矩阵,Matrix.LookAtRH 用于创建右手法则的视图矩阵。创建视图矩阵代码如下:

Vector3 eye = new Vector3(0, 0, -30);
Vector3 at = new Vector3(0, 0, 0);
Vector3 up = new Vector3(0, 1, 0);
Matrix viewMatrix = Matrix.LookAtLH(eye, at, up);
其中向量eye 表示摄像机位置,向量at 表示摄像机目标位置,向量up 表示向上的方向,该向量一般都为(0,1,0)。


其次定义投影变换:可以使用Matrix.PerspectiveFovLH 或Matrix.PerspectiveFovRH 创建一个基于视场(FOV)的投影变换,其中PerspectiveFovLH 用于创建左手法则的投影矩阵,PerspectiveFovRH 用于创建右手法则的投影矩阵。下面以PerspectiveFovRH 为例来说明,PerspectiveFovRH()函数的定义如下:
public static Matrix PerspectiveFovLH

(

float fieldOfViewY,
float aspectRatio,
float znearPlane,
float zfarPlane
);
其中参数fieldOfViewY表示视场在Y 方向的弧度,参数aspectRatio 表示平面纵横比,
参数znearPlane,表示*面的距离,参数zfarPlane表示远平面的距离。如下图所示:

Visual C# 的DirectX开发系列二了解摄像机

建立投影矩阵代码如下:

Matrix projection = Matrix.PerspectiveFovLH((float)Math.PI / 4,
this.Width/this.Height, 1.0f, 50.0f);

之后是设置绘图设备投影及视图矩阵、绘制三角形等。全部代码如下:

using System;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Windows.Forms;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;

namespace 摄像机
{
    public partial class Camera : Form
    {
        Device device = null;//定义绘图设备

        public Camera()
        {
            this.ClientSize = new Size(800, 800);//指定窗体尺寸
            this.Text = "摄像机";//指定窗体标题
        }

        public bool InitializeDirect3D()
        {
            try
            {
                PresentParameters presentParams = new PresentParameters();
                presentParams.Windowed = true; //指定以Windows窗体形式显示
                presentParams.SwapEffect = SwapEffect.Discard; //当前屏幕绘制后它将自动从内存中删除
                device = new Device(0, DeviceType.Hardware, this, CreateFlags.SoftwareVertexProcessing, presentParams); //实例化device对象
                return true;
            }
            catch (DirectXException e)
            {
                MessageBox.Show(e.ToString(), "Error"); //处理异常
                return false;
            }
        }

        public void Render()
        {
            if (device == null)   //如果device为空则不渲染
            {
                return;
            }
            Vector3 eye = new Vector3(30, 0, -30);
            Vector3 at = new Vector3(0, 0, 0);
            Vector3 up = new Vector3(0, 1, 0);
            Matrix viewMatrix = Matrix.LookAtLH(eye, at, up);
            Matrix projection = Matrix.PerspectiveFovLH((float)Math.PI / 4, this.Width/this.Height, 1.0f, 50.0f);

            device.Transform.Projection = projection;
            device.Transform.View = viewMatrix;

            device.RenderState.FillMode = FillMode.WireFrame;
            device.RenderState.Lighting = false;

            device.Clear(ClearFlags.Target, Color.Black, 1.0f, 0);  //清除windows界面为黑色
            device.BeginScene();
            //在此添加渲染图形代码
            CustomVertex.PositionColored[] vertices = new CustomVertex.PositionColored[3];//定义顶点
            vertices[0].Position = new Vector3(0f, 0f, 0f);
            vertices[0].Color = Color.Red.ToArgb();
            vertices[1].Position = new Vector3(5f, 10f, 0f);
            vertices[1].Color = Color.Green.ToArgb();
            vertices[2].Position = new Vector3(10f, 0f, 0f);
            vertices[2].Color = Color.Yellow.ToArgb();

            device.VertexFormat = CustomVertex.PositionColored.Format;
            device.DrawUserPrimitives(PrimitiveType.TriangleList, 1, vertices);
            
            device.EndScene();
            device.Present();
        }

        static void Main()
        {
            Camera Camera = new Camera(); //创建窗体对象
            if (Camera.InitializeDirect3D() == false) //检查Direct3D是否启动
            {
                MessageBox.Show("无法启动Direct3D!", "错误!");
                return;
            }
            Camera.Show(); //如果一切都初始化成功,则显示窗体
            while (Camera.Created) //设置一个循环用于实时更新渲染状态
            {
                Camera.Render(); //保持device渲染,直到程序结束
                Application.DoEvents(); //处理键盘鼠标等输入事件
            }
        }
    }
}

最终效果如图:

Visual C# 的DirectX开发系列二了解摄像机


本文源码下载地址:http://download.csdn.net/detail/yangyisen0713/8385885

Visual C# 的DirectX开发系列二了解摄像机

上一篇:【C#】Abstract和Virtual的区别


下一篇:c# 如何获取系统管理员权限(UAC) 及判断当前是否是管理员权限