三维化三角形

  再来看看我们的程序,看起来并不是那么“三维”。而且我们所做的都能用GDI+轻易完成。So,我们应该怎样在3维空间里绘图,并且给人留下深刻的印象呢?实际上,简单的修改就能达到这样的效果。

  如果你还记得,先前在我们创建第一个三角形的时候,我们使用了一个叫做“经过变换的”(transformed)坐标系统。这种坐标是显示器的屏幕区所使用的坐标,也是最容易定义的。如果我们使用未变换过的坐标系统会怎样呢?实际上,未变换过的坐标系统被广泛的用于现代游戏场景。

  与屏幕坐标(screem space)相比我们定义这些坐标时,还应在世界坐标(world space)里定义每一个顶点。你可以把世界坐标设想为一个无限大的三维笛卡儿坐标。你可以把你的对象放到这个“世界”的任意位置。现在来修改我们的程序,绘制一个未经过世界坐标变换的三角形。

  首先使用未变换顶点格式类型中的一种来改变三角形的数据。在这里我们只关心顶点的位置,以及颜色,因此使用CustomVertex.PositionColored。

  CustomVertex.positionColored[] verts = new CustomVertex. positionColored[3];
  Verts[0].SetPosition(new Vector3(0.0f,1.0f,1.0f));
  Verts[0].Color = System.Drawing.Color.Aqua.ToArgb();
  Verts[1]`````````
  Verts[2]`````````
  (参见DirectX sdk Tutorial 3: Using Matrices)

  同样改变VertexFormat属性:

  device.VertexFormat = CustomVertex.PositionColored.Format;

  好了,现在运行程序:什么也没有发生,仅获得一个填充过的窗口。在讨论为什么之前,先来看看我们都作了些什么。就像你看到的,我们选择了PositonColored结构来保存数据。这个结构用世界坐标保存了顶点的位置,也保存了它的颜色。因为为顶点是没有变换过的,所以我们使用Vector3类来代替Vector4类,没有变换过的顶点是没有rhw值的。Vector3结构的成员直接映射为世界坐标系里x,y,z的值。同时,我们需要确定DirectX3D知道所做的改变,所以我们通过更新VertexFormat属性来让固定功能管道使用新的未变换但填充过颜色的顶点。

  So,为什么程序运行时没有正确的显示呢?问题在于,我们只是在世界坐标里绘图,但并没有给DirectX3D任何关于如何来显示它们的信息。我们需要为场景添加一个摄像机来确定如何观看我们的顶点。在经过变换的坐标系统里不需要摄像机的原因是:DirectX3D已经知道在屏幕的哪个位置来显示顶点。

  在device上通过两个不同的变换来控制摄像机。每一种变换都被定义为一个4×4的矩阵传递给DirectX3D。(???each transform is defined as a 4*4 matrix that you can pass in to DirectX3D)

  映射变换定义了场景被怎样投影到显示器。最简单的产生投影矩阵的方法就是使用Matrix类的PerspectiveFovLH方法。它将会使用左手坐标系创建一个正对场景的透视投影变换。(关于左右手坐标系的详细内容请参见sdk,或你的高等数学、高等物理教材^_^)DirectX3D通常使用左手坐标系。

以下是投影函数的签名:
  public static Matrix PerspectiveFovLH( float fieldOfViewY,float aspectRatio,float znearPlane,float zfarPlane);

  投影变换描绘了场景的视见体(注:即可见部分)。视见体是由可视角度和前裁剪面(Near Plane)与后裁剪面(Far Plane)定义的一个平截头体(注:比如四棱锥横截面与底面之间的部分,上帝保佑,你还记得高中几何),在这个平截头体之内的即是可见部分。函数头里的nearPlane和farPlane两个参数,描绘了锥体的边界:farPlane就是锥体的底面,而nearPlane则是横截面。fieldOfView参数描绘了锥体的角度。aspectRatio类似于电视的高宽比,比如,宽银幕电视的高宽比是1.85。你可以用可视区域的宽度来比上高度得出这个值。DirectX3D只绘制在这个平截头体中的物体。

  既然我没从来没有进行过投影变换,也就根本不存在一个视见体,应此DirectX3D什么也没有绘制。但是,就算我们进行了投影变换,我们还没有进行包含了摄像机信息的view transform。可以用一下函数完成这个任务:

  public static Matrix LookAtLH(Matrix pOut, Vector3 cameraPosition, Vector3 cameraTarget, Vector3 cameraUpVector);

  仅仅通过各变量的名字你就可以知道如何使用这个函数。其中三个是用来描述摄像机的属性:它的位置、它观察点的位置以及一个被参考为“up”的方向。有了投影变换和view transform的帮助,DirectX3D已经有足够的信息来绘制三角了。添加代码:(参见DirectX sdk Tutorial 3: Using Matrices中的SetupMatrices()函数)

  再运行一次试试,哦,我们已经有一个三角了,不过它完全是黑色的!问题在哪呢?在没有经过变换的环境里,DirectX3D默认使用灯光来计算场景中几何体每一个象素的颜色,我们没有定义灯光,也没有额外的光照在三角上,So,它完全是黑色的。既然我们已经为每一个点定义过了颜色,所以现在,可以安全并且简单的把场景里的灯关了。加上如下带码:

  dev.RenderState.Lighting = false;

  再试一次,终于,我们回到了未变换坐标前的样子。做了这么多改变到底有什么好处呢?最大的好处就是和在屏幕上直接绘制相比我们获得了一个三维空间里的三角形——迈向伟大三维作品的第一步!^_^

  既然有了三维空间里的三角,我们怎样做才能让他看起来确实是一个三维空间里的三角呢?最简单的事就是让它旋转起来。如何来做呢?很简单,我们只需要更改世界坐标就可以了。

  Device的世界坐标变换会把每一个用局部坐标定义的顶点位置转换为用世界坐标定义的顶点位置。(the world transform on the device is used to transform the objects being drawn from model space ,whice is where each vertex is defined with respect to the model, to world space,where each vertex is actually placed in the world.)Matrix对象的很多方法能完成这种变换:

  device.Transform.World = Matrix.RotationZ( (float)Math.PI/6.0f );

  它告诉DirectX3D除非指定一个新的世界坐标变换,否则在这段代码之后所有绘制的对象都将进行这种变换。以上的世界坐标变换是根据所给的弧度旋转x轴。注意这里的参数必须是弧度而不是角度。有规率的改变参数的值就能让三角形平滑的转动起来了(以下代码略,参考sdk中的示例)。
我们旋转的三角并不能给人留下深刻的印象。我们来试试让他变得特别一点,并且同时旋转多个轴。很幸运,恰好有这样一个方法,好了,更新代码:

  device.Transform.World = Matrix.RotationAxis( new Vector3(angle/((float)Math.PI*2.0f), angle/((float)Math.PI*4.0f), angle/((float)Math.PI*6.0f)), angle/((float)Math.PI);

  这里使用了RotationAxis函数,通过这个函数,我们先定义了旋转轴,并在每一维上用一个简单的式子不停改变轴的位置,然后再传入三角形围绕着轴旋转的角度,就像我们先前做的一样。

  再次运行程序,哦,我们确实得到了一个围绕着旋转轴转动的三角形,但似乎三角形会有规律的消失一阵,然后再显示出来。好了,还记得我们先前提到的背面剔除(back face culling)吗?这就是背面剔除在起作用的最好例子。当DirectX3D渲染物体的时候,如果它发现某一个面没有对着摄相机,就不会绘制它,这就叫做背面剔除。那么程序在运行时,又是怎样知道某一个特定的几何面是否对着摄像机呢?快速的看看DirectX3D中的裁剪选项或许能给你一点提示。三种可用的剔除选项分别是:none,clockwise(顺时针)以及counterclockwise(逆时针)。在clockwise以及counterclockwise的情况下,当简单几何体的顶点排列顺序与剔除模式相反时,它就不会被绘制。

  看看我们的三角形,它的顶点是按逆时针顺序来排列的(注:有关顶点的排列顺序,可参考sdk文档Face and Vertex Normal Vectors)。DirectX3D默认的剔除模式就是逆时针模式。

  你可以简单在顶点集合中把第一个和第三个元素交换一下,看看会有什么不同。

  现在我们知道背面剔除是怎样工作的,很显然,我们简单的程序并不需要剔除功能。有一个简单的render state来控制剔除模式,添加如下代码:

  Device.RenderStates.CullMode = Cull.None;

  再一次,erying works as expected,试试拖放窗口的大小会怎样??

  添上关于投影变换的图片一张
  摄像机位于o点,视见体为ABCD--A'B'C'D',ABCD为后裁剪面,A'B'DC'D'前裁剪面

(第二部分完,下一次我们将要讨论灯光了,并且解决拖放窗口时出现的问题)

转载于:https://www.cnblogs.com/yangbeibei/archive/2006/12/07/584927.html

深入Managed DirectX9(二)相关推荐

  1. 深入Managed DirectX9

    作者 calyman    clayman_joe@yahoo.com.cn   (超级好的翻译.建议初学者仔细看) 文章来源 >> http://www.cnblogs.com/dago ...

  2. 深入Managed DirectX9(转)作者calyman(超级好的翻译。建议初学者仔细看)

    作者 calyman    clayman_joe@yahoo.com.cn :[翻译]深入Managed DirectX9(一) Device类是DirectX里的所有绘图操作所必须的.可以把这个类 ...

  3. 深入Managed DirectX9(四)

    选择正确的Device The number of possible permutations when cretion a device is quite staggering. 如今,市场里有大量 ...

  4. (转)Managed DirectX +C# 开发(入门篇)(二)

    第二章 向量的运算(1) 1:向量相等 几何学上,有同样方向和长度的两个向量相等.数学上,我们说有同样维数和分量的向量相等.例如:如果ux = vx, uy = vy, 且 uz = vz.那么(ux ...

  5. 使用Managed DirectX编写游戏

    转自  http://dev.gameres.com/Program/Visual/DirectX/ManagedDirectX9Game_01.htm http://dev.gameres.com/ ...

  6. 《Managed DirectX +C# 开发(入门篇)》系列文章

    写在最前: 1.本系列文章版权归tongabcd所有,转载自dandanCool(并非原创作者),此处只作收藏与分享之用. 2.此系列文章如有再转,需按如下方式于文章醒目位置显示标明原创作者极其联系方 ...

  7. (转)Managed DirectX +C# 开发(入门篇)(一)

    前      言 以前是用VC 作计算机图形学的,大约在一年前,公司接到一个用C#+DirecX的项目,从那时起便开始学习Mangaged DirectX ,现将在开发过程中的一点总结发表出来,和同行 ...

  8. saltstack实现haproxy+keepalived负载均衡+高可用(二)

    一键部署haproxy+keepalived实现负载均衡+高可用 实验环境: !!!!    特别注意: www.westos.org为test1的minion名字 test1: 172.25.1.1 ...

  9. Civil 3D 二次开发 创建AutoCAD对象—— 00 ——

    不积跬步无以至千里,不积小流无以成江海.虽然创建一条直线.添加一个图层这样的小程序没有什么实际意义(内部命令很简单就可以完成),但对于初学二次开发的您来说,这可是一大步,这一步跨出去,您就跨进了二次开 ...

最新文章

  1. 说说Android桌面(Launcher应用)背后的故事(二)——应用程序的添加
  2. python运行速度和电脑配置有关系吗-学python最电脑配置有要求么
  3. Scala @BeanProperty注解生成getter/setter
  4. PyTorch学习问题记录
  5. 前端和后端哪个工资高_前端、后端、全栈都是干嘛的?哪个薪资高?
  6. mysql mgr bug_Mysql MGR架构误操作引发的问题处理
  7. Holding Bin-Laden Captive! (HDU-1085)
  8. 一些简单有趣的c语言编程,一个有趣的小程序
  9. oracle等待事件查询,Oracle查看等待事件_yh_zeng2的博客-CSDN博客
  10. opencv 纸箱分割_OpenCV与AIPCV库——学习笔记(一)
  11. docker︱docker run的解读与一键部署
  12. 1546: 回形取数
  13. oracle删sequen,sequen是什么意思
  14. python 今天日期是多少,python time时间,日期,时间
  15. Java基础语言(可查阅)
  16. 区块链对医疗行业的影响
  17. [资源]_清华大学计算机视频教程_31门_种子ed2k_BT下载
  18. 【Matlab作业】MATLAB语言基础
  19. 冯诺依曼机核心由运算器转变为存储器的原因
  20. 10分钟理解相机ISP(图像信号处理)整体流程

热门文章

  1. spring 查找实现类_69道Spring面试题和答案
  2. 鼬电脑壁纸_火影忍者高清壁纸需要自取1080p
  3. gb2312编码表_汉字编码输入系统模型(一)
  4. 基于Echarts+HTML5可视化数据大屏展示—大数据智慧数据平台
  5. mysql树节点路径,关于mysql:从使用物化路径编码树的表中选择,按深度优先排序(无递归/ ltree)...
  6. 怎么设置internet才能下载JAVA_如何使用Java从Internet下载和保存文件?
  7. java this关键字的使用
  8. windows mysql4.1安装_Windows下,MySql的安装及配置(Install and Config of MySQL in Windows)...
  9. Java 获取 URL 响应头信息
  10. linux查看mongodb的ip地址,[转载]在MongoDB的shell中显示服务器当前IP