GPU流水线上可高度编程的阶段,包括表面着色器、顶点片元着色器、固定管线着色器。目前的Unity5中,本质上只有顶点片元着色器
关于渲染流水线:
主要任务:从一个三维场景,渲染出一张二维图像,主要由CPU & GPU协作完成。
渲染流程三个阶段:应用阶段 | 几何阶段 | 光栅化阶段
应用阶段:根据三维场景输出渲染所需要的几何信息(图元:点、线、三角面等)
三个步骤: 1)数据加载到显存。 2)设置渲染状态(使用哪个着色函数、光源属性等)。 3)调用Draw Call(CPU向GPU发起渲染指令)
几何阶段:主要任务是把几何顶点坐标转换到屏幕空间中,然后交个光栅器处理
光栅化阶段:使用上阶段的数据产生屏幕像素,渲染成像。
两个主要任务:
计算每个图元覆盖了哪些像素
计算这些像素颜色
Draw Call(GPU流水线):【几何阶段 & 光栅化阶段】
顶点着色器:主要实现顶点空间变换(坐标变换)、可实现定点着色(光照计算)等,基本任务把顶点位置坐标从模型空间转换到裁剪空间
曲面细分着色器:可选,细分图元,需要显卡支持。使模型看起来更细腻
裁剪:不在摄像机视野内的物体在此阶段被裁剪掉
屏幕映射:坐标转换(三维->二维),但需要记录下坐标深度、法线方向、视角方向等,跟用于显示的屏幕分辨率有关。
三角形设置:计算三角网格表示数据的过程,为计算三角面覆盖的像素准备数据
三角形遍历:检查每个像素是否被一个三角网格覆盖并生成图元。输出片元序列
片元着色器:输入,顶点着色器输出数据的插值。输出,一个或多个颜色值。纹理采样
逐片元操作:片元–>模板测试–>深度测试–>混合–>颜色缓冲
1 | OpenGL |
着色器语言:
1)Direct X的HLSL(High Level Shading Language)
2)OpenGL的GLSL
3)NVIDIA的CG
4)Unity使用的是ShaderLab
重要的数学基础:
1)矢量点积
几何意义:投影
a * b = |a| * |b| * cosQ b在a上的投影
2)矢量叉积
几何意义:a X b得到同时垂直于a&b的新矢量
用途:计算垂直于一个平面、三角形的矢量。判断三角面的朝向
3)矩阵
几何意义:坐标变换(平移、缩放、旋转等,分别对应一变换矩阵)
用途:坐标空间变换
4)坐标空间
ShaderLab语法
基本结构:
1 | Shader "Custom Shaders/Simple Shader" { |
CG中的语义:
基本光照&光照模型:
环境光:通常是一个全局变量
自发光:
漫反射(兰伯特光照模型):
高光(镜面)反射(Phong光照模型):
光照模型:
Lambert模型:用来描述漫反射
1
2
3计算公式:Cdiffuse = (Clight * Mdiffuse ) Max(0, n * I)
n:表面法线;I:指向光源的单位矢量;Mdiffuse:材质的漫反射颜色;Clight:光源颜色Phong模型:模拟高光,可让物体表现出光斑
计算公式:1
mgloss:是材质光泽度,mspecular:材质的高光反射颜色,Clight:光源颜色,v:视角方向,r:反射方向
Blinn-Phong模型:基本原理同Phone,提高了运算效率;目前游戏上较流行的模型
PBR:基于物理的渲染;使用BRDF(双向反射率分布方程):主要描述了光线作用到物体表面后的反射(高光反射Specular)和散射(漫反射Diffuse)
光照计算:
1)逐像素光照:
以每个像素为基础,得到他们的法线(对顶点法线插值得到,或从法线纹理采样得到),然后进行光照计算。
2)逐顶点光照
在每个顶点上计算光照,然后在渲染图元内部进行线型插值,最后输出成像素颜色。 由于顶点数目往往小于像素数目,所以逐顶点光照计算量少些
纹理:
漫反射纹理(漫反射贴图)
凹凸纹理(法线贴图、Heightmap)
渐变纹理
透明效果:
两种实现方式:1)透明度测试 2)透明度混合
透明度测试:不能实现真正的半透明,不需要关闭深度写入,实际上是根据透明度舍弃一些图元,所以他实现的效果要么完全透明,要么不透明。
透明度混合:可以实现真正的半透明,使用当前片元的透明度作为混合因子,与颜色缓存区中的颜色进行混合,得到新的颜色存入颜色缓存区中。需要关闭深度写入,深度缓存是只读的。
透明度混合方式关闭深度写入的原因:深度缓存区的剔除机制。
渲染顺序问题:
从距离摄像机由远及近依次渲染。
不考虑透明物体的情况下,unity使用深度缓冲区(z-buffer)的方式,使我们不用关心场景中物体的渲染顺序。
z-buffer基本思想:根据深度缓冲中的值判断该图片距离摄像机的距离,当渲染一个图元时,需要把他的深度值跟已经存到z-buffer中的值比较,如果距离摄像机更近,则这个片元覆盖掉z-buffer中的值,深度值写入z-buffer中。
Unity Shader的渲染顺序:
采用渲染队列的方式解决:
1 | // 透明度测试 |
Unity 渲染路径
Unity Standard Sharder
1、Rendering Mode
Rendering Mode:在非透明和多种透明效果之间切换。
Opaque:默认,实体渲染。
Cutout:Alpha test,通过贴图的Alpha值缕空模型表面。
Transparent:透明效果,如玻璃,半透明塑料等等。
Fade:在这个模式下,一个对象可以实现淡入淡出效果。
参考:https://docs.unity3d.com/Manual/StandardShaderMaterialParameterRenderingMode.html
2、Albedo
Albedo是一个只拥有颜色信息的“平面”贴图,即不带任何AO,SHADOW等光影信息。是物体的Base Color颜色值。
3、Metallic & Specluar & Smoothness
Specular通过直接赋与颜色的方式来决定高光反射强度。Metallic则通过一个0~1的值,来决定金属的反射强度。
不管是在metallic还是Specular模式下,一但使用了贴图来决定高光反射效果。引擎将会采用贴图中的值,设置的Metallic因子,或者Specular Color均会无效。
Smoothness则决定了一个物体的光滑呈度。 即使一个物体表面高光很强烈。若它是一个不光滑的物体,那么其反射会呈不规则的方向分布,光会分散到不同的地方。那么到达人眼中的反射光就会少。整体的反射效果就会变得很弱。(注:当Metallic或者Specular被赋与贴图后。Smoothness值会失效。 转而采用Matallic或者Specular贴中的Alpha通道作为Smoothness值。)
4、Normal Map
Normal Map是Bump Mapping的一种特例化。 它主要是通过贴图为光照计算时提供更细节的法线信息。使物体表面具有高度的细节效果。如下图所示
5、Heightmap
Heightmap比NormalMap更上一层楼,NormalMap是通过赋与物体表面更多的法线信息,来造成光照上的细节增强。 Normal Map有一个缺点就是,当视线与表面平行时,就失去法线效果。而Heightmap则直接对某些顶点进行位移。由此也可以看出来,Heightmap的效率开销会比Normalmap高,要更据情况选择使用。
高度图是一张灰度图,白色表示突出,黑色表示凹陷。
6、Occlusion Map
Occlusion Map用于决定一个模型各部位受到间隔光照的影响情况。 间隔光照一般来自于Ambient和环境反射。
7、Emission
Emission表示一个物体的自发光程度。默认是纯黑,如果为这个物体赋值了非黑色的材质。 那么这个物体即使在黑暗的场景下,也会有亮光。
8、Detail Mask & Secondary Maps
Secondary Maps用于在物体的表面增加细节。我们可以为一个物体再赋值一套Albedo和NormalMap. 第一套Albedo和第二套Albedo是叠加的。
参考:https://docs.unity3d.com/Manual/StandardShaderMaterialParameterDetail.html
9、Fresnel
Fresnel菲涅尔效果。物体的表面与视线的夹角的不同,会导致眼睛看到的从物体反射出来的光线的反射量不同。
Standard Shader通过Smoothness间接控制菲涅尔反射效果
参考:http://docs.unity3d.com/Manual/StandardShaderFresnel.html
PBR官方参考使用样例:
https://blogs.unity3d.com/2015/02/18/working-with-physically-based-shading-a-practical-approach/