Shader smoothstep实现线条渐变色

效果展示

在这里插入图片描述
细节说明(也是下面准备shader实现的三个要点):

  1. 线条有三段颜色拼接(代号1 2 3);
  2. 红黑(1 2)之间有渐变过度;
  3. 黑绿(2 3)之间没有渐变过度。

具体实现

线条创建

       基础线条载体就是LineRenderer组件。先在场景中创建一个空对象,然后挂在LineRenderer组件,保持默认设置就好。设置线条起点(-7,0,0)和终点(7,0,0),线条宽度0.5,以及线条颜色。
如图:
在这里插入图片描述
在这里插入图片描述

创建Shader(LineGradualColor)

  1. 创建Shader。首先创建一个UnlitShader模板,命名为LineGradualColor.shader。接着创建一个材质球,命名为LineGradualColor。
  2. 打开LineGradualColor.shader,修改第一行shader名称为Shader “ShadersHub/LineGradualColor”
  3. 设置刚刚创建的材质球的shader为ShadersHub/LineGradualColor(即刚刚创建的shader);

Shader源码

Shader "ShadersHub/LineGradualColor"
{
    Properties
    {
		_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
		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
            {
                float4 vertex : SV_POSITION;
				float2 uv : TEXCOORD0;
				fixed4 color : COLOR;
            };

			half _StartBoost;
			half _EndBoost;

			half _LineLength;

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

            fixed4 frag (v2f i) : SV_Target
            {
				fixed4 col = fixed4(0,0,0,1);
				col.r += _StartBoost * smoothstep(1, 0, (i.uv.x * _LineLength));
				col.g += _EndBoost * smoothstep(_LineLength - 1, _LineLength, (i.uv.x * _LineLength));

				//col *= i.color;//这是线条LineRenderer原始颜色,可以打开注释看看效果
				
				return col;
            }
            ENDCG
        }
    }
}

Shader源码分析

       顶点函数中很简单,只是将模型顶点中的三个属性拿过来存到v2f的实例中,传输到片段着色器中。
重点在片段函数。

fixed4 frag (v2f i) : SV_Target
	{
		fixed4 col = fixed4(0,0,0,1);
		col.r += _StartBoost * smoothstep(1, 0, (i.uv.x * _LineLength));
		col.g += _EndBoost * smoothstep(_LineLength - 1, _LineLength, (i.uv.x * _LineLength));

		//col *= i.color;
		
		return col;
    }
    ENDCG
}

       一开始展示的线条中,分为三段,就是这里的三行代码。主体色是纯黑色,即代码:fixed4 col = fixed4(0,0,0,1);第一段红色,第三段绿色的控制代码分别为:col.r += _StartBoost * smoothstep(1, 0, (i.uv.x * _LineLength))col.g += _EndBoost * smoothstep(_LineLength - 1, _LineLength, (i.uv.x * _LineLength))
       混色过程:首先整条是纯黑色,rgb通道值都是0,然后r通道加上一个值,有效范围是[0,1],然后b通道加上一个值,有效范围也是[0,1]。那么为什么只有一开始一段被混入红色,最后一段被混入绿色呢,那就是smoothstep这个函数起了很大的作用,否则整段线条颜色就是(r,g,0,1),其中r,g为任意有效值。从代码中看,r通道的计算,uv.x被限制在[0,1]之间;g通道的计算,uv.x被限定在[3,4]之间,所以uv.x对应的区间[1,3]不受影响,颜色保持默认值黑色。
       最终结果解释了,那么smoothstep(a,b,x)函数原理又是什么呢?请参考链接

  1. 值域在[0,1]
  2. a>b时,图像趋势递增
  3. a<b时,图像趋势递减

       至此,我们不难理解 col.r += _StartBoost 0 smoothstep(1, 0, (i.uv.x * _LineLength)) 在(uv.x * _LineLength)值域在[0,4],然后 smoothstep(1, 0, (i.uv.x * _LineLength)) 在[0,1]上的值由1 平滑过度 减为0,后面一直为0;这就解释了为什么第一段有r通道叠加,第二段第三段没有r通道叠加。平滑过度,正是红到黑渐变的原因。

       同理第三段的绿色也一样理解。smoothstep(_LineLength - 1, _LineLength, (i.uv.x * _LineLength)) 公式对应的图像正好是上面的参考链接(i.uv.x * _LineLength) 在[0,3]上对应的值是0,[3,4]上对应的值从0 平滑过度 到1,所以第二段第三段,黑绿就这么产生了。现在有个问题,为什么二三段不是渐变过度呢?因为,编辑器中 _EndBoost 值设置得太大(我的本机上设置的是1000),也就是说即使 smoothstep(_LineLength - 1, _LineLength, (i.uv.x * _LineLength)) 在[3,4]上的值是0到1平滑过度,但是再乘上1000,这个过度就变得很陡了,再加上单个通道有效值仅仅是[0,1],也就是0到1000的值域中只有那么千分之一段有效,这个曲线的切线斜率(变化率)可以脑补下多大。所以就没有了渐变过度。

       本篇至此完结,欢迎指正交流(或邮件1136468882@qq.com)!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值