• DirectX绘制流水线


    使用DirectX可以让在Windows平台上运行的游戏或多媒体程序获得更高的执行效率,掌握DirectX的基本概念和技术是虚拟现实技术、计算机仿真和3D游戏程序开发的基础。

    DirectX概述

    DirectX是微软的一个多媒体应用编程接口(API)工具包,用于为Windows操作系统开发交互式软件。
    DirectX主要包含两方面:

    1. DirectX软件开发包(DirectX Software Development Kit,DirectX SDK):一整套开发Windows应用程序所需的相关文件、范例和工具的工具包
    2. DirectX Runtime:一组动态链接库,用于开发和运行DirectX应用程序。

    DirectX中的API可以按照功能性质分为以下4个部分:

    1. 显示部分:Direct Graphics负责图形处理,也称为Direct3D,包含DirectDraw和Direct3D。
      1. DirectDraw主要负责2D图像加速。
      2. Direct3D主要负责3D效果的显示。
    2. 输入部分:DirectInput接口对象可以处理游戏用户输入事件的快速响应,支持多种游戏设备的输入。DirectInput提供了大量接口函数处理游戏杆以及鼠标、键盘和力反馈游戏控制器等其他相关设备的输入,由于其直接与硬件驱动程序打交道,因此可较快地处理用户的输入。
    3. 声音部分:DirectAudio是声音处理的主要API,包括DirectSound和DirectMusic两部分。
      1. DirectSound可实现多个声音的混合播放,并提供3D声效和录音功能。
      2. DirectMusic组件用来处理数字音频,.wav文件或其他音频资源可以由DirectMusic加载器加载。
    4. 网络部分:DirectPlay支持具有网络功能的游戏开发,提供了多种连接方式,如TCP/IP、IPX、MODEM和串口等,玩家可以用各种联网方式进行对战,也提供网络对话功能及保密措施。

    应用程序、Direct3D以及硬件间的关系

    在这里插入图片描述应用程序调用Direct3D(D3D)方法,D3D方法通过HAL层指示设备完成某些操作,最终实现对设备的操作。
    显卡品种具有丰富的多样性,为了让D3D能够始终按照统一的规范进行编程,因此各设备制造商将产品支持的功能写入HAL层中,供Direct3D 调用。HAL是Direct3D和图形设备之间的中间环节硬件抽象层(Hardware Abstraction Layer,HAL),封装了指示设备完成某些操作的代码。

    DirectX的发展史

    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基础知识

    左手坐标系

    Direct3D默认使用左手坐标系,左手手背朝自己,手掌向上竖直。坐标系中的 +x 轴 朝向为左手大拇指的指向, +z 轴 朝向从手心穿进, +y 轴 朝向为四指朝向。如图所示,+z方向指向屏幕里,+y方向竖直向上,+x方向向右。

    顶点缓存与索引缓存

    顶点缓存是包含顶点数据的连续内存空间。索引缓存是包含索引数据的连续内存空间。顶点缓存和索引缓存可以被放置在显存或内存中。绘制时,使用显存中的数据比使用内存中的数据要快得多。

    深度缓存

    深度缓存算法是由Catmull在1975年提出的,基本思想是对当前点(x,y)保持到目前为止遇到的最小z值,以求出具有最小z值的点。
    深度缓存是一个后台缓存,缓存中只存储场景深度信息,而不包含图像数据的表面信息。绘制图元时,将图元的深度信息和深度缓存中的内容加以比较,如果深度信息小于深度缓存中的内容(该图元更靠近视点),就更新深度缓存和颜色缓存的内容;如果深度信息大于深度缓存,则该像素不可见,直接抛弃。
    深度缓存通过对每一个图元给予一个深度值的方式,来判断哪些图元被遮住。

    模型表示

    Direct3D的图形绘制是通过一个称作 Direct3D 渲染流水线的过程来完成的。在整个绘制过程中,首先提供描述三维物体模型的顶点数据及其他的场景元素,然后经过Direct3D渲染流水线的处理,最终得到能够显示在屏幕上的像素。

    图元

    所有的物体模型都是通过多边形网格逼近表示,这些多边形网格是构成物体模型的基本单元,可以是三角形或四边形,通常选用的几何图形种类是三角形。通常这些构成物体模型的三角形为三角形图元,此外还有点图元。
    Direct3D在描述三角形图元时,需要指定三角形单元的3个顶点的列表,该列表包含顶点的位置以及其他一些信息(如颜色等)。在描述由三角形图元构成的物体时,需要指定构成该物体的三角形图元列表。
    ![[Pasted image 20231013144557.png|750]]

    FVF灵活顶点格式

    顶点结构定义好之后,需要用FVF(灵活顶点格式,Flexible Vertex Format)来描述在顶点缓冲区的顶点存储格式中包含哪些属性。灵活顶点格式的作用是,使应用程序只使用它需要的顶点数据,排除那些它不需要的组成成分。通过D3DFVF的组合,可以描述图元顶点的格式。
    顶点格式指定:

    ![[Pasted image 20231013153543.png|700]]
    顶点格式指定的顺序要求:
    ![[Pasted image 20231013153624.png|700]]

    三角形图元

    三角形图元是构成3D物体的基本组成部分,在 Direct3D中,所有物体均可以由三角形逼近拟合来构成。
    一个完整的模型通常是由多个三角形图元构成的三角形网格,需要使用三角形图元列表来存储。每个三角形图元由3个顶点构成。
    如图所示,一个正方形共有6个顶点,需要两个三角形图元来构成,顶点列表为Vertex vertexList[6].(v0,v1,v2,v3,v4,v5),其中有两个顶点重复。当物体形状复杂、描述物体用到的三角形数目非常大时,重复的顶点会占用大量的存储空间,造成资源浪费。为防止这种情况发生,引入了[[#顶点索引列表]]。
    三角形顶点的指定顺序称为绕序(Winding Order)。Direct3D 中规定:

    1. 顶点排列顺序为顺时针的三角形单元是朝向正面的。
    2. 顶点排列顺序为逆时针的三角形单元是朝向背面的。

    顶点索引列表

    顶点索引链表是为了避免共用顶点数较多时,重复顶点的储存占用大量的储存空间。顶点的索引在三维形体绘制中尤为重要,索引列表决定了三角形单元的构成与朝向。
    首先为需要绘制的图形建立顶点列表,再建立一个指向该顶点列表的索引列表,这些索引规定了三角形单元的顶点组织方式,当Direct3D绘制图形时,会根据这些索引结构创建三角形列表,并进一步构建三角形网络。
    以左图的五边形网格体为例,其顶点结构、和索引链表如右图。
    ![[Pasted image 20231013220804.png|inl|209]]![[Pasted image 20231013220748.png|inl|675]]

    Direct3D绘制流水线

    在 Direct3D中,在屏幕上绘制任何物体都要通过一系列变换的流水线,Direct3D绘制流水线主要包括变换和照明(T&L阶段)、光栅化处理两个阶段:

    1. 变换和照明阶段:将每个对象的顶点从局部坐标系变换到基于像素的屏幕坐标系,并考虑虚拟摄像机的属性。另外还可以对顶点应用照明、裁剪、视口缩放等效果。从原始模型顶点数据到添加了照明效果的顶点数据的处理过程如下图所示,图中的非T&L顶点就是原始模型顶点数据。

    ![[Pasted image 20231013223546.png|525]]

    1. 光栅化处理阶段:将这些经过转化并添加了照明效果的顶点组织为点、线和三角形,由光栅化处理程序将绘制结果显示在屏幕上,同时应用纹理映射并添加多种属性。光栅化处理程序同时决定深度缓冲的结果,判断哪些像素是用户可见的,哪些被其他像素所遮挡。

    局部坐标系

    局部坐标系描述了模型的方向及构成物体的元素(点、三角形、子模型)相对于物体中心的位置。在创建模型时,模型各顶点的坐标是相对于局部坐标系描述的,当模型旋转或移动时,与该模型相关联的局部坐标系将随之旋转或移动。

    世界坐标系

    将模型放置在要绘制的场景中,整个场景的坐标系就是世界坐标系,场景中的每个模型的坐标系就是自己独立的局部坐标系。场景中的所有模型都必须从自己的局部坐标系变换到世界坐标系中,用以定义场景中模型之间的空间相对关系。场景中光源的坐标使用世界坐标系定义。
    对于一个在场景中不断运动的模型,就需要为该模型定义一个随时间变化的变化序列,以便在每一帧中确定该模型在世界坐标系中的不同位置。
    将位于局部坐标系中的物体变换到世界坐标系中,需要通过世界变换运算。该变换通常包括平移、旋转和比例缩放,分别用于设置物体在世界坐标系中的位置、方向和大小。

    平移矩阵

    设某点P坐标值为(x,y,z),将该点向x轴方向移动dx,向y轴方向移动 dy,向z轴方向移动 dz,变换后P’点坐标值为(x’,y’,z’),则有x’=x+dx;y’=y+dy;z’=z+dz。将点的平移以矩阵表示:

    ![[Pasted image 20231013225250.png|450]]

    旋转矩阵

    将旋转矩阵传给 Direct3D,经过坐标转换后就可以看到模型旋转效果。Direct3D提供了D3DXMatrixRotationXD3DXMatrixRotationYD3DXMatrixRotationZ函数来计算模型绕x、y和z三个坐标轴旋转的矩阵。

    绕z轴旋转

    模型绕z轴旋转时,z坐标值不会发生变化,仅有x和y坐标值发生变化。等同于在z=0平面上绕原点的旋转变换。设空间中任意一点 P(x,y,z)z 轴旋转 θ角,变为P'(x',y',z'),如下图所示:
    ![[Pasted image 20231014214646.png|400]]在这里插入图片描述

    ![[Pasted image 20231014192500.png|550]]

    绕x轴旋转

    模型绕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轴旋转时,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轴的正方向一致,同时将世界坐标系中的所有几何体都随着摄像机一同进行旋转,来保持摄像机视场的恒定。变换后的几何体被称为“位于观察坐标系中的几何体”。

    ![[Pasted image 20231014201330.png|475]]

    消隐

    消隐的目的是剔除那些处于屏幕背面或物体内部的面,具体哪些面需要隐藏与观察位置有密切关系,即相对于观察位置,前面的面可见、背面或被其他面遮挡的面则不可见。
    早期的面消隐算法是深度排序法,这种方法是把屏幕设成背景色,再把各个面按照离视点的远近进行排序,按照由远到近的顺序逐层绘制。
    现在常用的消隐算法是z-缓冲算法,z-缓冲算法对显示设备上每一个像素进行判断,对每一个像素检查所有的三角形面,判断其在该像素上是否可见。z-缓冲算法使用更新缓冲存储器存储屏幕上所有点的像素值,使用Z缓冲存储器存储屏幕上所有点的z值。
    每当有一个新的图元被转换到屏幕坐标系中,在开始着色之前,GPU会计算新像素到摄像机之间的距离,并与已经存储在z-缓冲存储器中的z值进行比较。如果新的像素离摄像机更近,就把旧的像素替换掉,把新的深度值记入z-缓冲存储器,把新像素的颜色值记入更新缓冲存储器。
    在消隐阶段,还会对图元的朝向进行判断。

    光照

    光源定义在世界坐标系中,变换到观察坐标系中进行计算。

    裁剪

    裁剪就是将视域外的几何体剔除掉的过程,Direct3D 的裁剪过程被包含在投影过程中,在定义投影变换矩阵的同时,定义取景体的范围,Direct3D通过裁剪过称剔除位于取景体外的物体模型部分,并将剩下的三维场景投影到一个二维平面上。

    投影

    投影,是把n维空间中的点投射到小于n维的空间中的变换过程。把摄像机观察到的三维景象显示在二维的平面上,这种三维到二维的变换就是投影变换。正交投影和透视投影是两种常见的投影变换:

    1. 在正交投影中,投影向量与观察平面垂直,模型坐标沿观察坐标系的z轴平行投影到观察平面上,观察点和观察平面的距离不影响物体的大小。正交投影在现实世界中是不存在的,在现实世界中,越远的物体看起来会越小。正交投影主要应用于工程制图,通常所说的三视图就是用三种常见的正交投影(正视投影、顶视投影和侧视投影)得到的。
    2. 在透视投影中,三维物体在二维空间中呈现出近大远小的特征,符合人眼的视觉投影规律。

    视口变换

    视口变换(viewport transform)是空间变换的最后一步,视口变换就是通过定义屏幕显示区域的实际宽、高等参数,将顶点从投影坐标转换为以像素为单位的屏幕坐标,最终完成从投影窗口到屏幕中某一区域的变换,这一区域也被称为视口。
    在游戏中,视口通常是整个屏幕,但视口也可以是屏幕上的某一块矩形区域。视口与其所在的窗口相关,并且通过所在窗口的相对坐标来进行描述。

    ![[Pasted image 20231014212225.png|300]]

    其中X、Y表示视口矩形相对于屏幕的位置,Width、Height表示视口区域的大小,MinZ、MaxZ表示深度缓存中的最小深度值和最大深度值,深度范围设置在[0,1]区间内。
    虚拟摄像机的可见视域模型如下图所示,可见视域外的物体都是不可见的。视椎体的主要参数包括视角的水平范围、垂直范围、投影窗口和远、近裁剪面。其中,投影窗口是一个二维区域,位于视域体中的三维几何体通过投影映射到该区域中,从而实现三维物体的二维显示。在 Direct3D中,将投影平面定义为平面z=1。

    ![[Pasted image 20231014213228.png|475]]

    渲染

    渲染也称光栅化,渲染的目的是计算每个三角形图元像素的颜色值,并最终绘制三角形图元,渲染的最终结果是显示在屏幕上的2D图像。光栅化的本质是矢量图像素化的过程,或者说是将连续的图像用像素点阵来表示,并显示在屏幕上的过程。

  • 相关阅读:
    C++ 窗体程序初步(全网最全)
    Python机器学习实战-特征重要性分析方法(4):相关性分析(附源码和实现效果)
    七天进阶elasticsearch[one]
    都说“存算分离”好,分布式数据库为何还要“进一步分离”?
    安装搭建私有仓库Harbor
    SpringBoot中异常处理
    C++:构造函数与析构函数
    网络的配置
    计算机毕业设计django基于python企业对账分析系统(源码+系统+mysql数据库+Lw文档)
    【群智能算法改进】一种改进的棕熊优化算法 IBOA算法[1]【Matlab代码#64】
  • 原文地址:https://blog.csdn.net/L_Chee/article/details/133844497