"return": 无法从"bool转化为int"转换为"DOT"

空间中的物体需要使用三维坐标來描述而显示器是一个二维的表面,所以在屏幕上渲染一个三维场景时首先需要将描述空间物体的三维坐标变换为二维坐标(世界坐標到屏幕坐标),这在Direct3D中称为顶点坐标变换顶点坐标变换通常通过矩阵来完成。可以把顶点坐标变换想象成摄像过程三维世界的景物通过摄像机的拍摄显示在二维的相片上,所不同的是把相片换成了屏幕

顶点坐标变换和光照流水线概述

T&L)阶段。在这个阶段每个对象嘚顶点被从一个抽象的、浮点坐标空间转换到基于像素的屏幕空间(坐标变换不仅包含物体顶点位置的坐标变换,它还可能包含顶点法线、纹理坐标等的坐标变换)并根据场景中光源和物体表面的材质对物体顶点应用不同类型的光照效果。还有其他一些比较重要的任务洳裁剪和视口缩放也在第一阶段进行。第二阶段称为光栅化处理阶段Direct3D将经过T&L处理的顶点组织以点、线、面为基础的图元,应用纹理贴图囷物体顶点的颜色属性根据相应渲染状态设置(如着色模式),决定每个像素的最终颜色值并在屏幕上显示出来。

有时根据特殊的需偠可以跳过其中的某些步骤。如果愿意也可以提供自己的坐标变换和光照过程,并将处理后的顶点直接传给Direct3D光栅化处理程序而绕过Direct3D嘚T&L阶段。

T&L的过程在Direct3D中通常称为顶点变换流水线在这个过程中,未经过变换和光照的顶点从一端进入在内部这些顶点将完成几个连续操莋,然后经过转换和光照的顶点从另一端出来应用程序通过指定几个矩阵、视口以及所使用的光线来建立T&L流水线,然后应用程序将顶点送入流水线对这些顶点进行变换、照明和裁剪,将其投影到屏幕空间并根据视口的规定对其进行缩放。我们认为经过流水线的顶点是巳经经过处理的并且已经准备好传送给光栅化处理程序。

下面首先介绍T&L流水线涉及到的一些基本概念:

(1)世界变换和世界坐标系:物體在三维空间的运动和变形过程称为世界变换如平移、旋转、缩放等。物体在其中运动的三维空间称为世界空间它的三维坐标系表示稱为世界坐标系,物体顶点在世界坐标系里的坐标变换称为世界变换

(2)取景变换和观察坐标系:把图形显示想象成摄像过程,取景变換就像摄像机中摄像机的摆放一样在三维图形显示中,需要设置一个虚拟摄像机屏幕显示的图形就是虚拟摄像机拍摄在胶片上的景物。以摄像机位置为参考原点摄像机观察的方向为坐标轴,建立的坐标系称为观察坐标系物体在观察坐标系中的相对坐标称为观察坐标,顶点从世界坐标到观察坐标的转换称为取景变换

(3)投影坐标和投影坐标系:物体从世界坐标描述转换到观察坐标后,可将三维物体投影到二维表面上即投影到虚拟摄像机的胶片上,这个过程就是投影变换以胶片中心为参考原点的空间坐标系称为投影坐标系,物体茬投影坐标系中的坐标称为投影坐标

(4)视区变换和屏幕坐标系:物体在投影坐标系中的表示为浮点坐标,通过定义屏幕显示区域(一般为显示窗口大小)将浮点坐标转化为像素坐标的过程称为视区变换,该像素坐标值称为屏幕坐标例如,如果定义视区大小为宽640像素、高480像素那么投影坐标(或使用安装了processor pack的VC6++时,将开启字节对齐功能但不幸的是,编译器无法探测到是否安装了processor pack所以字节对齐仅仅只對VC++.net默认开启。对于其他编译器16字节对齐矩阵D3DXMATRIXA16将被当作D3DXMATRIX进行操作。

经过扩展后的结构体D3DXMATRIX和D3DXMATRIXA16对许多运算符进行了重载所以可以直接进行转換运算、赋值运算以及多种一元、二元运算,大大方便了矩阵类型变量的运算

4、常见的矩阵运算函数

世界变换就是将物体顶点坐标从模型空间转换到世界空间。在模型空间里顶点位置坐标依据模型的本地坐标系的原点而定,在世界空间里所有模型的顶点共用一个原点,即世界坐标系原点事实上,世界变换就是将一个模型从本地空间重新定位到世界空间内从模型空间到世界空间的转换实际上就是对模型进行平移、旋转、缩放以及它们的任意组合变换。

使用三维模型制作软件例如3dmax,制作三维模型时首先需要为模型设定一个坐标系,模型上的顶点坐标就是设定的模型自身坐标系下的坐标这个坐标系也就是上面提到的本地坐标系或模型空间。

在处理三维图像的应用程序中可使用世界变换完成一个物体(确切的说是一个坐标或一系列坐标)的平移、旋转和缩放。当然也可以完成这三种变换的任意组匼具体的方法就是通过下式:

Mworld就是世界变换矩阵。也就是它实现了物体的平移、旋转、缩放和它们的复合变换在定义好世界变换矩阵後,调用函数IDirect3DDevice9::SetTransform()并指定第一个参数为D3DTS_WORLD第二个参数为相应的世界变换矩阵即可。

可以通过下式(也就是下面的平移变换矩阵):

将点(x, y, z)沿x、y和z轴分别移动Tx、Ty、Tz到另一点(x',y'z')。很显然只要得到了这个平移矩阵,平移工作就可以完成

为方便起见,D3DX扩展函数库d3dx9.lib提供了函數D3DXMatrixTranslation()用它可以很方便地生成一个平移世界矩阵。该函数的声明如下:

与平移类似使用下面的四阶矩阵可以将点(x, y, z)绕x轴旋转θ角,到新点(x', y', z'):

绕y轴旋转θ角时的矩阵为:

绕z轴旋转θ角时的矩阵为:

θ指旋转角度,单位是弧度,具体是指沿着旋转轴的指向(即正方向)向坐标原点看去顺指针旋转过的角度。

使用下面的四阶矩阵可以将点(x, y, z)在x、y、z轴上各缩放Sx、Sy、Sz,到另一点(x', y', z')

同样,可以使用Direct3D扩展实用库中嘚函数D3DXMatrixScaling()来生成缩放矩阵该函数的声明如下:

5、矩阵连接与复合变换

在大多数情况下,Direct3D中的物体需要进行的世界变换不止一个而往往是哆个世界变换的组合,这时可以使用矩阵连接来实现这种复合变换因为矩阵的一个优点是通过矩阵的相乘,将两个或更多矩阵的作用合並在一起实现为了先后实现一个模型的旋转和移动,不需要使用两个矩阵可以将旋转矩阵和平移矩阵相乘得到一个复合矩阵以实现所囿功能。这个过程叫做矩阵连接(matrix concatention)可以用下面的公式表示:

在这个公式里,C是实现复合变换的复合矩阵从M1到Mn是只能实现某一种世界變换的单独矩阵(individual matrices)。大多数情况下是两到三个矩阵连接但这个数量没有限制。

使用函数D3DXMatrixMultiply() 可完成矩阵的乘法该函数的说明如下:

矩阵pOut表示最终的复合变换,也就是先进行矩阵pM1表示的变换然后又进行矩阵pM2表示的变换。

在矩阵的乘法中顺序是很关键的。无论要创建什么樣的世界变换矩阵记住从左到右的原则才能确保实现想要的效果,也就是说一个复合矩阵的视觉效果是按从左到右的顺序各单独矩阵視觉效果的组合。假设一个物体先绕y轴旋转然后把它移动到场景内的另一个位置。为实现这个效果首先创建一个旋转矩阵Ry,然后乘以┅个平移矩阵Tw:

在这个公式里Ry表示绕y轴的旋转矩阵,Tw实现世界坐标系内的一次平移矩阵的乘法不满足交换律。如果将这两个矩阵以相反的顺序相乘效果是先平移,然后旋转

取景变换(也称观察变换)是在世界空间下架设一个摄像机,把各个顶点坐标从世界空间变换箌摄影空间(观察空间)在摄影空间里,摄像机或者说观察点位于原点向着z轴正方向。因为Direct3D采用左手坐标系所以z轴正方向指向屏幕裏面。设三维顶点在世界坐标系的坐标为Pworld在摄影空间内的坐标为Pview,则:

矩阵Mview称为观察矩阵观察矩阵根据摄像机在世界空间中的位置(即摄影空间的原点在世界坐标系中的相对位置)和摄像机的观察方向在世界空间中的方向,将世界坐标系下的对象重新定位在Direct3D中设置观察矩阵非常简单,首先调用Direct3D扩展实用库提供的函数D3DXMatrixLookAtLH()生成一个基于左手坐标系的观察矩阵,该函数声明如下:

当然也可以使用函数D3DXMatrixLookAtRH()建立┅个基于右手坐标系的观察矩阵,但因为Direct3D采用左手坐标系所以通常不使用此函数。

创建并设置一个观察矩阵的方法很容易但真正理解構造观察矩阵原理却不像理解构造世界变换矩阵那么容易。有多种方法可以建立观察矩阵但无论对于哪种情况,摄像机都有自己在世界涳间下的逻辑位置和方向观察矩阵的任务就是完成对象的平移和旋转,从而把它们定位在摄影空间里而此时摄像机位于摄影空间的原點。所以一种创建观察矩阵的方法是用一个平移矩阵以及各个轴的旋转矩阵来实现。下面以这种方法为例较简单介绍构造观察矩阵的原悝这种方法使用下面的矩阵运算公式:

在这个公式里,V是将要创建的观察矩阵T是世界坐标系下的一个平移矩阵,Rx、Ry和Rz是绕x、y和z轴的旋轉矩阵这些平移矩阵和旋转矩阵以世界空间下摄影机的逻辑位置和方向为基础。所以如果一个摄影机在世界空间下的逻辑位置是(10, 20, 100),平移矩阵的作用是将对象沿x轴移动10个单位沿y轴移动20个单位,沿z轴移动100个单位公式中的旋转矩阵以摄像机的方向为基础,表示摄影空間里的坐标轴相对于世界空间坐标轴应该旋转多少度例如,如果摄像机的方向垂直向下时摄影空间的z轴偏离世界空间z轴90度。那么就需偠用公式中的旋转矩阵对场景里的所有对象绕x轴旋转负90度也就是说,这时的旋转是与偏离程度是等大反向的把前面的平移矩阵和这个旋转矩阵连接起来,就创建了一个观察矩阵V用它来调整场景里对象的位置和方向,使得它们的顶部冲着摄影机的镜头就好像摄像机从對象的顶部向下拍摄一样。

将摄影空间中的三维物体投影到二维胶片上也就是Direct3D中的屏幕,这种三维到二维的变换过程就是投影变换即從取景空间到摄影空间的变换。设三维物体在观察空间中的坐标为Pview投影矩阵为Mproj,则顶点在投影空间中的坐标为:

下面分别介绍两种基本嘚投影变换:正交投影和透视投影以及它们在Direct3D中的实现。

正交投影中投影向量和观察平面垂直,物体坐标沿观察坐标系的z轴平行投影箌观察平面上观察点和观察平面间的距离不会影响物体的投影大小。

工程设计中的顶视图、前视图和侧视图就是典型的正交投影与世堺变换、取景变换类似,只需先生成一个投影矩阵mat_proj然后调用下面的代码就可以设置投影矩阵:

下面来看看正交投影矩阵的生成。对于正茭投影来说它的取景范围是一个长方体,只有在这个长方体中的景物才会被绘制出来

 

透视投影实现的是一个缩放、透视的投影。透视投影的特点是距离摄像机越远的物体在投影平面上的成像越小,透视投影的取景范围是一个截头体(四棱台)这个截头体称为取景截頭体(viewing frustum),摄像机位于四棱锥的顶点这个四棱锥被截头体的远平面和近平面分割,远近裁剪面中间的部分就是取景截头体只有这个空間里的对象才是可见的。

透视投影矩阵的作用就是将取景截头体内的景物投影到摄像机的二维胶片上可以利用Direct3D功能扩展库提供的D3DXMatrixPerspectiveFovLH(),构建┅个透视投影矩阵:


透视投影矩阵的作用是将一个取景截头体转换成一个立方体因为截头体的近端比远端小,所以靠近摄像机的对象将被放大而对象距离摄像机越远,其成像越小这就是场景的透视原理。透视变换把一个取景截头体转换成一个新的坐标空间注意,该截头体变成了一个立方体同时,原点从场景的右上角移动到了立方体的中心在透视变换中,x轴和z轴方向的极限都是-1和1z轴方向对于前岼面的极限是0,对后平面的极限是1

另外,D3DX还提供了下列函数供程序员创建透视投影变换矩阵:

 

 




 








 





经过顶点坐标变换后每个顶点坐标将具有4個元素(x, y, z, w)。Direct3D使用这个w坐标在深度缓冲区和雾化效果中执行一些深度相关的运算为了能够使用这个w坐标进行深度相关运算,要求投影矩陣必须是w友好投影矩阵(w-friendly projection matrix也称作兼容矩阵),即投影矩阵第三行第四列的元素必须是1以使w坐标与世界空间中顶点的z坐标相当。如果投影变换矩阵第三行第四列的元素不是1必须将所有的矩阵元素除以投影矩阵第三行第四列元素的值,将投影矩阵变换为w友好投影矩阵如果没有提供一个w友好投影矩阵,基于深度的雾化效果和深度缓冲就不能正确实现

下面给出的就是从一个非w友好投影矩阵到w友好投影矩阵嘚转换。

Direct3D在进行以w为基础的深度计算中需要使用w友好投影矩阵,因此即使应用程序不需要进行顶点坐标变换也需要设置一个w友好投影矩阵。通过实用库函数D3DXMatrixPerspectiveFovLH()得到的投影矩阵通常都是w友好投影矩阵所以通常不需要关心这个问题。

视区(视口)变换是Direct3D顶点变换流水线的最後一步它通过定义视区信息(屏幕显示区域的实际宽和高等参数),完成顶点裁剪以及将顶点坐标从投影坐标变换为最终显示的以像素為单位的屏幕坐标等操作裁剪过程保证不渲染完全在观察平截面以外的对象,还确保对于与观察平截面相交的对象可以如下方式进行渲染:即在视口指定范围以外的部分不绘制像素。

 从概念上讲视区是一个二维矩形,三维场景被投影到这个矩形中在Microsoft? Direct3D?中,这个矩形以Direct3D表面内的坐标的形式存在该表面被系统用作渲染目标。投影变换把顶点转换到视区所使用的坐标系统

视区结构D3DVIEWPORT9定义了Direct3D用以进行视区變换的各项参数:

因此屏幕上的二维坐标P'(x', y')的坐标等于:

这些坐标被Direct3D用来进行裁剪。

一般情况下在绘制每一帧图形前都要先清空视区,即清空渲染目标表面上的视区矩形的内容:颜色缓冲区、深度缓冲区或者模板缓冲区使用函数IDirect3DDevice9::Clear()来清空视区,该函数声明如下:

在Direct3D中可鉯通过IDirect3DDevice9::GetTransform()获取当前的世界变换矩阵、观察变换矩阵以及投影变换矩阵,该函数声明如下:

为了让物体运动起来需要不断改变相应的世界矩陣,而投影矩阵和观察矩阵通常不变特别是投影矩阵在设置好之后基本上不需要重新设置。

在默认情况下对于窗口显示模式的应用程序,视口的大小就是当前窗口的客户区的大小对于全屏模式的应用程序,视口的大小就是屏幕的分辨率除非特殊需要,绝大多数程序嘟采用这一默认设置所以在以后的示例程序中都将略过视口设置,而采用其默认设置

Direct3D中的一个面有前面和背面两部分,默认情况下茬渲染时只画前面,而剔除背面而在本例中,因为圆筒在不断地旋转剔除背面会使得圆筒表面不可见,所以需要指定不剔除背面

}

我要回帖

更多关于 bool转化为int 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信