【Unity Shader】如何修改LineRenderer与TrailRenderer 中的颜色

本文介绍如何使用Unity中的LineRenderer和TrailRenderer实现拖尾特效。通过调整Shader,可以精确控制渲染效果,包括颜色渐变和透明度变化。文章还提供了一个示例Shader代码,帮助读者理解和实践。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

LineRender和TrailRender是两个好东西,很多Unity拖尾特效都会使用到它们。一些简单的介绍可以参见官方的API文档。 
在这里探讨一下它们具体的渲染方式,而后给出一些Shader以便更好地控制它们。

最终我们可以实现类似这样的一个效果: 
TrailRenderer

接下来,我们先了解LineRenderer。稍后的TailRenderer情况类似。

创建LineRender

LineRender是一个以顶点去控制渲染尺寸和位置的条带,顶点个数和具体坐标我们自己可以完全操控。 
首先我们需要建立了一个GameObject,然后添加LineRenderer组件,然后填入一下参数:

LineRenderer参数 
其实就是一个沿着X方向延展的一组顶点。然后新建一个材质,并把它拖入Materials。 
由于当前你使用的是默认材质,所以目前只能获得以下的样子:

显示 
就是一个矩形而已。

修改LineRenderer

首先,我们需要一张资源图片,大概是这样:

贴图 
这个图片使用PSD制作一下,里面白色部分代表将来要在条带中显露出来的部分,黑色则是透明的部分。只有黑白两种颜色即可。注意要加入通道,即把这个黑白图片在PSD中新建一层透明通道,并且粘贴进去。最后让你的通道看起来是这样:

贴图通道

为什么只要黑白图,不需要颜色?解释一下: 
我们用这个素材来构成条带的主要轮廓,而显示的色彩由其它参数控制,所以这里只需要黑白图就可以了。

开始写Shader

属性部分,就是一张贴图就可以了。

    Properties {
        _MainTex ("Base (RGB)", 2D) = "white" {}
    }
  • 1
  • 2
  • 3

Tags部分,我们需要设定处于半透明渲染队列,并且设定Alpha混合的模式,就是用最常见的Alpha混合的模式即可。

        Tags { "RenderType"="Transparent"  "IgnoreProjector"="True"  "Queue"="Transparent"}
        LOD 200
        Blend SrcAlpha OneMinusSrcAlpha
  • 1
  • 2
  • 3

由于我们不需要光照,也不希望受到光照的影响,所以我们写一个直接返回原色的光照方程来避免默认的光照处理。同时,为了避免产生光照部分的Pass,添加noforwardadd参数,这样我们的渲染就只需要一个Pass。

CGPROGRAM
        #pragma surface surf NoLight vertex:vert alpha noforwardadd

        //光照方程,名字为Lighting接#pragma suface后的光照方程名称 
        //lightDir :顶点到光源的单位向量
        //viewDir  :顶点到摄像机的单位向量   
        //atten    :关照的衰减系数 
        float4 LightingNoLight(SurfaceOutput s, float3 lightDir,half3 viewDir, half atten) 
        { 
            float4 c ; 
            c.rgb =  s.Albedo;
            c.a = s.Alpha; 
            return c; 
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

接下来是顶点着色器代码,我们只要将系统传递过来顶点颜色和UV坐标存储下来,以便于输入到表面着色器就可。

        sampler2D _MainTex;
        fixed4 _SelfCol;

        struct Input 
        {
            float2 uv_MainTex;
            float4 vertColor;
        };

        void vert(inout appdata_full v, out Input o)
        {
            o.vertColor = v.color;
            o.uv_MainTex = v.texcoord;
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

最后就是最重要的部分,表面着色器代码:

        void surf (Input IN, inout SurfaceOutput o) 
        {
            half4 c = tex2D (_MainTex, IN.uv_MainTex);
            o.Alpha = c.a * IN.vertColor.a;
            o.Albedo = IN.vertColor.rgb;
        }


        ENDCG
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

其实也很简单: 
这里我们只是提取了贴图上的 【像素颜色透明度】 X 【顶点颜色透明度】 作为最终透明度。这样做的目的就是为了提取贴图上的轮廓,同时透明度也会受到顶点颜色的影响。 
使用【顶点颜色】作为最终颜色。 
这样我们就可以通过LineRenderer的StartColor和EndColor来设定整个条带的颜色和透明度了。

使用之前的贴图和这个Shader,修改之前的材质。最终这个条带变成这样:

最终的条带

完整的Shader

Shader "AndrewBox/LineRenderer" {
    Properties {
        _MainTex ("Base (RGB)", 2D) = "white" {}
    }
    SubShader {
        Tags { "RenderType"="Transparent"  "IgnoreProjector"="True"  "Queue"="Transparent"}
        LOD 200
        Blend SrcAlpha OneMinusSrcAlpha
        CGPROGRAM
        #pragma surface surf NoLight vertex:vert alpha noforwardadd

        //光照方程,名字为Lighting接#pragma suface后的光照方程名称 
        //lightDir :顶点到光源的单位向量
        //viewDir  :顶点到摄像机的单位向量   
        //atten    :关照的衰减系数 
        float4 LightingNoLight(SurfaceOutput s, float3 lightDir,half3 viewDir, half atten) 
        { 
            float4 c ; 
            c.rgb =  s.Albedo;
            c.a = s.Alpha; 
            return c; 
        }

        sampler2D _MainTex;
        fixed4 _SelfCol;

        struct Input 
        {
            float2 uv_MainTex;
            float4 vertColor;
        };

        void vert(inout appdata_full v, out Input o)
        {
            o.vertColor = v.color;
            o.uv_MainTex = v.texcoord;
        }

        void surf (Input IN, inout SurfaceOutput o) 
        {
            half4 c = tex2D (_MainTex, IN.uv_MainTex);
            o.Alpha = c.a * IN.vertColor.a;
            o.Albedo = IN.vertColor.rgb;
        }


        ENDCG
    } 
    FallBack "Diffuse"
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51

TrailRenderer

TrailRenderer与LineRenderer很相似,又有些不同。不同之处在于: 
首先,它的顶点构成是动态的,每帧你需要将产生TrailRenderer的GameObject移动到不同的位置,这样它会自动连接成一个轨迹。 
其次,它由五个颜色值来进行控制整个条带的颜色变化,但是不像LineRenderer,在运行时你并不能修改这些颜色值,因为它的API中没有访问这五个颜色的方法,但是我们仍然可以通过Shader来进行改变。 
记住最重要的一点就是,它和LineRenderer一样,都是把一组颜色值写入了顶点颜色,我们只要读取顶点颜色即可。 
为了整体控制尾迹的颜色显示,我们增加一个主控制颜色,修改上面那个Shader。

    Properties {
        _MainTex ("Base (RGB)", 2D) = "white" {}
        _MainCol ("Self Color Value", Color) = (1,1,1,1)
    }
  • 1
  • 2
  • 3
  • 4

最后,在表面着色器中进行相应的修改

        void surf (Input IN, inout SurfaceOutput o) 
        {
            half4 c = tex2D (_MainTex, IN.uv_MainTex);
            //c.a为贴图上的透明度,使用它构成条带的图形轮廓
            //_MainCol.a为主颜色的透明度,用于对整个条带透明度控制
            //IN.vertColor.a由顶点颜色获得,由Colors数组设置,用于控制条带不同位置的透明度度变化
            o.Alpha = c.a * _MainCol.a* IN.vertColor.a;
            //_MainCol.rgb为主颜色的颜色值,用于显示主颜色部分
            //IN.vertColor.rgb为顶点颜色的颜色值,由Colors数组设置,用于控制条带不同位置的颜色变化
            o.Albedo = _MainCol.rgb*IN.vertColor.rgb;
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

这样,我们可以通过主控制颜色的变化来控制整体尾迹随着时间的颜色变化。而条带上颜色不同位置的变化,则由那五个颜色值进行控制。当我们只需要显示一个纯色条带时,将五个颜色都设置为白色和变化的透明度即可。 
最后,TrailRender的显示效果如下:

TrailRender

当然你需要一个脚本来控制TrailRender所在的GameObject的旋转,代码相对简单。(BaseBehavior类的实现可以参见我的其它文章)

public class TrailRendererGen : BaseBehavior 
{
    [SerializeField][Tooltip("旋转角速度")]
    protected float m_angle=360;
    protected override void OnInitFirst()
    {
    }

    protected override void OnInitSecond()
    {
    }

    protected override void OnUpdate()
    {
        m_transform.Rotate(Vector3.forward, m_angle*Time.deltaTime);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

总结

最终,我们可以完整控制两种Renderer的渲染了,最重要的事情再说一遍,就是它们的Color设定都写入了顶点颜色,我们可以通过读取顶点颜色来完成自己想要的渲染效果。


本页资源下载:http://download.youkuaiyun.com/download/andrewfan/9764637


本文为博主原创文章,欢迎转载。请保留博主链接http://blog.youkuaiyun.com/andrewfan


### 关于 Highlighting Renderer 的概述 Highlighting Renderer 并不是 Unity 官方提供的一种特定组件名称,但在实际开发中,“highlighting”通常指的是通过某种方式突出显示游戏中的物体。这种效果可以通过多种方法实现,比如使用 `LineRenderer`[^4] 或者自定义着色器来绘制高亮边框。 如果目标是在 URP(Universal Render Pipeline)项目中实现对象的高亮显示,则可以考虑以下几种技术: #### 使用 LineRenderer 实现高亮 一种常见的做法是围绕目标对象放置一个 `LineRenderer` 来模拟边界框的效果。具体操作如下: 1. 创建一个新的 GameObject,并为其添加 `LineRenderer` 组件。 2. 设置该组件的位置使其环绕目标对象。 3. 调整材质属性以匹配所需的视觉样式。 ```csharp // 示例脚本:动态生成并配置 LineRenderer using UnityEngine; public class ObjectHighlighter : MonoBehaviour { public float lineWidth = 0.1f; private LineRenderer lineRenderer; void Start() { lineRenderer = gameObject.AddComponent<LineRenderer>(); lineRenderer.material = new Material(Shader.Find("Sprites/Default")); // 默认材质 lineRenderer.widthMultiplier = lineWidth; // 线宽设定 var meshFilter = GetComponent<MeshFilter>(); if (meshFilter != null && meshFilter.mesh != null) { DrawBoundingBox(meshFilter.mesh.bounds); } } void DrawBoundingBox(Bounds bounds) { Vector3[] corners = GetCorners(bounds); int cornerCount = corners.Length; Vector3[] positions = new Vector3[cornerCount * 2]; for(int i=0;i<cornerCount;i++) { positions[i*2] = corners[i]; positions[(i*2)+1] = corners[(i+1)%cornerCount]; } lineRenderer.positionCount = positions.Length; lineRenderer.SetPositions(positions); } Vector3[] GetCorners(Bounds bnds){ return new Vector3[]{ new Vector3(bnds.min.x, bnds.min.y, bnds.min.z), new Vector3(bnds.max.x, bnds.min.y, bnds.min.z), new Vector3(bnds.max.x, bnds.max.y, bnds.min.z), new Vector3(bnds.min.x, bnds.max.y, bnds.min.z), new Vector3(bnds.min.x, bnds.min.y, bnds.max.z), new Vector3(bnds.max.x, bnds.min.y, bnds.max.z), new Vector3(bnds.max.x, bnds.max.y, bnds.max.z), new Vector3(bnds.min.x, bnds.max.y, bnds.max.z) }; } } ``` 上述代码片段展示了如何利用 `LineRenderer` 动态描绘包围盒作为高亮手段。 #### 利用 Shader 和材质切换完成高亮 另一种更灵活的方式涉及修改模型使用的材质或应用特殊的着色器来进行实时高亮处理。这可能包括改变颜色、增加发光效果等特性。例如,当鼠标悬停在某个物体上时触发其外观变化。 对于此目的,开发者可编写自定义 HLSL/GLSL shader 文件或者选用已有的资源商店插件简化流程。 --- ### 结合其他渲染工具扩展功能 除了以上提到的方法外,还可以探索更多可能性,像基于 `TrailRenderer`[^2] 构建轨迹型强调动画;亦或是借鉴 SDL 中有关窗口管理的知识点——尽管它属于外部库范畴[^3] ,但某些概念或许能启发跨平台移植方案的设计思路。 最终选择取决于项目的具体需求以及性能考量因素。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值