前言

  • 最近高精项目是真的忙到吃💩,学习时间都压榨得所剩无几了。
  • 之前虽然用Unity内置的Shader写过一些简单的shader,但涉及到别人的项目or教程or虚幻,用连连看的也不在少数,所以还是找时间学起了Shader Graph
  • 本篇实现的是一个简单的消融特效,基本都是完全参照油管BracKeys

效果预览

  • 教程里使用的是猴子模型

原教程的注意点

  1. 油管上教程原本是用PBRShader的,但那是Unity刚推出2018版本才存在的东西,本质上是光照模型;如果你要自己新建一个这样的Shader,在18之后的版本换成Lit Shader Graph即可
  2. 如果你使用和作者一样的Unity版本,会发现导入工程后猴子的模型无法显示,这可能是因为就版本的Unity对Blender的模型转换需要依赖更远古的Blender版本;如果你要解决这个问题,要么下远古版本的Blender,要么下个新的Blender,然后用20的Unity版本打开工程(我就是)
  3. 作者原工程使用的Settings目录在20版本的Unity上是有坑的(19可能也有?):
    • .setting后缀的文件导到新版本上是会直接什么都看不见的,但PostProcessProfile却不会有任何报错;
    • 神奇的事情就在于Package Manager补上PostProcess的插件后没有任何报错,却也没有任何效果,经过一番查阅才发现PostProcess已经不兼容新版Unity的URP渲染管线了,可即便如此,插件主页几乎没有任何这方面的提示。。
      • 如果PostProcess不生效的情况下,你会发现消融边缘的光一点都不亮,就像下面这样:
      • 颜色没有亮起来
      • 而如果PostProcess正常进行后处理的情况下,你会发现消融的边缘光非常亮,并且背景色也有变化:
      • 颜色亮起来了
    • 这个问题本质上就是三方开发的PostProcess已经被URP内置替代了,具体操作步骤可见B站的一个教程
    • 新版本上把原本的一些设置项打得更散了,但本质上还是一个东西:
      • 新版设置

Surf Shader实现

  • 其实之前也看过Surf Shader的实现方式,但在这里就不多说了,直接贴个效果:

  • 当时的代码:

Shader "Custom/Dissolve"
{
    Properties
    {
        _Color ("Color", Color) = (1,1,1,1)
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
		_Normal("Normal", 2D) = "bump" {}
		_NormalScale("NormalScale", Range(0,5)) = 1
        _Glossiness ("Smoothness", Range(0,1)) = 0.5
        _Metallic ("Metallic", Range(0,1)) = 0.0
		_DisolveTex("DisolveTex",2D) = "white"{}
		_Threshold("Threshold",Range(0,1)) = 0
        // 消融得边缘长度
		_EdgeLength("EdgeLength", Range(0,0.2)) = 0.1
        // 烧着贴图
		_BurnTex("BurnTex", 2D) = "white"{}
        // 颜色强度
		_BurnInstensity("BurnInstensity", Range(0,5)) = 1
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 200

        CGPROGRAM
        // Physically based Standard lighting model, and enable shadows on all light types
        #pragma surface surf Standard fullforwardshadows

        // Use shader model 3.0 target, to get nicer looking lighting
        #pragma target 3.0

        sampler2D _MainTex;
		sampler2D _Normal;
		half _NormalScale;
		sampler2D _DisolveTex;
		half _Threshold;
		sampler2D _BurnTex;
		half _EdgeLength;
		half _BurnInstensity;

        struct Input
        {
            float2 uv_MainTex;
			float2 uv_Normal;
			float2 uv_DisolveTex;
        };

        half _Glossiness;
        half _Metallic;
        fixed4 _Color;

        // Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
        // See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
        // #pragma instancing_options assumeuniformscaling
        UNITY_INSTANCING_BUFFER_START(Props)
            // put more per-instance properties here
        UNITY_INSTANCING_BUFFER_END(Props)

        void surf (Input IN, inout SurfaceOutputStandard o)
        {
            // Albedo comes from a texture tinted by color
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
			o.Normal = UnpackScaleNormal(tex2D(_Normal, IN.uv_Normal),_NormalScale);
            o.Albedo = c.rgb;

			float cutout = tex2D(_DisolveTex, IN.uv_DisolveTex).r;
			clip(cutout - _Threshold);
			float temp = saturate((cutout - _Threshold) / _EdgeLength);
			fixed4 edgeColor = tex2D(_BurnTex,float2(temp,temp));
			fixed4 finalColor = _BurnInstensity * lerp(edgeColor, fixed4(0,0,0,0), temp);
			o.Emission = finalColor.rgb;
            // Metallic and smoothness come from slider variables
            o.Metallic = _Metallic;
            o.Smoothness = _Glossiness;
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}
  • 但上面的代码其实还有各种问题,比如把模型换成一个正方形,侧面的烧着贴图就没法显示等,具体的就不赘述了。

噪音贴图

  • 噪音贴图的作用是通过在不规则的贴图上进行UV采样,从而使得每个片元的透明度都不一样,从而让物体不同的位置的A通道都不规则,我们可以通过更改Surface看到这个效果:
  • 过更改Surface

当然,更改Surface只是为了方便理解,实际还是使用Opaque使物体不透明才能更好看到效果

  • 看完效果后,我们变回Opaque,之后通过控制Alpha Clip Threshold就可以得到最初步的消融效果:
  • 控制 Alpha Clip Threshold
  • 我们还可以添加时间轮询的节点来轮询播放以便于我们调试:
  • 轮询播放

添加消融边缘光

  • 为了方便调试,我们首先是要先关闭噪音纹理->Alpha的输入:
  • 关闭 噪音纹理->Alpha 输入
  • 然后增加Step节点,Step的作用就是“当In值>=Edge时,才会输出1”,可以把它当作一个开关,当In全部>=Edge时,物体就会完全变为白色:
  • 黑变白
  • 这里的白色后续其实就是替换成消融边缘光的颜色;不过在此之前,我们尝试把噪声纹理的输出重新链接的Alpha,就会发现我们又回到起点了,跟上面搞完噪音贴图的时候没啥区别:
  • 跟搞完噪音贴图的时候没啥区别
  • 但实际上是有区别的,目前看起来没区别主要是因为变白的部分刚好也被剔除掉了而已:
  • 重叠挖空
  • 而我们要实现边缘光,其实就相当于把白色那层再“外拓”下:
  • 外拓
  • 而目前无论是变白部分还是剔除部分,都来自与噪声纹理的输出,我们无论是减小噪音纹理输出,还是增大Step的In等都可以实现类似的效果,比如减少噪音纹理输出:
  • 减少噪音纹理输出
  • 又比如增大Step的In:
  • 增大Step的In
  • 最后,我们把颜色加上去:
  • 加上颜色

最后

  • 把Shader套到猴子模型上,基本大功告成:
  • 应用到模型上
  • 最后为了方便shader参数从外部调试,可以将部分再shader里写死的入参参数化:
  • 参数化
  • 对了,不要忘了我们目前是还没勾上双面渲染的,勾上后如下图所示:
  • 双面