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(投影变换)可以认为是用来控制摄像机的,有点类似于设置摄像机镜头,这也是这三种变换形式中最复杂的。其中定义视图变换和投影变换是模拟摄像机必须的,若不指定世界矩阵,默认情况下它为一个四阶单位矩阵。三维空间中的坐标,经过世界变换、视图变换(摄像机变换)、投影变换和屏幕转换,才得到二维屏幕上的坐标,其过程如下图所示:

首先我们定义视图变换:可以使用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表示远平面的距离。如下图所示:

建立投影矩阵代码如下:

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(); //处理键盘鼠标等输入事件
            }
        }
    }
}

最终效果如图:

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

时间: 2024-11-06 11:39:23

Visual C# 的DirectX开发系列二了解摄像机的相关文章

Visual C# 的DirectX开发系列一初识DirectX

1.如何查看本机的DirectX的版本: 点"开始"-"运行",在"运行"里输入"dxdiag"回车,弹出DirectX 诊断工具窗口,就在首页中,有很多系统信息,最下面一条就是DirectX版本.如图: 2.添加DirectX类库的引用: 新建WinForm窗体应用程序,然后添加三个Reference(引用),分别是:Microsoft.DirectX.Microsoft.DirectX.Direct3D 和Microsof

arcgis api for js入门开发系列二不同地图服务展示(含源代码)

上一篇介绍了arcgis api离线部署,这篇开始正式介绍arcgis api for js开发:想要学习webgis开发,首先得熟悉了解前端技术,比如界面布局设计的html+css,核心的是javascript(js),arcgis api就是js写的,就是说想要开发gis功能前提下,你得熟悉了解js,不然你连源代码都看不懂.在这里,推荐esri官网的arcgis api for js:https://developers.arcgis.com/javascript/3/jsapi/:里面详细

【Qt编程】基于Qt的词典开发系列<二>--本地词典的设计

我设计的词典不仅可以实现在线查单词,而且一个重大特色就是具有丰富的本地词典库:我默认加入了八个类型的词典,如下所示: 由于是本人是通信专业,因此加入了华为通信词典.电子工程词典,又由于我喜爱编程,也加入了c语言基本函数词典.下面介绍如何设计本地词典: 词典类型的选择 当然是txt格式的最好了,因为我们可以用程序直接进行读取.可是网上词典一般都是用mdx格式.ld2格式的,我无法用Qt来直接读取.最终,经过不断摸索,网上查找,发现我们可以将mdx格式的词典通过软件转化为txt格式的! mdx词典的

BizTalk开发系列(二) "Hello World" 程序搬运文件

我们在<QuickLearn BizTalk系列之"Hello World">里讲到了如何快速的开发第一个BizTalk 应用程序.现在我们来讲一下如何把这个程序改成用于搬运文件的程序. 我们的设想是:不管文件的类型是什么,将文件从In 文件夹搬到 Out 文件夹.我们来看看应该怎么实现这个设想. 首先我们会发现"Hello World"程序在接收位置的文件名称是" *.XML ".也就是说它只接收XML文件类型的文件.既然它支持通配

visual Studio 2017 扩展开发(二)《菜单图标详解》

在上一篇我们在菜单栏创建了一个菜单,菜单上显示了一个图标跟文本.那么我们自己创建的菜单如何修改自定义的菜单图标呢.下面娓娓道来..... 首先你要有一个图,创建一个32位的位图.这个位图的像素是16px 16px,或者是16px 16px的倍数. 每个图标都放在单个行中彼此相邻的位图上.使用Alpha通道在每个图标中指示透明的位置.如果使用8位颜色深度,请使用RGB(255,0,255)作为透明度.32位彩色图标是首选. 将图标文件复制到项目的Resources文件夹下. 打开command.p

Vue开发系列二 熟悉项目结构

初始项目结构如上所示.src:  写代码地方,我们大部分的操作都在此 static :资源目录 static目录下还可以放一些第三方的js库,通用的css等,这样每次打包的时候节省打包时间 原文地址:https://www.cnblogs.com/menchao/p/8425749.html

arcgis api for js入门开发系列二十一气泡窗口信息动态配置模板

前面地图查询篇实现图层查询query功能,但是查询结果的气泡窗口展示信息是在代码写死绑定图层的字段来的,比如name属性字段对应的值.但是这种实现方式很不灵活,对于图层字段不变的情况下或者多个图层字段名称都是一致情况下,还好,代码也不用变动:要是图层字段新增或者删除以及多个图层的字段不一致情况下,每次改动,查询结果的js代码也要对应的修改,对于维护来说,挺不方便的.所以,本篇优化一下气泡窗口的信息模板,采取动态可配置化图层字段方式,在配置文件里面配置好图层需要展示的字段模板,比如在mapconf

短信开发系列(三):短信接收引擎

短信开发系列目录: 短信开发系列(一):GSM手机短信开发初探短信开发系列(二):GSM手机短信开发之短信解码短信开发系列(三):短信接收引擎 之前写了短信接收处理的一些内容,今年事情实在太多了,就停顿了这么一大段的时间.接下来会继续完成相关的内容. 今天先写用之前写的短信类库的一个应用,短信接收引擎.可以用在处理一些短信的提醒:作为前面两篇文章的一个实战运用,可以作为一个多线程.委托和事件.串口等方面知识的一个综合运用. 先来分析一下整个程序的流程: - 启动线程 - 定时运行线程主函数 -

【DevOps】团队敏捷开发系列--开山篇

随着软件发布迭代的频率越来越高,传统的「瀑布型」(开发-测试-发布)模式已经不能满足快速交付的需求.2009 年左右 DevOps 应运而生,开发运维一体化,通过自动化工具与流程让整个软件开发构建.测试.发布更加快捷.频繁.高效和可靠. 本系列教程目录 本系列将详细讲解Devops落地细节.将构建整个持续集成与交付的一整套体系与流程.对于未来要开篇的系列博文列表如下: [DevOps]团队敏捷开发系列(一)--开山篇 [DevOps]团队敏捷开发系列(二)--版本控制之道Git [DevOps]