使用DirectX可以让在Windows平台上运行的游戏或多媒体程序获得更高的执行效率,掌握DirectX的基本概念和技术是虚拟现实技术、计算机仿真和3D游戏程序开发的基础。
DirectX是微软的一个多媒体应用编程接口(API)工具包,用于为Windows操作系统开发交互式软件。
DirectX主要包含两方面:
DirectX中的API可以按照功能性质分为以下4个部分:
应用程序调用Direct3D(D3D)方法,D3D方法通过HAL层指示设备完成某些操作,最终实现对设备的操作。
显卡品种具有丰富的多样性,为了让D3D能够始终按照统一的规范进行编程,因此各设备制造商将产品支持的功能写入HAL层中,供Direct3D 调用。HAL是Direct3D和图形设备之间的中间环节硬件抽象层(Hardware Abstraction Layer,HAL),封装了指示设备完成某些操作的代码。
DirectX的第1个版本发布于1995年,最早是作为openGL的替代品被加入windows操作系统中。
1996年,DirectX2.0发布,并提供了其标志性产品Direct draw。1997年,Direct3.0和3D加速卡开始出现。
2001年,微软发布了DirectX 8.0,首次引入“像素渲染”概念,还提供Pixel Shader(像素渲染)引擎和 Vertex Shader(顶点渲染)引擎,可实现动态光影效果。而此时 OpenGL的功能改进十分有限,逐渐落后于图形硬件的发展。
2004年OpenGL版本更新,改善了其功能,但随着 DirectX 的不断发展和完善,OpenGL的优势逐渐丧失。
2005年,微软发布Windows Vista 系统,Vista内置 DirectX 10,而且向下兼容,显卡的画质和速度有了革命性的提升,所有的显卡GPU管线被赋予更加完善的 Shader 功能运算。
2009年,微软发布Windows 7,DirectX11作为DirectX 10的加强版集成在其中。DirectX 11拥有Tessellation(拆嵌式细分曲面技术)、Multi-Threading(多线程)、DirectCompute(通用计算)、Shader Model5.0(渲染引擎5.0)以及 Texture Compression(纹理压缩)5个重要特性。
Direct3D默认使用左手坐标系,左手手背朝自己,手掌向上竖直。坐标系中的 +x 轴 朝向为左手大拇指的指向, +z 轴 朝向从手心穿进, +y 轴 朝向为四指朝向。如图所示,+z方向指向屏幕里,+y方向竖直向上,+x方向向右。
顶点缓存是包含顶点数据的连续内存空间。索引缓存是包含索引数据的连续内存空间。顶点缓存和索引缓存可以被放置在显存或内存中。绘制时,使用显存中的数据比使用内存中的数据要快得多。
深度缓存算法是由Catmull在1975年提出的,基本思想是对当前点(x,y)保持到目前为止遇到的最小z值,以求出具有最小z值的点。
深度缓存是一个后台缓存,缓存中只存储场景深度信息,而不包含图像数据的表面信息。绘制图元时,将图元的深度信息和深度缓存中的内容加以比较,如果深度信息小于深度缓存中的内容(该图元更靠近视点),就更新深度缓存和颜色缓存的内容;如果深度信息大于深度缓存,则该像素不可见,直接抛弃。
深度缓存通过对每一个图元给予一个深度值的方式,来判断哪些图元被遮住。
Direct3D的图形绘制是通过一个称作 Direct3D 渲染流水线的过程来完成的。在整个绘制过程中,首先提供描述三维物体模型的顶点数据及其他的场景元素,然后经过Direct3D渲染流水线的处理,最终得到能够显示在屏幕上的像素。
所有的物体模型都是通过多边形网格逼近表示,这些多边形网格是构成物体模型的基本单元,可以是三角形或四边形,通常选用的几何图形种类是三角形。通常这些构成物体模型的三角形为三角形图元,此外还有点图元。
Direct3D在描述三角形图元时,需要指定三角形单元的3个顶点的列表,该列表包含顶点的位置以及其他一些信息(如颜色等)。在描述由三角形图元构成的物体时,需要指定构成该物体的三角形图元列表。
顶点结构定义好之后,需要用FVF(灵活顶点格式,Flexible Vertex Format)来描述在顶点缓冲区的顶点存储格式中包含哪些属性。灵活顶点格式的作用是,使应用程序只使用它需要的顶点数据,排除那些它不需要的组成成分。通过D3DFVF的组合,可以描述图元顶点的格式。
顶点格式指定:
顶点格式指定的顺序要求:
三角形图元是构成3D物体的基本组成部分,在 Direct3D中,所有物体均可以由三角形逼近拟合来构成。
一个完整的模型通常是由多个三角形图元构成的三角形网格,需要使用三角形图元列表来存储。每个三角形图元由3个顶点构成。
如图所示,一个正方形共有6个顶点,需要两个三角形图元来构成,顶点列表为Vertex vertexList[6].(v0,v1,v2,v3,v4,v5)
,其中有两个顶点重复。当物体形状复杂、描述物体用到的三角形数目非常大时,重复的顶点会占用大量的存储空间,造成资源浪费。为防止这种情况发生,引入了[[#顶点索引列表]]。
三角形顶点的指定顺序称为绕序(Winding Order)。Direct3D 中规定:
顶点索引链表是为了避免共用顶点数较多时,重复顶点的储存占用大量的储存空间。顶点的索引在三维形体绘制中尤为重要,索引列表决定了三角形单元的构成与朝向。
首先为需要绘制的图形建立顶点列表,再建立一个指向该顶点列表的索引列表,这些索引规定了三角形单元的顶点组织方式,当Direct3D绘制图形时,会根据这些索引结构创建三角形列表,并进一步构建三角形网络。
以左图的五边形网格体为例,其顶点结构、和索引链表如右图。
在 Direct3D中,在屏幕上绘制任何物体都要通过一系列变换的流水线,Direct3D绘制流水线主要包括变换和照明(T&L阶段)、光栅化处理两个阶段:
局部坐标系描述了模型的方向及构成物体的元素(点、三角形、子模型)相对于物体中心的位置。在创建模型时,模型各顶点的坐标是相对于局部坐标系描述的,当模型旋转或移动时,与该模型相关联的局部坐标系将随之旋转或移动。
将模型放置在要绘制的场景中,整个场景的坐标系就是世界坐标系,场景中的每个模型的坐标系就是自己独立的局部坐标系。场景中的所有模型都必须从自己的局部坐标系变换到世界坐标系中,用以定义场景中模型之间的空间相对关系。场景中光源的坐标使用世界坐标系定义。
对于一个在场景中不断运动的模型,就需要为该模型定义一个随时间变化的变化序列,以便在每一帧中确定该模型在世界坐标系中的不同位置。
将位于局部坐标系中的物体变换到世界坐标系中,需要通过世界变换运算。该变换通常包括平移、旋转和比例缩放,分别用于设置物体在世界坐标系中的位置、方向和大小。
设某点P坐标值为(x,y,z),将该点向x轴方向移动dx,向y轴方向移动 dy,向z轴方向移动 dz,变换后P’点坐标值为(x’,y’,z’),则有x’=x+dx;y’=y+dy;z’=z+dz。将点的平移以矩阵表示:
将旋转矩阵传给 Direct3D,经过坐标转换后就可以看到模型旋转效果。Direct3D提供了D3DXMatrixRotationX、D3DXMatrixRotationY和 D3DXMatrixRotationZ函数来计算模型绕x、y和z三个坐标轴旋转的矩阵。
模型绕z轴旋转时,z坐标值不会发生变化,仅有x和y坐标值发生变化。等同于在z=0平面上绕原点的旋转变换。设空间中任意一点 P(x,y,z)
绕 z
轴旋转 θ
角,变为P'(x',y',z')
,如下图所示:
模型绕x轴旋转时,x坐标值不会发生变化,仅有y和z坐标值发生变化。设空间中任意一点 P(x,y,z)
绕 x
轴旋转 θ
角,变为P'(x',y',z')
,有:
![![[Pasted image 20231014194310.png|475]](https://img-blog.csdnimg.cn/7c41f99c75504e6aa36a2f27e5af8ae7.png)
模型绕y轴旋转时,y坐标值不会发生变化,仅有x和z坐标值发生变化。设空间中任意一点 P(x,y,z)
绕 y
轴旋转 θ
角,变为P'(x',y',z')
,有:
设某点P
坐标值为(x,y,z)
,在x、y、z轴方向扩大S倍后,变换后P'
点坐标值为(x',y',z')
,则有x'=S*x,y'=S*y,z'=S*z
,则用矩阵表示如下:
观察坐标系(或相机坐标系)指定了从何种方向和位置对三维空间中的物体展开观察,以及摄像机的屏幕可视区域。通常情况下,观察坐标系指定了摄像机(观察视角)的位置,从而能够将三维空间中的物体投影到屏幕可视区域的二维平面中。
当摄像机旋转时,为了简化运算将进行取景变换(view space transformation),设置摄像机的视线方向与世界坐标系z轴的正方向一致,同时将世界坐标系中的所有几何体都随着摄像机一同进行旋转,来保持摄像机视场的恒定。变换后的几何体被称为“位于观察坐标系中的几何体”。
消隐的目的是剔除那些处于屏幕背面或物体内部的面,具体哪些面需要隐藏与观察位置有密切关系,即相对于观察位置,前面的面可见、背面或被其他面遮挡的面则不可见。
早期的面消隐算法是深度排序法,这种方法是把屏幕设成背景色,再把各个面按照离视点的远近进行排序,按照由远到近的顺序逐层绘制。
现在常用的消隐算法是z-缓冲算法,z-缓冲算法对显示设备上每一个像素进行判断,对每一个像素检查所有的三角形面,判断其在该像素上是否可见。z-缓冲算法使用更新缓冲存储器存储屏幕上所有点的像素值,使用Z缓冲存储器存储屏幕上所有点的z值。
每当有一个新的图元被转换到屏幕坐标系中,在开始着色之前,GPU会计算新像素到摄像机之间的距离,并与已经存储在z-缓冲存储器中的z值进行比较。如果新的像素离摄像机更近,就把旧的像素替换掉,把新的深度值记入z-缓冲存储器,把新像素的颜色值记入更新缓冲存储器。
在消隐阶段,还会对图元的朝向进行判断。
光源定义在世界坐标系中,变换到观察坐标系中进行计算。
裁剪就是将视域外的几何体剔除掉的过程,Direct3D 的裁剪过程被包含在投影过程中,在定义投影变换矩阵的同时,定义取景体的范围,Direct3D通过裁剪过称剔除位于取景体外的物体模型部分,并将剩下的三维场景投影到一个二维平面上。
投影,是把n
维空间中的点投射到小于n
维的空间中的变换过程。把摄像机观察到的三维景象显示在二维的平面上,这种三维到二维的变换就是投影变换。正交投影和透视投影是两种常见的投影变换:
视口变换(viewport transform)是空间变换的最后一步,视口变换就是通过定义屏幕显示区域的实际宽、高等参数,将顶点从投影坐标转换为以像素为单位的屏幕坐标,最终完成从投影窗口到屏幕中某一区域的变换,这一区域也被称为视口。
在游戏中,视口通常是整个屏幕,但视口也可以是屏幕上的某一块矩形区域。视口与其所在的窗口相关,并且通过所在窗口的相对坐标来进行描述。
其中X、Y表示视口矩形相对于屏幕的位置,Width、Height表示视口区域的大小,MinZ、MaxZ表示深度缓存中的最小深度值和最大深度值,深度范围设置在[0,1]区间内。
虚拟摄像机的可见视域模型如下图所示,可见视域外的物体都是不可见的。视椎体的主要参数包括视角的水平范围、垂直范围、投影窗口和远、近裁剪面。其中,投影窗口是一个二维区域,位于视域体中的三维几何体通过投影映射到该区域中,从而实现三维物体的二维显示。在 Direct3D中,将投影平面定义为平面z=1。
渲染也称光栅化,渲染的目的是计算每个三角形图元像素的颜色值,并最终绘制三角形图元,渲染的最终结果是显示在屏幕上的2D图像。光栅化的本质是矢量图像素化的过程,或者说是将连续的图像用像素点阵来表示,并显示在屏幕上的过程。