DX学习笔记(三):渲染流水线

渲染流水线

平行线最终会相交于消失点,又称为灭点

物体重叠:即不同命的物体能够遮挡住其后侧物体的局部

3D实体对象是通过三角形网格来近似表示的

颜色

分量式乘法:(r,g,b)*(a,b,c)=(ra,gb,bc)

128位颜色

每个分量用浮点表示,即4D向量 (r,g,b,a)

0<=r,g,b,a<=1

DirectXMath库对分量式乘法的支持

1
XMVECTOR XM_CAKKCIBV XMColorModulate (FXMVECTOR C1,FXMVECTOR C2);//返回C1*C2
32位颜色

每个分量仅分配1个字节,因此每个占用8字节的颜色分量就分别描述256种不同的颜色强度

即0代表无强度,256代表最大强度

DirectXMath(include<DirectXPackedVector.h>)DirectX::PackedVector命名空间提供了相应函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
namespace DirectX
{
namespace PackedVector
{
struct XMCOLOR
{
union
{
struct
{
uint8_t b; // Blue: 0/255 to 255/255
uint8_t g; // Green: 0/255 to 255/255
uint8_t r; // Red: 0/255 to 255/255
uint8_t a; // Alpha: 0/255 to 255/255

};uint32_t c;
XMCOLOR() = default;

XMCOLOR(const XMCOLOR&) = default;
XMCOLOR& operator=(const XMCOLOR&) = default;

XMCOLOR(XMCOLOR&&) = default;
XMCOLOR& operator=(XMCOLOR&&) = default;

XM_CONSTEXPR XMCOLOR(uint32_t Color) : c(Color) {}
XMCOLOR(float _r, float _g, float _b, float _a);
explicit XMCOLOR(_In_reads_(4) const float *pArray);

operator uint32_t () const { return c; }

XMCOLOR& operator= (const uint32_t Color) { c = Color; return *this; }
}
}
}
}

通过将[0,255]映射到[0,1]即可完成32位到128位的转换

转换函数

1
XMVECTOR XM_CALLCONV XMLoadColor( const XMCOLOR* pSource);
1
void XM_CALLCONV XMStoreColor( XMCOLOR* pDestination, FXMVECTOR V );

渲染流水线概述

渲染流水线(rendering pipeline)是以摄像机位观察视角而生成的2D图像的一系列完整步骤

输入装配阶段

输入装配阶段:从显存中读取集合数据(顶点和索引,vertex and index)

再装配为几何图元(几何基元),如三角形和线条

  • 顶点缓冲区:将顶点与渲染流水线绑定的特殊结构体
图元拓扑(primitive topology)
1
2
virtual void STDMETHODCALLTYPE IASetPrimitiveTopology( 
_In_ D3D12_PRIMITIVE_TOPOLOGY PrimitiveTopology) = 0;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
typedef 
enum D3D_PRIMITIVE_TOPOLOGY
{
D3D_PRIMITIVE_TOPOLOGY_UNDEFINED = 0,
D3D_PRIMITIVE_TOPOLOGY_POINTLIST = 1,
D3D_PRIMITIVE_TOPOLOGY_LINELIST = 2,
D3D_PRIMITIVE_TOPOLOGY_LINESTRIP = 3,
D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST = 4,
D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP = 5,
D3D_PRIMITIVE_TOPOLOGY_LINELIST_ADJ = 10,
D3D_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ = 11,
D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ = 12,
D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ = 13,
D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST = 33,
D3D_PRIMITIVE_TOPOLOGY_2_CONTROL_POINT_PATCHLIST = 34,
D3D_PRIMITIVE_TOPOLOGY_3_CONTROL_POINT_PATCHLIST = 35,
D3D_PRIMITIVE_TOPOLOGY_4_CONTROL_POINT_PATCHLIST = 36,
D3D_PRIMITIVE_TOPOLOGY_5_CONTROL_POINT_PATCHLIST = 37,
D3D_PRIMITIVE_TOPOLOGY_6_CONTROL_POINT_PATCHLIST = 38,
D3D_PRIMITIVE_TOPOLOGY_7_CONTROL_POINT_PATCHLIST = 39,
D3D_PRIMITIVE_TOPOLOGY_8_CONTROL_POINT_PATCHLIST = 40,
D3D_PRIMITIVE_TOPOLOGY_9_CONTROL_POINT_PATCHLIST = 41,
D3D_PRIMITIVE_TOPOLOGY_10_CONTROL_POINT_PATCHLIST = 42,
D3D_PRIMITIVE_TOPOLOGY_11_CONTROL_POINT_PATCHLIST = 43,
D3D_PRIMITIVE_TOPOLOGY_12_CONTROL_POINT_PATCHLIST = 44,
D3D_PRIMITIVE_TOPOLOGY_13_CONTROL_POINT_PATCHLIST = 45,
D3D_PRIMITIVE_TOPOLOGY_14_CONTROL_POINT_PATCHLIST = 46,
D3D_PRIMITIVE_TOPOLOGY_15_CONTROL_POINT_PATCHLIST = 47,
D3D_PRIMITIVE_TOPOLOGY_16_CONTROL_POINT_PATCHLIST = 48,
D3D_PRIMITIVE_TOPOLOGY_17_CONTROL_POINT_PATCHLIST = 49,
D3D_PRIMITIVE_TOPOLOGY_18_CONTROL_POINT_PATCHLIST = 50,
D3D_PRIMITIVE_TOPOLOGY_19_CONTROL_POINT_PATCHLIST = 51,
D3D_PRIMITIVE_TOPOLOGY_20_CONTROL_POINT_PATCHLIST = 52,
D3D_PRIMITIVE_TOPOLOGY_21_CONTROL_POINT_PATCHLIST = 53,
D3D_PRIMITIVE_TOPOLOGY_22_CONTROL_POINT_PATCHLIST = 54,
D3D_PRIMITIVE_TOPOLOGY_23_CONTROL_POINT_PATCHLIST = 55,
D3D_PRIMITIVE_TOPOLOGY_24_CONTROL_POINT_PATCHLIST = 56,
D3D_PRIMITIVE_TOPOLOGY_25_CONTROL_POINT_PATCHLIST = 57,
D3D_PRIMITIVE_TOPOLOGY_26_CONTROL_POINT_PATCHLIST = 58,
D3D_PRIMITIVE_TOPOLOGY_27_CONTROL_POINT_PATCHLIST = 59,
D3D_PRIMITIVE_TOPOLOGY_28_CONTROL_POINT_PATCHLIST = 60,
D3D_PRIMITIVE_TOPOLOGY_29_CONTROL_POINT_PATCHLIST = 61,
D3D_PRIMITIVE_TOPOLOGY_30_CONTROL_POINT_PATCHLIST = 62,
D3D_PRIMITIVE_TOPOLOGY_31_CONTROL_POINT_PATCHLIST = 63,
D3D_PRIMITIVE_TOPOLOGY_32_CONTROL_POINT_PATCHLIST = 64,
D3D10_PRIMITIVE_TOPOLOGY_UNDEFINED = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED,
D3D10_PRIMITIVE_TOPOLOGY_POINTLIST = D3D_PRIMITIVE_TOPOLOGY_POINTLIST,
D3D10_PRIMITIVE_TOPOLOGY_LINELIST = D3D_PRIMITIVE_TOPOLOGY_LINELIST,
D3D10_PRIMITIVE_TOPOLOGY_LINESTRIP = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP,
D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST,
D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP,
D3D10_PRIMITIVE_TOPOLOGY_LINELIST_ADJ = D3D_PRIMITIVE_TOPOLOGY_LINELIST_ADJ,
D3D10_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ,
D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ,
D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ,
D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED,
D3D11_PRIMITIVE_TOPOLOGY_POINTLIST = D3D_PRIMITIVE_TOPOLOGY_POINTLIST,
D3D11_PRIMITIVE_TOPOLOGY_LINELIST = D3D_PRIMITIVE_TOPOLOGY_LINELIST,
D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP,
D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST,
D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP,
D3D11_PRIMITIVE_TOPOLOGY_LINELIST_ADJ = D3D_PRIMITIVE_TOPOLOGY_LINELIST_ADJ,
D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ,
D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ,
D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ,
D3D11_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST = D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST,
D3D11_PRIMITIVE_TOPOLOGY_2_CONTROL_POINT_PATCHLIST = D3D_PRIMITIVE_TOPOLOGY_2_CONTROL_POINT_PATCHLIST,
D3D11_PRIMITIVE_TOPOLOGY_3_CONTROL_POINT_PATCHLIST = D3D_PRIMITIVE_TOPOLOGY_3_CONTROL_POINT_PATCHLIST,
D3D11_PRIMITIVE_TOPOLOGY_4_CONTROL_POINT_PATCHLIST = D3D_PRIMITIVE_TOPOLOGY_4_CONTROL_POINT_PATCHLIST,
D3D11_PRIMITIVE_TOPOLOGY_5_CONTROL_POINT_PATCHLIST = D3D_PRIMITIVE_TOPOLOGY_5_CONTROL_POINT_PATCHLIST,
D3D11_PRIMITIVE_TOPOLOGY_6_CONTROL_POINT_PATCHLIST = D3D_PRIMITIVE_TOPOLOGY_6_CONTROL_POINT_PATCHLIST,
D3D11_PRIMITIVE_TOPOLOGY_7_CONTROL_POINT_PATCHLIST = D3D_PRIMITIVE_TOPOLOGY_7_CONTROL_POINT_PATCHLIST,
D3D11_PRIMITIVE_TOPOLOGY_8_CONTROL_POINT_PATCHLIST = D3D_PRIMITIVE_TOPOLOGY_8_CONTROL_POINT_PATCHLIST,
D3D11_PRIMITIVE_TOPOLOGY_9_CONTROL_POINT_PATCHLIST = D3D_PRIMITIVE_TOPOLOGY_9_CONTROL_POINT_PATCHLIST,
D3D11_PRIMITIVE_TOPOLOGY_10_CONTROL_POINT_PATCHLIST = D3D_PRIMITIVE_TOPOLOGY_10_CONTROL_POINT_PATCHLIST,
D3D11_PRIMITIVE_TOPOLOGY_11_CONTROL_POINT_PATCHLIST = D3D_PRIMITIVE_TOPOLOGY_11_CONTROL_POINT_PATCHLIST,
D3D11_PRIMITIVE_TOPOLOGY_12_CONTROL_POINT_PATCHLIST = D3D_PRIMITIVE_TOPOLOGY_12_CONTROL_POINT_PATCHLIST,
D3D11_PRIMITIVE_TOPOLOGY_13_CONTROL_POINT_PATCHLIST = D3D_PRIMITIVE_TOPOLOGY_13_CONTROL_POINT_PATCHLIST,
D3D11_PRIMITIVE_TOPOLOGY_14_CONTROL_POINT_PATCHLIST = D3D_PRIMITIVE_TOPOLOGY_14_CONTROL_POINT_PATCHLIST,
D3D11_PRIMITIVE_TOPOLOGY_15_CONTROL_POINT_PATCHLIST = D3D_PRIMITIVE_TOPOLOGY_15_CONTROL_POINT_PATCHLIST,
D3D11_PRIMITIVE_TOPOLOGY_16_CONTROL_POINT_PATCHLIST = D3D_PRIMITIVE_TOPOLOGY_16_CONTROL_POINT_PATCHLIST,
D3D11_PRIMITIVE_TOPOLOGY_17_CONTROL_POINT_PATCHLIST = D3D_PRIMITIVE_TOPOLOGY_17_CONTROL_POINT_PATCHLIST,
D3D11_PRIMITIVE_TOPOLOGY_18_CONTROL_POINT_PATCHLIST = D3D_PRIMITIVE_TOPOLOGY_18_CONTROL_POINT_PATCHLIST,
D3D11_PRIMITIVE_TOPOLOGY_19_CONTROL_POINT_PATCHLIST = D3D_PRIMITIVE_TOPOLOGY_19_CONTROL_POINT_PATCHLIST,
D3D11_PRIMITIVE_TOPOLOGY_20_CONTROL_POINT_PATCHLIST = D3D_PRIMITIVE_TOPOLOGY_20_CONTROL_POINT_PATCHLIST,
D3D11_PRIMITIVE_TOPOLOGY_21_CONTROL_POINT_PATCHLIST = D3D_PRIMITIVE_TOPOLOGY_21_CONTROL_POINT_PATCHLIST,
D3D11_PRIMITIVE_TOPOLOGY_22_CONTROL_POINT_PATCHLIST = D3D_PRIMITIVE_TOPOLOGY_22_CONTROL_POINT_PATCHLIST,
D3D11_PRIMITIVE_TOPOLOGY_23_CONTROL_POINT_PATCHLIST = D3D_PRIMITIVE_TOPOLOGY_23_CONTROL_POINT_PATCHLIST,
D3D11_PRIMITIVE_TOPOLOGY_24_CONTROL_POINT_PATCHLIST = D3D_PRIMITIVE_TOPOLOGY_24_CONTROL_POINT_PATCHLIST,
D3D11_PRIMITIVE_TOPOLOGY_25_CONTROL_POINT_PATCHLIST = D3D_PRIMITIVE_TOPOLOGY_25_CONTROL_POINT_PATCHLIST,
D3D11_PRIMITIVE_TOPOLOGY_26_CONTROL_POINT_PATCHLIST = D3D_PRIMITIVE_TOPOLOGY_26_CONTROL_POINT_PATCHLIST,
D3D11_PRIMITIVE_TOPOLOGY_27_CONTROL_POINT_PATCHLIST = D3D_PRIMITIVE_TOPOLOGY_27_CONTROL_POINT_PATCHLIST,
D3D11_PRIMITIVE_TOPOLOGY_28_CONTROL_POINT_PATCHLIST = D3D_PRIMITIVE_TOPOLOGY_28_CONTROL_POINT_PATCHLIST,
D3D11_PRIMITIVE_TOPOLOGY_29_CONTROL_POINT_PATCHLIST = D3D_PRIMITIVE_TOPOLOGY_29_CONTROL_POINT_PATCHLIST,
D3D11_PRIMITIVE_TOPOLOGY_30_CONTROL_POINT_PATCHLIST = D3D_PRIMITIVE_TOPOLOGY_30_CONTROL_POINT_PATCHLIST,
D3D11_PRIMITIVE_TOPOLOGY_31_CONTROL_POINT_PATCHLIST = D3D_PRIMITIVE_TOPOLOGY_31_CONTROL_POINT_PATCHLIST,
D3D11_PRIMITIVE_TOPOLOGY_32_CONTROL_POINT_PATCHLIST = D3D_PRIMITIVE_TOPOLOGY_32_CONTROL_POINT_PATCHLIST
} D3D_PRIMITIVE_TOPOLOGY;

示例

1
2
3
4
5
6
//通过线列表来绘制对象
mCommandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_LINELIST);
//通过三角形列表来绘制对象
mCommandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
//通过三角形带来绘制对象
mCommandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
  • 点列表 D3D_PRIMITIVE_TOPOLOGY_POINTLIST
  • 线条带 D3D_PRIMITIVE_TOPOLOGY_LINESTRIP
  • 线列表 D3D_PRIMITIVE_TOPOLOGY_LINELIST
  • 三角形带 D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP

  • 剔除(culling)问题:奇数与偶数三角形的绕序(环绕顺序)即装配图元的顶点顺序是不同的

CPU会对偶数三角形的前两个顶点顺序进行调换已达到有奇数三角形绕序相同

正确的应该是后两个顶点顺序调换,而OpenGL中才是前两个顶点调换

  • 三角形列表

D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST

三角形列表与三角形带的区别是,三角形列表的三角形可以彼此分离,所以每n*3个顶点组成n个三角形

  • 具有邻接数据的图元拓扑

对于有邻接数据的三角形列表,每个三角形都有3个与之相邻的邻接三角形

借助顶点缓冲区索引缓冲区将它们随主三角形一并提交至渲染流水线

并且要把拓扑类型指定为D3D12_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ让渲染流水线知道如何以顶点缓冲区的顶点来构建主三角形和其邻接三角形;

邻接图元的顶点只作为集合着色器的输入数据,并不会被绘制

索引
1
2
3
4
Vertex quad[6]={
v0,v1,v2,//三角形0
v0,v2,v3 //三角形1
};
  • 绕序:为三角形指定顶点顺序

顶点列表索引列表组合起来构成三角形

1
2
3
4
5
6
7
8
9
10
11
Vertex v[9]={v0,v1,v2,v3,v4,v5,v6,v7,v8};
UINT indexList[24]={
0,1,2,
0,2,3,
0,3,4,
0,4,5,
0,5,6,
0,6,7,
0,7,8,
0,8,1
}

顶点着色阶段

  • 世界变换:将局部坐标系内的坐标转换到世界坐标系
  • 世界矩阵:上述变换的矩阵

$$
W=SRT
$$

  • 观察空间:相机的局部坐标系,亦称视觉空间、摄像机空间等
  • 取景变换:世界空间至观察空间的变换;此变换的矩阵叫做观察矩阵

观察矩阵函数

1
2
3
4
5
6
inline XMMATRIX XM_CALLCONV XMMatrixLookAtLH
(
FXMVECTOR EyePosition,
FXMVECTOR FocusPosition,
FXMVECTOR UpDirection
)

示例

1
2
3
4
5
6
XMVECTOR eyePos=XMVectorSet(100,100,100,1);
XMVECTOR target=XMVectorZero();
XMVECTOR up=XMVectorSet(0,1,0,0);
XMMATRIX V=XMMatrixLookAtLH(eyePos,target,up);//返回观察矩阵
XMVECTOR v2=XMVector3TransformCoord(target,V);
cout<<v2;//输出得到(0,0,173.2),即在观察空间的坐标
  • 顶点的投影线:顶点到观察点的连线
  • 透视投影变换:3D顶点v变换至其投影线与3D投影平面的交点v

近平面(近裁剪面)n,远平面f,垂直视场角α,纵横比r,4个参数定义了以原点作为投影的中心,以Z轴进行观察的平截头体

纵横比
$$
r=w/h
$$
w:投影窗口的宽度

h:投影窗口的高度

如果后台缓冲区与投影窗口纵横比不一致,在映射的过程中会产生非均匀缩放(不等比例缩放),导致图像拉伸

  • NDC:规格化设备坐标(Normalized Device Coordinates)

  • 透视除法(齐次除法):顶点与投影矩阵相乘以后,对每个坐标除以w=z

  • 归一化深度值:通过函数 g(z)z坐标从[n,f]映射到区间[0,1]

$$
g(z)=A+ {B \over z}
$$

  • 透视投影矩阵

$$
P=\begin{bmatrix}1\over rtan({\alpha \over 2}) & 0 & 0 & 0\
0 & 1\over{tan({\alpha\over 2})} & 0 & 0 \
0 & 0 & f\over {f-n} & 1 \
0 & & 0 & -nf\over{f-n} & 0
\end{bmatrix}
$$

在顶点乘以投影矩阵后,集合体会处于所谓的齐次裁剪空间或者投影空间

完成透视除法以后,便是**规格化设备坐标(NDC)**了

  • XMMatrixPerspectiveFovLH
1
2
3
4
5
6
7
inline XMMATRIX XM_CALLCONV XMMatrixPerspectiveFovLH
(
float FovAngleY, //用弧度值表示的垂直视场角
float AspectRatio, //纵横比:宽度/高度
float NearZ, //近平面距离
float FarZ//到远平面距离
)

示例

1
2
XMMATRIX M2=XMMatrixPerspectiveFovLH(0.25f*XM_PI,1092/1080,1.0,1000);
cout<<M2;

2.41421 0 0 0
0 2.41421 0 0
0 0 1.001 1
0 0 -1.001 0

曲面细分阶段

利用镶嵌化处理技术对网格中的三角形进行细分,以此来增加物体表面上的三角形数量。

再将这些新增的三角形偏移到适当的位置,使网格表现出更加细腻的细节

  • 曲面细分的优点
  1. 实现LOD
  2. 在内存中只维护低模,在有需求时动态增添三角形,从而节省资源
  3. 处理动画和物理时使用低模,渲染时使用处理过的高模

几何着色器阶段

几何着色器阶段接受输入是完整的图元

与顶点着色器相比,几何着色器可以创建或者修改几何体

比如,将一个点或者一条线扩展为一个四边形

裁剪

对视锥体之外的物体进行裁剪

苏泽兰-霍奇曼裁剪算法

光栅化阶段

光栅化阶段(RS,栅格化):投影主屏幕上的3D三角形计算出对应的像素颜色

  • 视口变换:裁剪完成后,硬件通过透视除法将物体从齐次空间变换为规格化设备坐标(NDC)。此后顶点x、y坐标会以像素单位表示
  • 背面剔除:将背面朝向的三角形从渲染流水线中除去
  • 透视矫正插值:为得到2D空间的顶点的插值属性,对3D空间的三角形属性进行线性插值,即利用三角形属性计算出内部像素的属性
  • 像素着色器阶段(pixel shader):针对每个像素片段进行处理,根据顶点的差值属性作为输入来计算像素颜色,亦可实现如逐像素光照(per-pixel lighting)、反射以及阴影等复杂效果
  • 输入合并阶段:上述阶段生成的像素片段送至渲染流水线的输出合并阶段(OM)。丢弃部分像素(如未通过深度测试等),剩下的写入后台缓冲区,执行混合(blend)操作(透明效果也混合实现的)