第1篇 初识庐山真面目——Unity 3D Shader 2
第1章Shader(着色器)的概念和在3D游戏中的作用 2
1.1 Shader的概念 2
1.1.1虚拟世界中的光明和色彩 2
1.1.2游戏开发人员的终点 2
1.1.3 Shader(着色器)简史 2
1.2 Shader的实例化 3
1.3 Shader的实现语言 3
1.3.1 GPU上的编程 3
1.3.2 Unity中的着色器编程 3
第2章Unity中Shader(着色器)的形态 4
2.1 Unity通过ShaderLab来组织Shader 4
2.1.1关键字Shader 4
2.1.2使用SubShader组织Shader的不同实现 4
2.1.3 SubShader的重要标签 4
2.1.4 SubShader中的Pass块 5
2.1.5 Pass块的标签及其名字的意义 5
2.1.6使用FallBack保证Shader的广泛适应性 6
2.2 Unity的ShaderLab所支持的Shader编程语言 6
2.3 Unity中Shader的3种形态 6
2.3.1固定管线 6
2.3.2可编程Shader 7
2.3.3 ShaderLab的骄傲:Surface Shader 8
2.4 Shader的数据接口:属性和uniform变量 8
2.4.1在Propeties块中定义属性 8
2.4.2通过图形界面操作属性 9
2.4.3通过脚本操控属性 9
2.4.4矩阵:不能在属性块定义的变量 10
2.4.5在Cg代码中使用属性 10
第3章Shader(着色器)中用到的各种空间概念 11
3.1模型空间 11
3.1.1为什么用模型空间 11
3.1.2在脚本和Shader中进出模型空间 11
3.2世界坐标空间 11
3.2.1统一表达:世界坐标空间 11
3.2.2在脚本和Shader中进出世界坐标空间 12
3.3视空间 12
3.3.1渲染的需要:视空间 12
3.3.2在脚本和Shader中进出视空间 12
3.4空间的一块:视锥体 12
3.5剪切空间 13
3.5.1投影 13
3.5.2脚本和Shader中的投影矩阵 13
第4章 基本的光照模型 14
4.1光源对物体照明的分类 14
4.1.1间接照明 14
4.1.2直接照明 14
4.2照明的计算方式:光照模型 14
4.2.1漫反射和Lambert 14
4.2.2镜面高光和Phong 15
4.2.3半角向量和BlinnPhong 16
第2篇 让你的应用更炫彩——Unity中的照明 18
第5章 第一个被执行的Pass 18
5.1不同的LightMode被选择的顺序 18
5.1.1渲染路径和Pass的LightMode标签 18
5.1.2设计可以检测渲染路径的材质 18
5.1.3设计便于检测渲染路径的场景 21
5.1.4 VertexLit渲染路径下Pass的执行 21
5.1.5 Forward渲染路径下Pass的执行 21
5.1.6 Deferred渲染路径下Pass的执行 21
5.1.7不同渲染路径下的Pass执行规则总结 22
5.2 3个渲染路径之外 22
5.2.1 LightMode的其他值 22
5.2.2设计检测用的材质 23
5.2.3 Always类型的Pass在3种渲染路径下的执行 24
5.2.4 LightMode的默认值及其在3种渲染路径下的执行 25
第6章VertexLit渲染路径 26
6.1顶点照明 26
6.1.1什么是顶点照明 26
6.1.2存取光源的变量 26
6.2顶点照明和Unity存放光源的第一种方式 27
6.2.1用于调试输出的材质 27
6.2.2设计用于检测的场景 27
6.2.3在Vertex Pass中的检测结果 28
6.2.4无效数据 28
6.3顶点照明和Unity存放光源的第二种方式 29
6.3.1用于调试输出的材质 29
6.3.2设计用于检测的场景 30
6.3.3在Vertex Pass中的检测结果 30
6.4顶点照明和Unity存放光源的第三种方式 31
6.4.1 Unity为Vertex Pass准备的光源 31
6.4.2设计用于检测的场景 31
6.4.3顶点照明中的点光源 32
6.4.4计算顶点照明的ShadeVertexLights函数 32
6.4.5顶点照明中的Pixel光源 33
6.4.6顶点照明中的平行光 33
6.4.7顶点照明中的灯光信息小结 35
6.4.8一个顶点照明的实现例子 35
第7章Forward渲染路径 37
7.1 ForwardBase和ForwardAdd 37
7.1.1设计检测用的场景和材质 37
7.1.2 ForwardBase和ForwardAdd的表现 39
7.2 Forward渲染路径下的重要光源 39
7.2.1设计检测用的材质 39
7.2.2不存在Pixel光源时的情况 40
7.2.3存在Pixel平行光时的情况 40
7.2.4存在Pixel点光源时的情况 40
7.2.5有多种类型的Pixel光源时的情况 41
7.2.6 Forward渲染路径下的Pixel光源小结 41
7.3重要光源在ForwardAdd内的执行 41
7.3.1设计用来检测Pixel光源的材质 41
7.3.2设计检测用的场景 44
7.3.3检测结果:ForwardAdd如何被执行 44
7.4 ForwardBase和Unity存放光源的第一种方式 45
7.4.1设计检测用的材质 45
7.4.2第一种方式内的Vertex点光源 46
7.4.3第一种方式内的平行光 46
7.4.4第一种方式内的重要Pixel点光源 46
7.4.5只有ForwardBase时的情况总结 47
7.4.6 ForwardAdd对ForwardBase内光源的影响 47
7.4.7有ForwardAdd时存放光源数据第一种方式的总结 49
7.5 ForwardAdd和Unity存放光源的第一种方式 49
7.5.1设计检测用的材质 49
7.5.2设计检测用的场景 50
7.5.3 ForwardAdd内的Pixel光源 50
7.5.4 ForwardAdd内的平行光 51
7.5.5数组变量unity4LightPos的使用情况分析 51
7.6 Forward渲染路径和Unity存放光源的第三种方式 51
7.6.1检测ForwardBase内情况的材质 51
7.6.2检测结果:第三种方式不包含对ForwardBase有效的数据 52
7.6.3检测结果:第三种方式不包含对ForwardAdd有效的数据 52
7.7 Forward渲染路径总结 53
7.7.1 Forward渲染路径下材质的适应性 53
7.7.2 Unity如何为Forward渲染路径设置光源 53
第8章 基于光照贴图的烘焙照明 54
8.1单光照贴图和VertexLit渲染路径 54
8.1.1测试烘焙的场景 54
8.1.2烘焙场景中使用的材质 55
8.1.3烘焙的前提:静态物体 55
8.1.4如何在烘焙中使用自发光材质 55
8.1.5烘焙之后静态物体和非静态物体的实时照明 57
8.1.6应用光照贴图到VertexLit渲染路径下的材质中 57
8.1.7通过自己的材质改变实时光源对烘焙后物体的照明 59
8.2在效果和性能间进行权衡 60
8.2.1影响全局的Resolution选项 60
8.2.2影响单个物体的Scale In Lightmap选项 61
8.3单光照贴图和Forward渲染路径 62
8.3.1单光照贴图在VertexLit和Forward下面的不同表现 62
8.3.2准备可应用于烘焙的自发光材质 62
8.3.3在ForwardBase内计算光照贴图 64
8.3.4 Forward渲染路径下烘焙之后的实时照明 65
8.4单光照贴图在Deferred渲染路径下的实时阴影 67
8.5双光照贴图和Deferred渲染路径 67
8.5.1全局GI、间接照明以及双光照贴图 67
8.5.2混合双光照贴图和实时照明 67
8.5.3观察混合过程 69
8.5.4双光照贴图的使用限制 70
8.6双光照贴图和Forward渲染路径 71
8.7方向光照贴图和Forward渲染路径 71
8.7.1烘焙后的凹凸问题 71
8.7.2方向光照贴图(Direction Lightmaps)和凹凸贴图 72
第9章 基于LightProbes的照明 74
9.1初识LightProbes 74
9.1.1 LightProbes照明的优点 74
9.1.2检测LightProbes照明的场景 74
9.1.3使用Light Probe Group进行管理 76
9.1.4烘焙场景光照信息到LightProbes中 76
9.1.5对比Light Probes照明和实时照明 77
9.2放置LightProbes的注意事项 77
9.2.1必须形成一个体积 77
9.2.2单个Light Probe必须处于采样光源的照射范围 77
9.3动态更新LightProbes 78
9.3.1跟新数据的注意事项 78
9.3.2更改不同通道的Coeffcient 78
9.4照明采样的Archor Override 79
9.4.1基于线性插值的采样 79
9.4.2改变默认的插值位置 79
9.5 LightProbes照明和阴影 80
9.5.1 LightProbes和光照贴图的异同 80
9.5.2烘焙阴影时可能会犯的错误 80
9.5.3将静态物体的阴影烘焙到Light Probe上 81
9.5.4 LightProbes照明和实时阴影的混合 82
9.6烘焙一个色彩丰富的场景 82
9.7在自己的材质中使用LightProbes 83
9.7.1为Forward渲染路径的材质计算LightProbes 84
9.7.2使用ShadeSH9函数 84
9.7.3在一个Surface Shader中进行计算 85
第3篇 使应用更逼真——Shadows(阴影) 88
第10章 平面阴影 88
10.1平行光对平面的投影 88
10.1.1对平行光投影的考虑 88
10.1.2进出阴影接受平面的矩阵 88
10.1.3使用三角形相似计算阴影 89
10.2点光源对平面的投影 90
10.3阴影的淡出 91
10.3.1有效利用计算平面阴影过程中的数据 91
10.3.2潜在的问题 91
第11章 球体阴影 92
11.1平行光对球体的投影 92
11.1.1投影球体的信息 92
11.1.2使用相似三角形计算投影 92
11.2阴影的淡入/淡出 93
11.3点光源对球体的投影 94
第12章 体积阴影 95
12.1将顶点沿某一方向挤出 95
12.1.1在Vertex函数中操作 95
12.1.2判断顶点是向光还是背光 95
12.2从Volumes中找到阴影区域 96
12.2.1两次挤出 96
12.2.2计算出阴影区域 97
12.2.3渲染阴影 97
12.2.4需要注意的问题 98
第13章 阴影映射 99
13.1灯光空间和相机空间 99
13.1.1观察两个空间 99
13.1.2两个视角的Z深度 99
13.1.3渲染Z深度的材质 99
13.2投射Z深度 100
13.2.1准备灯光视角的投影矩阵 100
13.2.2在材质中计算投影后的Z深度 101
13.3比较Z深度 103
13.3.1比较Z深度的材质 103
13.3.2 Z精度引起的问题 104
13.3.3增加Z的精度 104
13.3.4对Z值进行偏移 105
第14章 内置的阴影 107
14.1投射阴影 107
14.1.1使用ShadowCaster投射阴影 107
14.1.2 ShadowCaster里都做了什么 108
14.1.3写一个自己的ShadowCaster 108
14.1.4改变ShadowCaster的行为 109
14.1.5阴影和FallBack机制 110
14.2接受阴影 111
14.3 Surface Shader和阴影 112
14.3.1 Surface Shader的阴影和Fallback 112
14.3.2 Surface Shader里的灯光参数和阴影 112
14.3.3 Surface Shader对Forward渲染路径下阴影的支持 112
第4篇Unity中的各种Shader 116
第15章Pass的通用指令开关 116
15.1使用LOD在运行时决定材质 116
15.1.1材质的LOD 116
15.1.2运行时设定单个材质的LOD 116
15.1.3设定全局所有材质的LOD 117
15.1.4 Unity内置的LOD层级 118
15.2渲染队列 118
15.2.1标签队列和渲染顺序 118
15.2.2渲染队列和ZTest判断 120
15.2.3 Unity中内置的渲染队列 120
15.3透明的产生 120
15.3.1 Alpha检测和8种比较条件 120
15.3.2动态生成A1phaTest的材质 120
15.3.3动态生成Shader的内容 121
15.3.4结合AlphaTest和Blend操作 122
15.4混合操作 123
15.4.1什么是混合(Blend)操作 123
15.4.2动态生成测试用的材质 123
15.4.3生成Shader的代码 124
15.4.4检测不同的混合操作 125
15.4.5 BlendOp选项 126
15.4.6动态生成带BlendOp选项的材质 126
15.4.7生成Shader的代码 127
15.4.8检测BlendOp操作 127
15.5使用通道遮罩(ColorMask) 128
15.5.1 ColorMask的作用 128
15.5.2检测ColorMask 128
15.5.3一个使用ColorMask的例子 129
15.6 ZTest(深度测试) 130
15.6.1存取场景的ZTest 130
15.6.2 RenderType标签和生成ZTest的关联 130
15.6.3内置RenderType的值 131
15.6.4 Forward渲染路径下的ZTest 131
15.6.5 Deferred渲染路径下的ZTest 132
15.7对Z深度的偏移 134
15.7.1干预正常ZTest的手段 134
15.7.2动态改变Offset的参数 134
15.7.3观察Offset在不同应用条件下的表现 135
15.8面的剔除操作 135
15.9自动贴图坐标的生成 136
15.9.1 ObjectLinear和等价的Cg代码 136
15.9.2 EyeLinear和等价的Cg代码 137
15.9.3 SphereMap和等价的Cg代码 138
15.9.4 CubeReflect和等价的Cg代码 139
15.9.5 CubeNormal和等价的Cg代码 139
15.10抓屏操作 140
15.10.1如何使用GrabPass 140
15.10.2一个模拟曲面反射的例子 141
15.11 Fog(雾效) 142
15.11.1 Fog和Unity的3种实现 142
15.11.2材质中对Fog的控制 142
15.11.3实现自己的Fog 143
第16章 固定管线 146
16.1 Unity中固定管线的基本形态 146
16.1.1基本形态 146
16.1.2与照明相关的Material块 147
16.1.3处理纹理的SetTexture块 147
16.1.4基本形态的另一种写法 147
16.1.5 Combine语句 147
16.2使用顶点色 148
16.2.1使用ColorMaterial 148
16.2.2使用Bind 148
16.3在固定管线中使用光照贴图 149
16.4嵌套Cg代码 149
第17章Surface Shader 151
17.1 Surface Shader的适应性 151
17.1.1一个分析策略 151
17.1.2 VertexLit渲染路径的检测材质 151
17.1.3 Forward渲染路径的检测材质 152
17.1.4测试用的场景 153
17.1.5检测结果:不独立支持VertexLit渲染路径 153
17.1.6检测结果:对Forward渲染路径的有条件支持 153
17.2 Surface Shader和Deferred渲染路径 154
17.2.1设计检测的策略和材质 154
17.2.2检测结果:Surface Shader对Deferred渲染路径的支持条件 156
17.3 Forward渲染路径下的Surface Shader 157
17.3.1 Cg代码完全体 157
17.3.2最简形式的等价Cg代码 158
17.3.3 Cg代码对光照贴图的支持 163
17.3.4一个检测生成的ForwardBase场景 164
17.3.5自动生成的ForwardAdd 165
17.3.6参数noambient和novertexlights 168
17.3.7参数approxvi ew和halfasview 168
17.3.8 Forward渲染路径下的透明和混合模式参数 169
17.3.9加强Forward渲染路径下效果的参数 171
17.4 Deferred渲染路径下的Surface Shader 174
17.4.1自动生成的PrePassBase和PrePassFinal 174
17.4.2 PrePassBase都做了什么 177
17.4.3_ LightBuffer里面的东西 179
17.4.4计算LightBuffer所使用的材质 180
17.4.5 PrePassFinal的工作 185
17.4.6 FallBack和Surface Shader的阴影 186
17.4.7精简用的参数 187
17.4.8 Vertex、finalcolor函数和addshadow选项 188
17.4.9 Deferred模式下的材质透明 188
17.4.10 decal参数 189
第18章 凹凸材质 190
18.1切空间 190
18.2凹凸贴图 190
18.2.1计算到切空间的矩阵 190
18.2.2 Unity中法线贴图的压缩格式 191
18.2.3使用切空间矩阵的另一种方法 191
18.2.4 Unity对切空间计算的支持 192
18.2.5解压缩法线贴图的函数 193
18.2.6在切空间中计算高光 193
18.2.7 Surface Shader和切空间 194
18.3 Parallax Mapping(视差映射) 194
18.3.1 Parallax Mapping及其别名 194
18.3.2一个使用灰度图来偏移UV的材质 195
18.3.3结合法线贴图 196
18.3.4用视角来决定UV偏移 197
18.3.5一个完整的实现 197
18.4 Relief Mapping(地势映射) 198
18.4.1 Parallax Mapping的极限和Relief Mapping的面世 198
18.4.2 Relief Mapping的算法 199
18.4.3一个完整的实现 200
第19章 卡通材质 203
19.1描边 203
19.1.1沿法线挤出轮廓 203
19.1.2容易产生的问题 204
19.1.3在视空间中挤出 205
19.1.4顶点位置的另一个含义 206
19.1.5调和法线和顶点方向 207
19.1.6判断顶点的指向 207
19.1.7不仅仅是轮廓 208
19.1.8通过Z偏移来描边 210
19.2卡通着色 211
19.2.1对光照进行离散化 211
19.2.2使用2D贴图重新映射光照 213
第20章 镜面材质 215
20.1镜像一个相机 215
20.1.1镜子里的世界和我的计划 215
20.1.2在脚本中对位置和角度进行镜像 215
20.2使用镜像相机来渲染、投影 216
20.2.1镜面材质的工作:采样被投影的渲染结果 216
20.2.2脚本的工作:渲染镜像相机和设置投影矩阵 217
20.3镜像相机的近剪切平面和倾斜矩阵 218
20.3.1调节近剪切平面 218
20.3.2使用倾斜矩阵微调视锥体 218
第21章 半透明材质 219
21.1什么是半透明材质 219
21.2用简单来表达复杂 219
第22章 体积雾 221
22.1距离的表达:相对于背景的体积雾 221
22.1.1需要计算的东西 221
22.1.2使用一个Pass来完成所有的计算 221
22.1.3黑色的雾效 222
22.2厚度的表达:物体形体的体积雾 223
22.2.1必须计算的两个数据 223
22.2.2在Unity中使用一个Pass来完成所有计算 223
第23章Wrap Model新解 226
23.1一个可调节的Wrap光照模型 226
23.2另一种实现途径 226
23.2.1基于不同构想的Wrap 226
23.2.2实现这种构想 227
23.2.3进一步的变通 227
第24章 面积光 228
24.1线光源 228
24.1.1点,线,面 228
24.1.2如何理解一个线光源 228
24.1.3通过脚本传递线光源的几何信息 228
24.1.4计算线光源的照明 229
24.1.5线光源的辐射方向 230
24.1.6线光源的衰减 230
24.2面积光源 231
24.2.1面积光和线光源的不同 231
24.2.2通过脚本设定面积光的几何特性 231
24.2.3计算面积光 232
24.2.4和默认照明的整合 234
第25章 体积光 235
25.1体积光和体积阴影 235
25.1.1什么是体积光 235
25.1.2体积光和体积阴影的关系 235
25.2实现体积光 235
25.2.1在Shader中表现体积光 235
25.2.2脚本的帮助 236
第26章 材质替代渲染 238
26.1相机(Camera)和渲染消息 238
26.1.1相机的渲染消息发送顺序 238
26.1.2物体的渲染消息发送顺序 239
26.1.3相机和物体的渲染消息先后顺序 240
26.1.4存在两个相机时的渲染消息 240
26.1.5最后能改变Cull操作结果的地方 241
26.1.6最后能设置材质数据的地方 241
26.2相机(Camera)的渲染方法 242
26.2.1 Render方法 242
26.2.2 RenderWithShader方法 243
26.3如何使用RenderWithShader方法 245
26.3.1标签值不同的5个Shader 245
26.3.2调用RenderWithShader方法的脚本 246
26.3.3替换用的5个材质 247
26.3.4检测RenderWithShader方法的效果 248
26.3.5使用SubShader组织替代材质 249
26.3.6如何设置替代材质的属性 249
26.3.7将结果输出到屏幕上 250
26.4 SetReplacementShader和ResetReplacementShader 251
第27章 后期效果 252
27.1 Graphics的两个方法 252
27.1.1与相机渲染方法的不同之处 252
27.1.2 Blit方法的简单示例 252
27.1.3使用BlitMultiTap方法进行多重采样 254
27.2一个简单的调色 257
27.2.1调色用的脚本 257
27.2.2调色用的材质 258
27.2.3更高效的做法 259
27.3景深 261
27.3.1用于模糊图像的材质 261
27.3.2进行纵横两次模糊操作 262
27.3.3进行混合操作的脚本 263
27.3.4进行混合操作的材质 263
27.3.5提供一个可调节参数 264
27.4轮廓检测 265
27.4.1用脚本索要场景的Z深度和法线 265
27.4.2在材质中进行边缘检测 265
27.5扭曲 267
27.5.1通过UV操作扭曲图像 267
27.5.2限定扭曲的区域 268
27.5.3使用物体来做遮罩 268
27.6运动模糊 271
27.6.1如何记录运动轨迹 271
27.6.2实现运动模糊的材质 271
27.6.3用于完成整个过程的脚本 272
27.6.4通过Alpha和帧的混合操作实现运动模糊 273
27.7噪波 273
27.7.1根据Z深度来混合噪波 274
27.7.2根据明暗程度来混合噪波 274
27.8色彩的溢出 275
27.8.1色彩溢出的算法考量 276
27.8.2实现色彩溢出的采样计算 276
第28章 地形 278
28.1地表的材质 278
28.1.1地面纹理的控制贴图 278
28.1.2如何自定义地表材质 279
28.1.3如何使用更多的纹理贴图 280
28.2花草的材质 280
28.2.1非Billboard类型花草的材质 281
28.2.2 Terrain引擎传入的数据 282
28.2.3 Billboard类型花草的材质 282
28.2.4自定义Detail Mesh的材质 283
28.3树木的材质 283
28.3.1树木的2D Billboard材质 283
28.3.2 3D形态树木的材质 284
28.3.3应用Unity计算的Occlusion 286
第29章 投影 288
29.1 Unity的Projector 288
29.1.1 Projector中的材质被执行的顺序 288
29.1.2如何写Projector使用的材质 288
29.1.3控制投影淡进淡出的矩阵 289
29.2实现自己的投影 290
29.2.1设定投影矩阵的脚本 290
29.2.2采样投影的材质 291
29.2.3直接投影到屏幕上 292
29.2.4模拟GUITexture 293
29.3模拟粒子的广告牌效果 294
29.3.1使用材质将物体面向相机 294
29.3.2保持旋转角度 295
第5篇Shader的组织和优化 298
第30章Shader的组织和复用 298
30.1 cginc文件 298
30.1.1 Unity的Unity CGcginc文件 298
30.1.2定义自己的cginc文件 298
30.1.3使用自定义的cginc文件 299
30.2通过U sePass来复用 300
30.2.1定义自己要复用的Pass 300
30.2.2复用这些Pass 301
30.3定义自己的Shader关键字 301
30.3.1使用关键字改变Shader的行为 301
30.3.2定义自己的Shader关键字 301
30.4使用multi_ compile编译Shader的多个版本 302
30.4.1使用multi_ compile实现多次编译 302
30.4.2在脚本中选择Shader的版本 302
30.5 Unity对DX 11支持所带来的问题 303
第31章 你必须知道的渲染概念 304
31.1逐顶点计算和逐像素计算 304
31.1.1逐顶点计算 304
31.1.2逐像素计算 304
31.1.3如何在这两个概念中取舍 304
31.2 Draw Call的指标意义 304
31.2.1 Draw Call的概念 304
31.2.2正确理解Draw Call对你开发应用的意义 304
31.2.3 Batching的概念和Unity为优化Draw Call所做的工作 305
31.2.4优化Draw Call 305
31.3利用渲染队列的技巧 305
31.3.1渲染队列的概念 305
31.3.2设置Render Queue的技巧 305
第32章 基于渲染路径的优化 306
32.1 VertexLit渲染路径下的优化 306
32.1.1 VertexLit渲染路径的特点 306
32.1.2合理的光照计算 306
32.2 Forward渲染路径下的优化 306
32.2.1 Forward渲染路径的特点 306
32.2.2合理的光照计算 306
32.3 Deferred渲染路径下的优化 307
32.3.1 Deferred渲染路径的特点 307
32.3.2合理的灯光布局 307
第33章 移动平台上的优化 308
33.1移动平台的特点 308
33.2一些指令的运算速度概念 308
33.3几何复杂度的考量 308
33.4贴图的问题 309
33.5数据类型的使用方式 309
33.6变量的使用 310
33.7慎用后期效果 310
33.8慎用透明效果 310
附录 相关资源 311