消融这个效果算得上游戏开发中用的比较多的一个效果,表现游戏对象消失的时候经常用到,这个效果实现也非常简单,因此在《UnityShader入门精要》中也就短短几句话讲完了,这里我想针对书中的效果详细讲解一下。
Shader源代码,我这里就不贴出源代码了,可以照着看。
消融效果的核心是使用clip函数,将小于阈值的像素裁剪掉
首先Disslove中包含两个Pass,一个前向渲染、一个阴影渲染,我们下面挨个解析。
参数说明
与消融效果相关的主要有噪声图、阈值。这两个就能实现消融,书中额外使用了Burn Line Width、Burn First Color、Burn Second Color来实现消融前表面先烧焦的效果。
噪声图
这里使用的噪声图类似高斯噪声图,使用这类噪声图可以让消融过渡更加平滑均匀。虽然本书讲的是消融效果,但是我觉得噪声图的选择使用也是一门很值得研究的门道。只要大体符合高斯噪声图规律就能实现比较好的效果。我们只要去拾取噪声图中的像素点,就能发现它们是梯度增加或减少点,这正符合烧毁东西的规律,从多个点扩散
fwdbase顶点着色器
顶点着色器没有什么特别好说明的,计算纹理uv、计算切线空间下的光照方向、计算世界坐标这些对于看了那么久书的你没什么好说明的了。
fwdbase片元着色器
如果只是实现消融,下面代码就能实现
fixed4 frag(v2f i) : SV_Target
{
//1.采样噪声图
fixed3 burn = tex2D(_BurnMap, i.uvBurnMap).rgb;
//2.根据当前Burn(燃烧进度)裁剪片元
clip(burn.r - _BurnAmount);
//计算切线空间下的光照方向与法线
//法线通过UnpackNormal获取,因为需要将采样值映射到[-1,1]区间
//光照方向就是顶点着色器计算后插值后的结果,在frag中再归一化,可以避免精度丢失
float3 tangentLightDir = normalize(i.lightDir);
fixed3 tangentNormal = UnpackNormal(tex2D(_BumpMap, i.uvBumpMap));
//3.采样反照率纹理
fixed3 albedo = tex2D(_MainTex, i.uvMainTex).rgb;
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
//计算漫反射,采用半兰伯特
fixed3 diffuse = _LightColor0.rgb * albedo * max(0, 0.5 * dot(tangentNormal, tangentLightDir) + 0.5);
UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);
fixed3 finalColor = ambient + diffuse * atten;
return fixed4(finalColor, 1);
}
这个与书中一开始将光照唯一区别就是裁剪掉了像素,实现了消融效果,所以为什么说消融效果很简单呢,就多了这么一句话。
书中增加了点难度,让燃烧效果更加逼真,实现了烧焦区域
//burn.r在这里一定大于_BurnAmount
//_LineWidth区间为[0,0.2]
//smoothstep结果为(0,1]区间内
//当burn.r - _BurnAmount > _LineWidth时最终t为0,说明火还没烧过来
//否则存在线性变换
//这里就刚好符合在LineWidth外没有燃烧痕迹的需求
fixed t = 1 - smoothstep(0.0, _LineWidth, burn.r - _BurnAmount);
//在燃烧范围内存在渐进变换
fixed3 burnColor = lerp(_BurnFirstColor, _BurnSecondColor, t);
//增加亮度和对比度
burnColor = pow(burnColor, 5);
UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);
fixed3 finalColor = lerp(ambient + diffuse * atten, burnColor, t * step(0.0001, _BurnAmount));
具体每句话的解析我写在了上面代码中。这里额外补充一下针对burnColor去计算幂运算的功能,在书中原话“为了让效果更接近烧焦的痕迹,我们还使用 pow 函数对结果进行处理”这句话也没说为什么,让人很难受,下面稍微解释一下
对颜色进行幂运算的意义通常是为了调整颜色的亮度、对比度或饱和度等方面。幂运算可以让颜色值呈现非线性的变化,从而实现更精细的颜色调整效果。
例如,将颜色值进行2次幂运算可以增加颜色的亮度和对比度。而将颜色值进行小于1的幂运算,可以减小颜色的亮度和对比度,同时增加饱和度。
另外,幂运算还可以用于对颜色进行颜色空间转换,例如将颜色值进行gamma校正,以实现更加自然的颜色表现。
shadowcaster
这个Pass与fwdbase类似,也是裁剪掉消融后的像素