Shader LineRenderer实现电波效果

Shader LineRenderer实现电波效果

  • 基础阅读
  • 效果展示
  • Shader源码
  • Shader源码分析
    • Perlin噪声

基础阅读

  1. Shader smoothstep实现线条渐变色
  2. Shader step函数实现线条拼色

效果展示

Shader源码

Shader "ShadersHub/LaserBeam"
{
    Properties
    {
		_MiddleColor("_MiddleColor color", Color) = (1,1,1,1)
		_EdgeColor("Edge color", Color) = (1,0,0,1)
		_Noise("Noise texture", 2D) = "gray"{}
		_NoiseIntensity("Noise intensity", Float) = 1
		_ScrollSpeed("Scroll speed", Float) = 1
		_StartBoost("Start boost", Float) = .5
		_EndBoost("End boost", Float) = .5
		_LineLength("LineLength", Float) = 2
    }

    SubShader
    {
        Tags { "RenderType"="Transparent" "RenderType" = "Transparent" }
        LOD 100

		//Blend SrcAlpha OneMinusSrcAlpha // 传统透明度
		//Blend One OneMinusSrcAlpha // 预乘透明度
		//Blend One One // 叠加
		//Blend OneMinusDstColor One // 柔和叠加
		//Blend DstColor Zero // 相乘——正片叠底
		//Blend DstColor SrcColor // 两倍相乘

		Blend One OneMinusSrcAlpha
		ZWrite Off

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
				fixed4 color:COLOR;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
				fixed4 color : COLOR;
				float4 worldPos : TEXCOORD1;
				float4 vertex : SV_POSITION;
            };

            sampler2D _Noise;
			float4 _Noise_ST;

			fixed4 _MiddleColor;
			fixed4 _EdgeColor;
			half _NoiseIntensity;
			half _ScrollSpeed;
			half _StartBoost;
			half _EndBoost;

			half _LineLength;

            v2f vert (appdata v)
            {
                v2f o;
				o.vertex = UnityObjectToClipPos(v.vertex);
				o.uv = v.uv;
				o.worldPos = mul(unity_ObjectToWorld, v.vertex);
				o.color = v.color;
				return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
				//perlin noise texture
				fixed noise = tex2D(_Noise, (i.worldPos.xy * _Noise_ST.xy + _Time.x * _ScrollSpeed) + _Noise_ST.zw).r;
				noise = noise * 2 - 1;
				i.uv.y += noise * _NoiseIntensity;

				half centerness = 1 - abs(i.uv.y - .5) * 2;
				float middle = step(0.85, centerness);
				middle *= abs(sin(i.uv.x * 8 + _Time.x * _ScrollSpeed));
				float edge = step(0.5, centerness) - middle;
				edge *= abs(sin(i.uv.x * 15 + _Time.x * _ScrollSpeed));
				
				fixed4 col = _MiddleColor * middle + _EdgeColor * edge;
				col.rgb += _StartBoost * smoothstep(1, 0, (i.uv.x * _LineLength));
				col.rgb += _EndBoost * smoothstep(_LineLength - 1, _LineLength, (i.uv.x * _LineLength));

				col *= i.color;

				col.rgb *= col.a;
				col.rgb *= 2;
				col.a *= .5;
				
				return col;
            }
            ENDCG
        }
    }
}

Shader源码分析

       看到这里,我建议shader新手看看本文开头的两篇基础知识介绍。老司机接着往下看。
       middle *= abs(sin(i.uv.x * 8 + _Time.x * _ScrollSpeed));edge *= abs(sin(i.uv.x * 15 + _Time.x * _ScrollSpeed)); 这两行是前两篇文章中没有的,这里引入正弦函数的作用是,让线条在 横向上 出现 周期性波动的片段效果周期性水平位移效果

Perlin噪声

       关于图形学中的噪声,参考下冯乐乐的【图形学】谈谈噪声

       上面源码中的关于perlin噪声的三行代码理解:

	fixed noise = tex2D(_Noise, (i.worldPos.xy * _Noise_ST.xy + _Time.x * _ScrollSpeed) + _Noise_ST.zw).r;
	noise = noise * 2 - 1;
	i.uv.y += noise * _NoiseIntensity;

上面第一行是针对noise噪声纹理采集,本来可以直接用Shader内置函数TRANSFORM_TEX搞定,无奈我们的动态效果需要根据时间来做周期性变化,也就是需要加入时间因子。所以我们不得不自己采集noise纹理,于是就有了 fixed noise = tex2D(_Noise, (i.worldPos.xy * _Noise_ST.xy + _Time.x * _ScrollSpeed) + _Noise_ST.zw).r。这个表达式的取值范围是[0,1];我们直接把这个范围内的随机值作用在uv.y上(i.uv.y += noise * _NoiseIntensity),也就是直接随机性影响线条纵向的像素点。Step函数在本例中作用就是纵向剔除像素,加上噪声,就形成了纵向随机性的像素剔除效果。
       noise = noise * 2 - 1这一行上面还没有提到,运行时,我们先注释掉,看效果,你会发现线条横向上被切了一刀似的,然后打开注释,就完美了。注释前后静态截图对比:
在这里插入图片描述
vs

在这里插入图片描述
noise = noise * 2 - 1公式对uv.y做了一个范围在[-1,1]上的随机分布,这个有点像 线性回归。这些巧妙的处理方法,展现了数学之美,经验多了,自然而然就会拿到实际项目中来应用了。图形学中还有句话叫做 “计算机图形学第一准则:近似原则如果她看上去是对的它就是对的”
       本篇至此完结,欢迎指正交流(或邮件[email protected])!

你可能感兴趣的:(Shader图步天下,Shader,Unity,LineRenderer)