DirectX11入门笔记---3D渲染管线

image-20201217210042177

3D渲染管线

渲染管线指:如何将3D场景根据摄像机视角生成2D画面

image-20201219220842650

输入装配阶段

从内存中读取几何数据(顶点和索引)并将这些数据组合为几何图元(三角形,直线等)

顶点

DirectX中的顶点由空间位置和各种附加属性组合而成,我们可以根据自己的需求建立属于我们的顶点格式。

image-20201218215356463

图元拓扑

顶点是以顶点缓冲区的数据结构绑定到图形管线中的,也就是说顶点缓冲区只是存储了一个顶点列表,并没有说以什么方式来组织顶点,顶点中连成直线还是三角形?这时候就需要图元拓扑来告知Directx顶点以什么方式组成几何图元。

void ID3D11Device::IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY Topology);
//比如说设置为直线列表Line list
DirectxDevice->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_LINELIST);

点列表,每个顶点都被绘制成独立的顶点

image-20201218215846709

线带,相邻的顶点会连成一条直线

image-20201218215931439

线列表,每两个顶点会形成一条独立的直线

image-20201218220238401

三角形带,生成连续的三角形

image-20201219121021600

三角形列表,每三个顶点形成独立的三角形

image-20201219121124685

索引

如下面构成三角形会共享许多顶点,当复制顶点的时候会造成存储空间的浪费

Vertex quad[6] ={ 
v0, v1, v2, // Triangle0
v0, v2, v3, // Triangle1 };

Vertex octagon[24] ={ 
v0, v1, v2, // Triangle0 
v0, v2, v3, // Triangle1 
v0, v3, v4, // Triangle2 
v0, v4, v5, // Triangle3 
v0, v5, v6, // Triangle4 
v0, v6, v7, // Triangle5 
v0, v7, v8, // Triangle6 
v0, v8, v1 // Triangle 7 };

不希望对顶点进行复制的原因:

  1. 增加内存需求量。(为什么要多次存储相同的顶点数据?)
  2. 增加图形硬件的处理负担。(为什么要多次处理相同的顶点数据?)

image-20201219121655223

索引就是为了解决这个问题,我们创建一个顶点列表和一个 索引列表。顶点列表包含所有唯一的顶点,而索引列表包含指向顶点列表的索引值,这些索 引定义了顶点以何种方式组成三角形。

Vertex v[4] = {v0, v1, v2, v3};
UINT indexList[6] = {
0, 1, 2, // Triangle0 
0, 2, 3}; // Triangle 1

我们将“复制问题”转嫁给了索引列表,但是这种复制是可以让人接受的。因为:

  1. 索引是简单的整数,不像顶点结构体那样占用很多内存(顶点结构体包含的分量越多,占用的内存就越多)。

  2. 通过适当的顶点缓存排序,图形硬件不必重复处理顶点(在绝大多数的情况下)。

顶点着色器

完成图元装配之后,顶点传入顶点着色器,顶点着色器可以被看成是一个以顶点作为输入输出数据的函数。每个将要绘制的顶点都会通过顶点着色器推送至硬件;

矩阵变换的方法

1.已知A坐标空间下的X Y Z轴以及原点Q在B空间下的表示,则可以构建变换矩阵

image-20201219125412645

2.将A坐标空间与B坐标空间重合,通常B坐标空间的远点并不是我们想放置A的地方,所以我们通过缩放,旋转,平移将A坐标空间放置在B空间确定的位置,可以确定SRT构成的矩阵就是变换矩阵

模型空间

每个模型都有自己的坐标空间,模型空间的原点一般在模型的重心

世界空间

可以理解为游戏空间,将顶点坐标从模型空间变换到世界空间的变换叫模型变换

image-20201219125014123

image-20201219125026311

观察空间(摄像机空间)

在观察空间中,摄像机位于原点,以摄像机的观察方向为Z轴正方向,右侧为X轴,上方为Y轴。

从世界空间到观察空间的坐标变换为:观察变换

image-20201219130700800

同样这里得到变换矩阵的方法有两种:

1.摄像机的原点,X Y Z轴在世界空间的表示我们是可以得到的,这样就可以构建从观察空间到世界空间的变换矩阵,所以逆矩阵就是从世界空间变换到观察空间的变换矩阵

通过摄像机观察方向与世界空间的向上方向构建观察空间在世界空间的坐标轴表示

image-20201219133411662

假设摄像机相对于世界空间的位置为(5, 3, −10),目标点为世界原点(0, 0,0)。我们可以使用如下代码创建观察矩阵:

XMVECTOR pos = XMVectorSet(5,3,-10,1.0f); 
XMVECTOR target = XMVectorZero(); 
XMVECTOR up = XMVectorSet(0.0f,1.0f,0.0f,0.0f); 
XMMATRIXV = XMMatrixLookAtLH(pos,target,up);

2.平移整个观察空间,让摄像机原点与世界坐标原点,坐标轴与世界空间坐标轴重合。

裁剪空间

描述摄像机所能看到的空间范围,通过一个平截头体来描述

image-20201219133825336

定义平截头体

近平面n,远平面f,垂直FOV a,横纵比r。

纵横比 r = w/h,w为宽度,h为高度,注意:投影窗口的纵横比要与后台缓冲区的纵横比一致,否则会出现图像变形,假设h为2,则w=r。

水平FOV b,它是由垂直FOV a和横纵比r决定。

image-20201219173740924

image-20201219173849286

对顶点进行投影

给出一个点 (x, y, z),求它在投影平面 z = d 上的投影点 (xʹ, yʹ, d)。通过下图可以通过相似三角形得到xʹ yʹ。前提条件:假设h为2,则w=r。

image-20201219174747257

image-20201219174816758

当且仅当以下条件成立时,点(x, y , z)在平截头体内。

image-20201219174833941

规范化设备坐标(NDC)

将平截头体缩放到X,Y在[-1,1],Z在[0,1]的立方体内

推导过程

参考文章:https://www.cnblogs.com/bluebean/p/5276111.html

只不过这篇文章是Opengl,Z轴在[-1,1]内,所以我重新推导Directx,有错请多多包涵

已知:近平面d,远平面f,垂直FOV a,横纵比r,宽度w,高度h

根据侧面三角形可得

根据相似三角形可得

这是$x_1,y_1$的范围在$[-\frac{w}{2},\frac{w}{2}]$和$[-\frac{h}{2},\frac{h}{2}]$之间,我们要把范围缩放到[-1,1]内,所以要除以$\frac{w}{2},\frac{h}{2}$即可

假设$z_2$为[0,1],所以我们最后的坐标为

接下来是构建矩阵

可以看到无法求解下列方程,那是因为z当分母的原因

我们只要将最右边向量每一项都乘以z即可

求得矩阵为

我们可以建立方程求解m22,m32

所以最后的矩阵为

在与投影矩阵相乘之后,进行透视除法之前,几何体所处的空间为裁剪空间。透视除法(即每个分量都除以第四个分量w)之后,几何体处于NDC内。

Directx函数得到投影矩阵

image-20201219213147479

曲面细分着色器(可选)

曲面细分(Tessellation)是指通过添加三角形的方式对一个网格的三角形进行细分,这些新添加的三角形可以偏移到一个新的位置,让网格的细节更加丰富。

image-20201219213305777

优点:

  1. 我们可以通过曲面细分实现细节层次(level -of-detai l,LOD),使靠近相机的三角形通过细分产生更多细节,而那些远离相机的三角形则保持不变。
  2. 我们可以在内存中保存一个低细节(低细节意味着三角形数量少)的网格,但可以实时地添加额外的三角形,这样可以节省内存。
  3. 我们可以在一个低细节的网格上处理动画和物理效果,而只在渲染时才使用细分过的高细节网格。

几何着色器(可选)

几何着色器阶段(geometry shader stage)是可选的,几何着色器以完整的图元作为输入数据,几何着色器的主要优势是它可以创建或销毁几何体。

注意:顶点位置在离开几何着色器之前,必须被变换到齐次裁剪空间。

裁剪阶段

我们必须完全丢弃在平截头体之外的几何体,裁剪与平截头体边界相交的几何体,只留下平截头体内的部分,这个时系统自动帮我们完成的,所以我就不深入了解了。

image-20201219213750375

视口变换(屏幕空间)

在裁剪之后,硬件会自动执行透视除法,将顶点从齐次裁剪空间变换到规范化设备空间(NDC)。然后将xy坐标映射到屏幕像素坐标),通常,视口变换不修改 z 坐标,因为 z 坐标还要由深度缓存使用,但是我们可以通过

D3D11_VIEWPORT 结构体的 MinDepthMaxDepth 值修改 z 坐标的取值范围。

光栅化阶段

光栅化(rasterization)阶段的主要任务是为投影后的 3D 三角形计算像素颜色。

背面消隐

一个三角形有两个面。我们使用如下约定来区分这两个面。根据约定好的顶点绕序删除三角形背面,减少GPU负担。

顶点属性插值

我们通过指定三角形的 3 个顶点来定义一个三角形。除位置外,顶点还可以包含其他属性,比如颜色、法线向量和纹理坐标。在视口变换之后,这些属性必须为三角形表面上的每个像素进行插值。这里需要用到透视矫正插值才能插值正确。

image-20201219222735513

像素着色器

像素着色器(Pixel shader)是由我们编写的在 GPU 上执行的程序。像素着色器会处理 每个像素片段(pixel fragment),它的输入是插值后的顶点属性,由此计算出一个颜色。像素着色器可以非常简单地输出一个颜色,也可以很复杂,例如实现逐像素光照、反射和阴影等效果。

输出合并阶段

经过像素着色器处理后的片元会被传输到输出合并阶段,未能通过深度测试和模板测试的片段将会被丢弃,最后通过测试的片元会与后台缓冲区进行混合。

  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2015-2021 Opda
  • 访问人数: | 浏览次数:

请我喝杯咖啡吧~

支付宝
微信