一般用到的渲染模式有以下四种:不透明、裁剪半透明(CutOut)、半透明(Fade)、漫反射半透明(Transparent)
代码设置如下:
// 各个渲染模式的设置,和枚举RenderingMode对应
public static RenderingSettings[] modes =
{
new RenderingSettings(){
queue = RenderQueue.Geometry, // 不透明
renderType = "",
srcBlend = BlendMode.One,
dstBlend = BlendMode.Zero,
zWrite = true,
},
new RenderingSettings(){
queue = RenderQueue.AlphaTest, // 全透明cutout,会直接裁剪掉透明度未达到阈值的片元
renderType = "TransparentCutout",
srcBlend = BlendMode.One,
dstBlend = BlendMode.Zero,
zWrite = true,
},
new RenderingSettings(){
queue = RenderQueue.Transparent, // 淡入半透明, 无论漫反射还是高光都进行半透明处理
renderType = "Transparent",
srcBlend = BlendMode.SrcAlpha,
dstBlend = BlendMode.OneMinusSrcAlpha,
zWrite = false,
},
new RenderingSettings(){
queue = RenderQueue.Transparent, // 半透明,只对漫反射进行半透明处理。如玻璃,则不需要对高光进行半透明处理
renderType = "Transparent",
srcBlend = BlendMode.One, // 已在片元着色器提前用透明度对漫反射进行处理,这里用One,来避免对高光进行透明度处理
dstBlend = BlendMode.OneMinusSrcAlpha,
zWrite = false,
},
};
渲染顺序:
渲染队列(RenderQueue):
1:不透明物体
渲染队列用RenderQueue.Geometry(2000);
打开深度写入,这样才能有效遮挡住比自己远的片元;
混合因子:
srcBlend用one(本次渲染的片元颜色占比百分百)
dstBlend用zero(完全舍弃color buffer的值)
(默认混合公式:最终颜色 = srcBlend * 本片元颜色 + dstBlend * 颜色缓冲区的颜色),可用BlendOp关键字来更改混合公式
2:裁剪半透明(CutOut,要不就全透明,要不就不透明)
渲染队列用RenderQueue.AlphaTest(2450);
打开深度写入,仅有未被裁剪的片元会进行深度写入;
混合因子:
srcBlend用one(本次渲染的片元颜色占比百分百)
dstBlend用zero(完全舍弃color buffer的值)
核心代码:
在片元着色器里做以下处理
float alpha = surface.alpha;
// 判断是否是透明度cutout模式
#if defined(_RENDERING_CUTOUT)
// 裁剪掉不符合阈值的片元
clip(alpha - _Cutoff);
#endif
3:半透明(Fade)
直接对本次渲染出来的片元的颜色与颜色缓冲区里的颜色进行半透明混合
渲染队列用RenderQueue.Transparent(3000);
关闭深度写入,因为被半透明物体挡住的物体也需要渲染;
混合因子:
srcBlend用SrcAlpha(片元的透明度)
dstBlend用OneMinusSrcAlpha(1-片元透明度)
4:半透明(Transparent,仅对漫反射做半透明处理,能做出玻璃的效果)
渲染队列用RenderQueue.Transparent(3000);
关闭深度写入,因为被半透明物体挡住的物体也需要渲染;
混合因子:
srcBlend用One(不对本次渲染的片元颜色进行处理,避免影响原本颜色的高光,而漫反射则在片元着色器中提前作处理)
dstBlend用OneMinusSrcAlpha(1-片元透明度)
核心代码:
在片元着色器里做以下处理
float3 viewDir = normalize(_WorldSpaceCameraPos - i.worldPos.xyz); // 视线方向
float3 _SpecularTint;
// 1 - 反射率
float oneMinusReflectivity;
// 确保漫反射的材质反射率加上高光反射的反射率不超过1,并得出高光反射的反射率
float3 albedo = DiffuseAndSpecularFromMetallic(surface.albedo, surface.metallic, _SpecularTint, oneMinusReflectivity); // 金属工作流
// 判断是否是半透明(仅调整漫反射的模式)
#if defined(_RENDERING_TRANSPARENT)
// 在这里提前用透明度处理漫反射,而在混合(Blend)的时候采用One OneMinusSrcAlpha的模式,来避免处理高光
albedo *= alpha;
// 能量守恒问题,一道光照射到物体表面,反射出来的光越多,则通过它的光越少,越不透明。
// 即当反射率是0(没有反射)的时候透明度不变,当反射率是1(完全反射)的时候透明度是1(完全不透明)
// 设反射率是r,即最终透明度a = a + (1 - a) * r = a + r - ra 而oneMinusReflectivity = 1 - r
// 所以有1 - oneMinusReflectivity + alpha * oneMinusReflectivity = 1 - (1-r) + a * (1 - r) = a + r - ra = a + (1 - a) * r
alpha = 1 - oneMinusReflectivity + alpha * oneMinusReflectivity;
#endif