前言
在上篇文章中我们简单实现了一个伪次表面散射模拟效果,这次我们就基于屏幕空间模糊的方式来模拟皮肤的次表面渲染。
实现
大致流程:
- 提取次表面散射对象Mask遮罩。
- 高斯模糊处理 + Mask遮罩。
- 最后和原图叠加。
1.提取皮肤遮罩
这里为了简单方便,直接采用Command Buffer提取需要次表面散射的对象Mask遮罩。
注意这里用了一个纯色Shader处理
C# 代码:
// 纯色Shader
Shader purecolorShader = Shader.Find("lcl/Common/PureColor");
// Shader purecolorShader = Shader.Find("lcl/Common/VertexColor");
if (purecolorMaterial == null)
purecolorMaterial = new Material(purecolorShader);
if (maskTexture == null)
maskTexture = RenderTexture.GetTemporary(Screen.width, Screen.height, 16, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Default, 4);
commandBuffer = new CommandBuffer();
commandBuffer.SetRenderTarget(maskTexture);
commandBuffer.ClearRenderTarget(true, true, Color.black);
for (var i = 0; i < targetObjects.Length; i++)
{
Renderer[] renderers = targetObjects[i].GetComponentsInChildren<Renderer>();
foreach (Renderer r in renderers)
commandBuffer.DrawRenderer(r, purecolorMaterial);
}
原图:
提取结果:
2.高斯模糊后处理
高斯模糊具体可以看之前的一篇文章:Unity Shader - 均值模糊和高斯模糊
模糊效果:
然后乘上Mask遮罩:
//对模糊处理后的图进行uv采样
fixed4 blurCol = tex2D(_BlurTex, i.uv);
// mask遮罩
fixed4 maskCol = tex2D(_MaskTex, i.uv);
blurCol *= maskCol;
3.叠加原图
最后叠加上原图:
//对原图进行uv采样
fixed4 srcCol = tex2D(_MainTex, i.uv);
//对模糊处理后的图进行uv采样
fixed4 blurCol = tex2D(_BlurTex, i.uv);
// mask遮罩
fixed4 maskCol = tex2D(_MaskTex, i.uv);
blurCol *= maskCol;
float fac = 1-pow(saturate(max(max(srcCol.r, srcCol.g), srcCol.b) * 1), 0.5);
// float fac = fixed4(1,0.2,0,0);
return srcCol + blurCol * _SSSColor * _ScatteringStrenth * fac;
原图 | SSS |
4.厚度
吸收(Absorption)是模拟半透明材质的最重要特性之一。
光线在物质中传播得越远,它被散射和吸收得就越厉害。
为了模拟这种效果,我们需要测量光在物质中传播的距离,并相应地对其进行衰减。
可以在下图中看到具有相同入射角的三种不同光线,穿过物体的长度却截然不同。
这里我们就采用外部局部厚度图来模拟该现象,当然,该方法在物理上来说并不准确,但是可以比较简单快速的模拟出这种效果。
烘焙厚度图可以用Substance Painter
或者用Unity的插件:Mesh Materializer把厚度信息存储在顶点色里面。
这里我是直接把厚度信息存储在顶点色里面,输出厚度信息如下:
这里取反了一下,越亮的地方,散射越强。
最终效果:
左边:开启SSS、右边:关闭SSS