深入了解Unity中LineRenderer與TrailRenderer


LineRender和TrailRender是兩個好東西,很多Unity拖尾特效都會使用到它們。一些簡單的介紹可以參見官方的API文檔。

在這里探討一下它們具體的渲染方式,而后給出一些Shader以便更好地控制它們。

最終我們可以實現類似這樣的一個效果:

 

接下來,我們先了解LineRenderer。稍后的TailRenderer情況類似。

創建LineRender

LineRender是一個以頂點去控制渲染尺寸和位置的條帶,頂點個數和具體坐標我們自己可以完全操控。
首先我們需要建立了一個GameObject,然后添加LineRenderer組件,然后填入一下參數:


LineRenderer參數


其實就是一個沿着X方向延展的一組頂點。然后新建一個材質,並把它拖入Materials。
由於當前你使用的是默認材質,所以目前只能獲得以下的樣子:


顯示


就是一個矩形而已。

修改LineRenderer

首先,我們需要一張資源圖片,大概是這樣:


貼圖


這個圖片使用PSD制作一下,里面白色部分代表將來要在條帶中顯露出來的部分,黑色則是透明的部分。只有黑白兩種顏色即可。注意要加入通道,即把這個黑白圖片在PSD中新建一層透明通道,並且粘貼進去。最后讓你的通道看起來是這樣:


貼圖通道

為什么只要黑白圖,不需要顏色?解釋一下:
我們用這個素材來構成條帶的主要輪廓,而顯示的色彩由其它參數控制,所以這里只需要黑白圖就可以了。

開始寫Shader

屬性部分,就是一張貼圖就可以了。

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

 

Tags部分,我們需要設定處於半透明渲染隊列,並且設定Alpha混合的模式,就是用最常見的Alpha混合的模式即可。

        Tags { "RenderType"="Transparent"  "IgnoreProjector"="True"  "Queue"="Transparent"}
        LOD 200
        Blend SrcAlpha OneMinusSrcAlpha

 

由於我們不需要光照,也不希望受到光照的影響,所以我們寫一個直接返回原色的光照方程來避免默認的光照處理。同時,為了避免產生光照部分的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; 
          }

接下來是頂點着色器代碼,我們只要將系統傳遞過來頂點顏色和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;
        }

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

       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

 

其實也很簡單:
這里我們只是提取了貼圖上的 【像素顏色透明度】 X 【頂點顏色透明度】 作為最終透明度。這樣做的目的就是為了提取貼圖上的輪廓,同時透明度也會受到頂點顏色的影響。
使用【頂點顏色】作為最終顏色。
這樣我們就可以通過LineRenderer的StartColor和EndColor來設定整個條帶的顏色和透明度了。

使用之前的貼圖和這個Shader,修改之前的材質。最終這個條帶變成這樣:


最終的條帶

完整的LineRenderer的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"
}

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)
    }

最后,在表面着色器中進行相應的修改

        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;
        }

這樣,我們可以通過主控制顏色的變化來控制整體尾跡隨着時間的顏色變化。而條帶上顏色不同位置的變化,則由那五個顏色值進行控制。當我們只需要顯示一個純色條帶時,將五個顏色都設置為白色和變化的透明度即可。
最后,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);
    }
}

完整的TailRenderer的Shader

Shader "AndrewBox/TrailRenderer" {
    Properties {
        _MainTex ("Base (RGB)", 2D) = "white" {}
        _MainCol ("Self Color Value", Color) = (1,1,1,1)
    }
    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 _MainCol;

        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);
            //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;
        }

        
        ENDCG
    } 
    FallBack "Diffuse"
}

總結

最終,我們可以完整控制兩種Renderer的渲染了,最重要的事情再說一遍,就是它們的Color設定都寫入了頂點顏色,我們可以通過讀取頂點顏色來完成自己想要的渲染效果。


本頁完整資源請在我的CSDN博客中獲取:http://blog.csdn.net/andrewfan

本文為博主原創文章,歡迎轉載。請保留博主鏈接http://blog.csdn.net/andrewfan


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM