9.1 渲染路径
在project setting 里面可以设置默认的渲染路径,但是在每个摄像机上面也可以设置,从而覆盖默认的渲染路径
常见的LightMode:
9.1.1 前向渲染
前向渲染的光照模型分为两种:一种是LightMode="ForwardBase" 一种是LightMode="ForwardAdd"
FB:只渲染一次,只进行最亮的逐像素光照渲染,以及所有逐顶点光照和SH光照
需要添加的宏定义:
#pragma multi_compile_fwdbase 获取相应的光照变量
FA:其它每个逐像素的光照,都要渲染一次
需要添加的宏定义:
#pragma multi_compile_fwdadd、#pragma multi_compile_fwdadd_fullshadows
9.1.2 延迟渲染
延迟渲染是把数据渲染到G-Buffer中,通过两个pass来完成,第一个pass不进行光照计算,只进行把数据处理后存储到G-Buffer中,这个G-Buffer包含多个渲染纹理用来分别存储法线、位置、深度信息等,在第二个pass中进行光照计算
延迟渲染不受光源的影响,只和屏幕的大小有关,屏幕大,则数据多,延迟渲染对硬件有一定的要求,需要支持MRT,因为它把不同的数据存储到不同的RT里面
9.2 光源类型
一个物体能接受的逐像素光源是有限的的,这个设置在quality面板,默认接受除最亮的平行光之外的四个逐像素光照,这个和shader mode也是有关的,不同的shader mode 处理光照的能力是不同的,也就是说如果你有其它满足逐像素光照条件的光源(比如 render mode 设置为 important),就会按照光照强度的排列顺序,从高到低依次渲染,直到达到逐像素的光源限制数量或者逐像素光源的数量
9.3 光源衰减
在内置渲染管线中,光源的衰减和光源强度、与光源的距离两者有关,在URP、HDRP中,光源的衰减只和光源强度有关,和距离无关,这一系列都是内置渲染管线
unity的光源衰减是通过对一张光源衰减图根据距离进行采样获得的,然后与漫反射、高光反射的和相乘
平行光没有衰减,所以衰减系数为1
_LightMatrix0 是从世界空间到光源空间的旋转矩阵,通过距离的平方,采样,然后通过 UNITY_ATTEN_CHANNEL 来获取衰减的值
9.4 阴影
阴影分为两个部分,一个是投射阴影,一个是接收阴影
9.4.1 投射阴影
unity 使用的是屏幕空间阴影投射方式,通过摄像机的深度贴图和一张shadow map,生成一张屏幕阴影贴图(包含了屏幕空间的阴影信息)
摄像机的深度贴图,在延迟渲染中是本来就存在的,但是在前向渲染中,如果通过base pass和 add pass 得到,比较浪费性能,所以通过LightMode 为 shadow caster 的pass 专门来渲染深度纹理信息,它记录了离摄像机最近的表面信息,比如点的位置,法线等
另一张是shadow map ,这是一张把摄像机放在光源位置,得到的一张深度图,它也是只记录了离它最近的表面信息,这张shadow map 是一个RT,所以屏幕空间纹理技术,需要设备支持MRT
最后一张是屏幕空间阴影贴图,包含了场景中阴影信息的,首先,我们通过摄像机的深度贴图得到该点的世界空间坐标,从而获得到光源距离,然后用该点的xy对shadow map 进行纹理采样,获取到shadow map 中存储的深度值,如果该深度值小于 原来的距离,则说明 该点处于阴影中,那么绘制阴影贴图的时候,就要按阴影来绘制
Coding Labs :: Deferred Rendering Shadow Mapping
Unity5.X中屏幕空间阴影投射技术(Screenspace ShadowMap)如何产生阴影图? - 知乎
V2F_SHADOW_CASTER :定义阴影投射的变量
TRANSFER_SHADOW_CASTER_NORMALOFFSET(V2F)
SHADOW_CASTER_FRAGMENT(V2F)
默认的物体的投射阴影只投射物体的正面,可以开启two side 开启双面阴影投射
9.4.2 接收阴影
物体要接收阴影,就是对阴影贴图纹理进行采样,然后和(漫反射+高光反射)*shadow
SHADOW_COORDS(TexcoordsIdx):声明一个插值器
TRANSFER_SHADOW(V2F):根据不同的平台,转换顶点坐标从模型坐标转换到光源空间,存储到上面声明的插值器中
SHADOW_ATEENUATION
缺点:
上述可以通过级联阴影解决
9.4.3 统一管理光照衰减和阴影
UNITY_LIGHT_ATTENUATION(atten,v2f,v2f.worldPos)
atten 就是我们最后的值,这个方法把衰减和阴影相乘的值赋予到attention 上,然后我们就可以直接用了
#param multi_compile_fulladd 只在base pass中计算一次逐像素的阴影
如果想在additional 里面叠加其它逐像素的光照阴影的话,就要添加变量#param multi_compile_fulladd_fullshadows
9.4.4 透明物体的阴影
透明物体的阴影 主要是shadow map的生成上,要进行透明度测试,fallback 采用内置的Transparent/VertexLit
10.1 立方体纹理
立方体纹理六张图,物体可以对其采样,从而在表面形成一层倒影
unity 把当前场景渲染到cubemap,
Camera.RenderToCubemap
10.1.1 反射
通过反射方向 对 立方体纹理进行采样
然后采样结果和漫反射结果混合
texCUBE(cubemap,reflectDir).rgb,对立方体纹理采样
10.1.2 折射
这里直接用的是第一次折射方向,对立方体纹理采样,实际上应该是第二次折射方向
折射满足 斯涅耳定律
refract(-normalize(worldViewDir),normalize(worldNormal),refractRatio)
第三个参数是两种介质的折射率的比值
上述计算的是折射方向
10.2 渲染到纹理
渲染到纹理一共有三种方法
1.创建一张RT,然后让摄像机渲染到该RT上
2.使用GrabPass 生成一张】
3.在OnRenerImage函数里获取当前屏幕图像
10.2.1 镜子效果
对屏幕图像采样,然后翻转x 的uv坐标
10.2.2 玻璃效果
玻璃效果就是对像素进行一个扰动
首先使用GrabPass得到当前的裁剪空间下的坐标,并不是NDC坐标,取值范围是[near,far]
o.screenPos=ComputeGrabScreenPos(o.worldPos)
然后对法线贴图进行采样,得到的是切线空间下的切线
然后用该切线对裁剪空间下的屏幕坐标进行偏移,然后得到该屏幕坐标的NDC坐标,范围在[0,1]之间 ,再用这个坐标对折射贴图采样,得到的是折射贴图的颜色
然后把法线转换到世界空间下,得到反射贴图的颜色,最后混合
切线空间-世界空间的旋转矩阵,先得到世界空间下的法线和切线,然后再通过叉乘得到副切线,然后按列排列
10.2.3 程序纹理
生成一个texture2D