以下内容仅仅记录了《Unity Shader入门精要》这本书中学到的知识点、和一些自己的理解和总结(可能存在错误)

第1、2章

  1. 开篇介绍了Shader的背景和作用,以及这本书的结构(共20章)
  2. 流水线—>渲染流水线(应用阶段、几何阶段、光栅化阶段)
  3. 应用阶段:CPU加载数据到显存—>设置渲染状态—>Draw Call
  4. GPU流水线:几何阶段+光栅化阶段
  5. 几何着色器:逐图元着色
  6. 片元着色器:逐片元着色(片元由三角形遍历后生成)
  7. OpenGL和DirectX屏幕坐标系不同
  8. 逐片元操作/输出合并阶段(模板测试、深度测试、混合)
  9. HLSL(微软)GLSL、CG(跨平台)
  10. Draw Call:命令缓冲区、批处理(适合静态物体)
  11. 固定管线:兼容旧设备

第3章

  1. Unity Shader和材质
  2. Unity Shader的语言:ShaderLab
  3. .shader文件的结构
  4. Properties SubShader(Pass Fallback)的代码举例
  5. 表面着色器 顶点/片元着色器 固定函数着色器
  6. 上述三种着色器的工作方式和适用背景
  7. Unity Shader和传统Shader的区别和联系
  8. Unity Shader和CG/HLSL

第4章

  1. 笛卡尔坐标系:标准正交基、左/右手坐标系
  2. 点、矢量、矢量的运算(点积叉积)
  3. 矩阵、矩阵的运算
  4. 矩阵变换:线性变换(缩放、旋转)、仿射变换(合并了线性变换和平移变换)
  5. 齐次坐标:缩放矩阵、旋转矩阵(zxy)、平移矩阵(依次)
  6. 坐标空间:父空间-子空间
  7. 模型空间/对象空间
  8. 世界空间
  9. 观察空间/相机空间
  10. 裁剪空间(正交/透视)
  11. 屏幕空间:进行标准齐次除法/透视除法
  12. 法线变化
  13. Unity内置的变换矩阵
  14. Unity内置的摄像机和屏幕参数
  15. Unity Shader中矩阵和矢量的定义和运算(左右乘的变化)
  16. 在着色器中获取片元的屏幕坐标

第5章

  1. Unity版本号和环境
  2. 创建场景,Shader->材质->球体
  3. 简单Shader中每一行代码的作用
  4. 使用语义(例如SV_POSITION)作为输入输出
  5. SV_POSITION/SV_TARGET:顶点/片元着色器输出
  6. 结构体的引入,并用于着色器间信息传递(顶点着色器插值后送给片元着色器)
  7. Properties声明属性和使用
  8. Unity内置文件的应用(结构体/函数/变量)
  9. Unity支持的语义列举
  10. Debug方法:假彩色图像/Graphics Debbuger/帧调试器
  11. OpenGL和DirectX平台下Unity对纹理的翻转处理:抗锯齿开启后需要判断情况手动处理翻转
  12. OpenGL和DirectX平台下语法和语义要求的不同(SV_开头的变量使用和参数数量报错等)
  13. Shader规范建议:① float/half/fixed的使用;② shader运算过多报错;③ 避免分支和循环;④ 避免除0
  14. 扩展阅读:《GPU精粹》

第6章

渐入佳境—-光照

  1. 光源(方向,辐射度):吸收、散射
  2. 散射:折射/投射、反射
  3. 高光反射-Specular:反射
  4. 漫反射-Diffuse:折射、吸收、反射
  5. 出射度-辐射度
  6. 光照模型:BRDF、标准光照模型(亦可称为Phong光照模型/Blinn-Phong光照模型)
  7. 标准光照模型(4部分)以下总结均基于此模型:emissive specular diffuse ambient
  8. 环境光-ambient:全局常量
  9. 自发光-emissive:材质自发光颜色
  10. 漫反射-diffuse:兰伯特定律->参数:表面法线方向、光源方向、漫反射颜色、光源颜色
  11. 高光反射-specular:Phong模型->参数:表面法线方向、光源方向、高光反射颜色、光泽度/反光度、观察方向、光源颜色
  12. Blinn模型:参数要求与Phong模型相同,光源方向和观察方向为定值时计算更快,反之较慢,具体结果需要根据不同情况来判断
  13. 逐顶点光照-高洛德着色:在顶点着色器中计算颜色,在片元着色器中插值。计算量小,但有棱角(插值颜色造成),不适用于计算高光
  14. 逐像素光照-Phong着色:得到法向量(插值或法线纹理),在片元着色器中计算颜色
  15. 模型缺陷:不适用物理现象,模型是各项同性的
  16. Unity实现自发光(输出前添加)、环境光(设置并使用)
  17. Unity Shader实现漫反射:逐顶点、逐像素、改进(半兰伯特模型:去掉了Max函数,改进了暗处的变化细节,视觉加强效果)
  18. Unity Shader实现高光反射:逐顶点、逐像素、Blinn光照模型
  19. 使用Unity内置函数替换上述代码中的部分计算过程:其中,方向使用前需要归一化;需要注意适用的渲染方式(如前向渲染);好处是可以处理计算复杂的光照方向(如点光源和聚光灯)。

第7章

基础纹理

  1. 纹理映射/纹素/UV坐标(左下角)
  2. 单张纹理实现:_MainTex(顶点着色器->uv 片元着色器->纹素值)
  3. 纹理详细信息中选项的设置(属性值、平铺模式、滤波模式等)
  4. 2种平铺模式:Repeat、Clamp
  5. 3种滤波模式:Point(最近邻滤波)、Trilinear(线性滤波)、Bilinear(线性滤波+多级渐远纹理技术)
  6. Unity中对纹理的压缩存储
  7. 凹凸映射:高度映射、法线映射
  8. 法线映射:模型空间/法线空间法线映射实现
  9. 上条中不同空间下应用时的优缺点
  10. 切线空间下计算:
  • 顶点着色器:切线空间下的lightDir和viewDir
  • 片元着色器:法线纹理采样得到切线法线、计算颜色
  1. 世界空间下计算:
  • 顶点着色器:切线空间到世界空间的转换矩阵
  • 片元着色器:世界空间的lightDir和viewDir、法线纹理采样得到切线法线并转换到世界空间、计算颜色
  1. 类型为Normal map标识的纹理使用(UnpackNormal)和压缩原理
  2. 渐变纹理:一维纹理,实现过程类似单张纹理
  3. 遮罩纹理:像素级的控制表面属性、实现过程(在计算Specular时采样纹理,作为系数控制高光值)

第8章 透明效果

在这里插入图片描述
在这里插入图片描述

  1. 2种透明效果的实现:Alpha Test、Alpha Blending
  2. 渲染顺序的意义
  3. 使用Unity提供的渲染队列解决不同的排序情景
  4. 透明度测试实现:使用clip函数抛弃texColor.a低于阈值的片元(要么在,要么不在),缺点:渲染边缘效果不好
  5. 透明度混合实现:关闭深度写入,设置混合因子SrcAlpha和1-SrcAlpha,最后透明度1.0改为texColor.a * _AlphaScale,缺点:同一模型的深度被忽略了,导致如图结果,前边无法遮挡后边
    在这里插入图片描述

  6. 在SubShader中增加一个Pass(只写入深度,不输入输出颜色)以修正这个问题 在这里插入图片描述

  7. Blend混合命令的参数、操作、常见混合类型使用
  8. 双面渲染透明效果:关闭深度写入时,使用Cull Off关闭剔除;开启深度写入时,将一个Pass分为2个,先使用Cull Front关闭前方剔除,渲染正面,再使用Cull Back关闭后方剔除,渲染背面,效果如开头图片所示。

第9章 更复杂的光照

总的来说就是增加了光照的衰减、阴影计算,学习处理不同种类的光源(均基于前向渲染路径)。

  1. 渲染路径简述:目前使用2种,前向渲染路径和延迟渲染路径。
  2. 渲染路径的设定和使用:项目设置、摄像机设置、Pass中使用LightMode标签。
  3. 各种LightMode标签名的用途:获取正确的光照变量值。
  4. 前向渲染路径原理:在Pass中计算颜色缓冲区、深度缓冲区。
  5. Unity中对前向渲染路径中光源的限制(光源中设置Render Mode)。
  6. 路径中的2种Pass:Base Pass和Additional Pass在不同类型光照效果实现中的分工。
  7. 设置LightMode后,用到的内置光照变量的列举。
  8. 顶点照明渲染路径:硬件要求低,性能高,效果差(很多效果只能逐顶点计算),是前向渲染的子集。
  9. 延迟渲染路径:利用额外缓冲区G-buffer,缓解前向渲染中由于包含大量实时光源造成的性能瓶颈。
  10. 工作原理:分2个Pass先后进行了片元淘汰(深度测试技术,通过的片元将其需要的信息存入G-buffer)、读取G-buffer并计算光照。
  11. Unity中的延迟渲染路径。
  12. Unity支持的光照类型:平行光、点光源、聚光灯、面光源。
  13. 不同光源中的属性:位置、方向、颜色、强度、衰减。
  14. 多个点光源(Additional Pass)+1个平行光(Base Pass)的shader实现,并配置点光源的Render Mode进行实验对比(使用帧调试器观察渲染过程)。
  15. 光照衰减的原理和实现:衰减纹理采样/数学公式计算(后者有误差)。
  16. 阴影的原理和实现:使用额外的Pass设置LightMode标签为ShadowCaster来计算阴影纹理纹理(将摄像机放置到光源位置后调用该Pass),采样该纹理后与之前的光照结果相乘。
  17. 屏幕空间的阴影映射技术和传统的阴影映射技术对比。
  18. 不透明物体阴影实现(投射阴影):Cast Shadows和Receive Shadows设置,使用Fallback语义计算阴影。
  19. 不透明物体阴影实现(接收阴影):在Shader中使用AutoLight.cginc的SHASOW_COORDS、TRANSFER_SHADOW、SHADOWATTENUATION实现。
  20. UNITY_LIGHT_ATTENUATION :将光照衰减因子和阴影结果使用一个函数共同计算得到fixed atten。
  21. 半透明物体阴影实现:沿用在透明物体效果实现一节中的Shader,加入了阴影因子fixed atten的计算,并配置不同的fallback。
  22. 实现时遇到的问题:AlphaBlend方法实现的半透明物体在渲染时,一旦更改了材质的shader,再改回来也得不到原先的接收的阴影了,未解决。
  23. 本书提供的标准Unity Shader,分别使用了Phong光照模型和Blinn-Phong光照模型,未加入透明效果实现。

第10章 高级纹理

对比之前学习的纹理(一维或二维),本章学习了更为复杂的纹理,包括立体纹理、渲染纹理、程序纹理。

  1. 环境映射:使用立方体纹理实现的反射或折射效果。
  2. 立方体纹理(Cubemap):从6张图像组成的3维立方体纹理中,从中心出发计算角度,然后采样得到颜色值。
  3. 天空盒子实现:创建Skybox类型的材质,使用Unity自带的Shader,在详情界面中选择6个面对应的纹理(Clamp展开)。
  4. 创建立方体纹理的3种方法:直接创建,设置纹理类型为Cubemap;创建Cubemap,赋值6个面;脚本生成。
  5. 脚本生成立方体纹理原理:在指定位置创建一个摄像机,记录6个方向的纹理到创建好的Cubemap中。
  6. 反射效果实现(基于环境映射):选中天空盒子;在模型的位置处使用脚本生成Cubemap;在Shader中使用内置函数reflect计算反射方向(顶点着色器);再由反射方向采样立方体纹理,得到颜色后使用lerp函数与原有颜色混合即为最终颜色(片元着色器)。
  7. 折射效果实现(基于环境映射):同上一步大致相同,不同点在于把反射计算替换为折射计算(引入了折射率)得到不同的采样方向。
  8. 菲涅儿反射实现:使用Empricial菲涅儿近似等式(Scale、视角方向、法线方向),计算了6中lerp函数的混合参数,使得边界处的反射更加真实。
  9. 渲染纹理(Render Texture):将渲染结果暂存到中间缓存中。
  10. 镜子效果实现:建立渲染纹理并附给一个摄像机,然后将纹理赋值给做为镜子的物体,并用shader完成采样时的左右翻转(uv的x值)。
  11. 玻璃效果实现:镜子包括反射和折射;反射效果使用立方体纹理实现,折射效果在使用内置函数对抓取屏幕图像采样后,计算偏移offset实现。
  12. GrabPass{} :抓取屏幕图像的Pass,填入不同的TextureName后可以访问不同物体抓到的不同图像。
  13. 渲染纹理和GrapPass的性能对比、适用场景。
  14. 程序纹理:纹理由代码生成(.cs后缀代码拖给材质,材质拖给模型)。
  15. 程序材质:适用Substance Designer创建的材质,拖入Unity中使用。

第11章 让画面动起来

这一章节的内容介绍了2种让图像移动的方法:根据时间变化,根据视角变化;书中分别列举了2种用途:动画效果(纹理,顶点),广告牌技术(顶点随ciewDir变化)。

  1. Unity中的内置事件变量介绍。
  2. 纹理动画:帧序列、背景滚动。
  3. 帧序列动画:从一张图中,有若干按照行列顺序排布的纹理(2D);在片元着色器中,通过时间函数,移动行列位置,换算为UV值并采样。
  4. 计算过程:首先得到不超过总行列数的行列值,例如一行有8个(8列),则得到的column值为0-7(假设,超过总列数后,由于设置的纹理图像的展开方式,超过了边界也可以正确采样);由于uv值是0-1的浮点数,故可以用cloumn/8来计算偏移;小图像中的纹理位置,由原来的uv值/8得到;将上述的偏移和分割后的纹理位置相加,得到8*8图片序列中的纹理位置。
  5. 背景滚动:书中将2层纹理分别读入后,使用不同的速度水平滚动。
  6. 计算过程:在顶点着色器中,计算UV值时,添加x方向的偏移(随时间增加),片元着色器得到的UV值就是偏移过后的,由此即可得到滚动效果。
  7. 顶点动画:纹理动画中顶点位置时不发生改变的,改变的只有纹理(UV值的变化),顶点动画则加入了顶点的改变,下边列举了2个例子:2D河流效果,广告牌技术。
  8. 河流效果实现:根据预先设定的波动幅度、波动频率(是否波动一致)、波长、河流纹理移动速度,计算得到顶点的移动(以时间为基础);其中需要注意的细节有,关闭批处理、深度写入、剔除;如果想要具有投射的阴影(Fallback中只会的到顶点移动前的阴影,没有动画效果),还需要加入额外的Pass,同样使用上边的参数(不用计算纹理了),利用内置函数计算投影的效果。
  9. 广告牌技术:重点在于计算一个旋转过后的3维正交基(在模型空间中处理旋转),得到旋转后的正交基后分别相乘之前模型空间中,每个点距离锚点(0,0,0)的距离,得到旋转过后的位置,将这个位置使用MVP转换到裁剪空间中即可。
  10. 计算过程:分两种策略,是否固定向上为(0,1,0)。若固定向上方向,则将视角方向的y分量置为0,up x normal 得到 right 方向,3个方向计算完成;若不固定,则将(0,1,0)x normal得到 right 方向,然后由normal和right叉乘得到upDir,其中需要注意的时,如果normal已经和(0,1,0)重合,则将替换为(0,0,1),重复之后的过程。

第12章 屏幕后处理效果

总的来说把渲染出来的结果(Texture),类似于又用PS处理了一下。方法就是把不同的脚本加在摄像机上,脚本和Shader共同使画面具有不同的效果。

  1. OnRenderImage接口和Bilt函数的使用。
  2. 创建基类PostEffectsBase,配置一些check函数。
  3. 调整亮度、饱和度、对比度的实现:分别在脚本中定义3个对应的变量作为变化范围,赋值给Shader,在Shader中的片元着色器中,对每个片元进行计算,达到调整效果。
  4. 边缘检测实现:卷积的介绍(卷积核,卷积计算,卷积的意义,梯度),使用给定的卷积核计算梯度(卷积计算每一个纹素),在片元着色器中使用得到的梯度作为比例(0-1)将原先的Color与边缘颜色进行混合(lerp函数),最后同样使用lerp混合2张含有原图信息/替换背景为纯色的效果图。
  5. 高斯模糊实现:高斯方程的引入,二维高斯核转化为2个一维的权重分布(横向和纵向分开,在Shader中使用2个Pass分别计算),使用实现明确的权重分布(总和为1),将每个片元周围(参数控制,甚至可以取到相邻更远的片元参加运算)的片元rgb值与其相乘,得到结果(这个结果可以多次重复计算,增加模糊程度);以上2个Pass都进行了命名,方便在其他Shader中使用。
  6. Bloom效果实现:用一个阈值,在第1个Pass中将亮度超过阈值的部分减去阈值,其余部分变为0;第23个Pass将上一步得到的区域进行高斯模糊(通过NAME命名调用);第4个Pass将前几步的结果和原图混合,得到最终效果。
  7. 运动模糊实现:为了模仿曝光效果,使用累计缓存的方法,将多张渲染中的RGB信息进行混合(提前设定了A通道值),原有A通道则保留不变(原文为“不希望A通道的值写入渲染纹理”,暂且这样理解的)。

第13、14章 深度和法线纹理、非真实渲染

实现更加贴近应用的渲染效果(运动模糊、雾、卡通风格、素描风格),往往需要更加巧妙的思路和数学计算。

  1. 透视投影和正交投影的原理复习。
  2. 2种获取深度和法线纹理的方法:延迟渲染将纹理存入G-buffer中;正确的设置RenderType,使用单独的Pass渲染得到纹理。
  3. 脚本中相机的设置和纹理获取的代码实现,使用包装好的函数处理纹理采样后得到的线性的深度值。
  4. 使用Frame Debugger查看深度纹理的渲染效果(远裁剪平面太远或太近效果变差)
  5. 使用深度信息实现运动模糊:之前的运动模糊是整个屏幕每一帧渲染结果的叠加。现在的方法改进为,使用顶点的速度信息(6)进行模糊处理(7)。
  6. 速度:当前帧和前一帧的顶点位置(NDC坐标)相减除2。NDC坐标的xy分量为UV计算得到,z分量由解析深度纹理值后得到。难点在于由当前帧的NDC坐标计算前一帧的NDC坐标(使用了2个脚本中预先计算的变换矩阵)。
  7. 模糊处理:在每一个for循环中,延速度*模糊Size的方向迭代UV采样的偏移,累加到当前片元的颜色中。此方法不适用于物体移动而固定摄像机的运动模糊,可在Unity自带的ImageEffect包中寻找更多方法。
  8. 全局雾效:基于深度纹理,在一次屏幕后处理中,实现雾效。
  9. 雾效:共3种计算方法,线性、指数、指数平方;本节使用一个f和1-f混合原始颜色和雾的颜色,属于基于世界坐标高度信息(10)的线性混合,即雾的浓度随像素高度的增加而减小。
  10. 世界坐标/距离信息:以近裁剪面为基础获得4个边角的向量,使用近似三角形原理,带入深度信息后计算出像素点到摄像机的向量信息(片元着色器),摄像机坐标+向量信息得到像素点的世界坐标。难点在于从4个边角向量(顶点着色器)得到像素点摄像机向量(片元着色器)的插值过程,存疑。
  11. 边缘检测:使用Roberts算子,先后计算根据UV值采样得到的深度信息和法线信息,其中法线信息忽略了z分量以简化计算;最终返回0或1表示是否为边缘。
  12. 卡通风格渲染:其中一种方法,基于色调的着色技术,漫反射控制+描边。
  13. 渲染过程:背面,渲染轮廓,使用纯色并适当的延法线方向扩展一小段距离;正面,使用渐变纹理处理漫反射,高光部分使用平滑的插值函数,防止锯齿状的边缘出现,混合得到的颜色并输出即可。
  14. 素描风格渲染:色调艺术映射。若干张素描的纹理(笔画线条的间隔不同)按权重分别采样并混合。
  15. 渲染过程:在顶点着色器中计算漫反射的强度,使用if else判断划分出6个权重并传送给片元着色器;在片元着色器中按权重混合采样后的纹理,1-权重和,得到预设颜色的权重,混合他们得到素描颜色,与光照衰减相乘得到具有阴影效果的最终颜色。
  16. 扩展:文中提到了《大神》《军团要塞》《海岛奇兵》《三国志》等游戏均用到了非真实渲染;推荐读物《艺术化绘制的图形学原理与方法》。

第15章-第20章

  1. 噪声:使用一张噪声纹理实现更多的渲染效果(消融、波浪等)。
  2. 消融效果:对应消融效果的纹理采样后,作为阈值控制当前片元是否被渲染。消融的边缘具有一定的宽度,其中渐变的颜色使用lerp函数混合。
  3. 动态的消融效果需要根据时间改变阈值,通过加在物体上的脚本实现。
  4. 消融后的片元需要同样在ShadowCaster的Pass中剔除,以产生正确的通盈效果。
  5. 水波效果:对应水波效果的纹理采样后,作为切线空间下的表面法线。
  6. 水面透射:GrapPass得到的屏幕纹理,在片元着色器中采样这个纹理得到透射颜色,其中利用法线计算采样时的offset。
  7. 水面反射:反射颜色由这个位置生成的cubemap根据反射方向采样后与主纹理颜色、预设颜色混合得到;反射方向由视角方向和法线方向计算得到。
  8. 波动:随时间修改采样噪声纹理的uv偏移,产生变化的法线方向。
  9. 全局雾效:在之前的雾效基础上,增加一个噪声纹理的采样与雾的浓度相乘,得到不均匀的雾。动态的实现与水波相同,随时间偏移噪声采样坐标即可。
  10. Unity中的渲染优化技术:移动平台与PC的特点对比;CPU、GPU、纹理造成的性能瓶颈及优化方向;Unity的渲染分析工具:渲染统计窗口、性能分析器、帧调试器等;
  11. 具体优化:CPU:利用批处理减少DrawCall的原理;GPU:减少顶点、减少overdraw;纹理:减小大小和使用缩放。
  12. Unity表面着色器:相对于顶点着色器和片元着色器跟高的抽象,更加简短,有利有弊。编译指令:指出表面着色器选哟的表面函数和光照函数、以及一些渲染的设定。结构体Input和SurfaceOutput,存储数据来源和表面属性。
  13. 表面着色器的编译过程和优缺点分析:缺点是自由度低,性能差,可能无法实现自定义的渲染效果;优点是可以便利的处理各种光源,编写简单。
  14. PBS的理论和数学基础:光的反射、此表面散射—>BRDF双向反射函数:计算这些光照的分布。
  15. 漫反射部分:Lambertian BRDF—>Unity5使用的漫反射增加了掠射角和表面粗糙程度的计算。
  16. 高光反射部分:基于Torrance-Sparrow微面元模型,值为:菲涅尔反射函数*法线分布函数*阴影遮盖函数/矫正因子。
  17. Unity中的PBS实现:漫反射部分如15所述;高光反射部分的法线分布函数(GGX模型),阴影遮盖函数(Smith-Schlick模型),菲涅尔反射函数(Schlick菲涅尔近似等式)。
  18. Unity5中的Standard Shader:是对于17的具体实现,按照工作流程分为金属工作流和高光工作流。
  19. 全局光照流水线:直接光照(平行光)+间接光照(前者的来回反射)。
  20. 反射探针:在指定位置获取Cubemap,模拟间接光照中的互相反射效果。
  21. 光线追踪不同于间接光照,只追踪了重要的光照路径。
  22. 预计算实时全局光照:预计算静态物体的光照信息存储到光照纹理、光照探针、Cubemap中。
  23. 伽马校正:线性和非线性的输入输出会产生差异,需要在移动平台上手动校正。
  24. HDR:高动态范围渲染,更加细节的掌握亮度差异,而不是将超过范围的值进行截取。缺点:需要更多存储空间、硬件支持不同。
  25. 第19章:Unity5更新内容。
  26. 第20章:学习资料推荐。