国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

unity shader 實(shí)現(xiàn)通用描邊shader -文字描邊-字體描邊

這篇具有很好參考價(jià)值的文章主要介紹了unity shader 實(shí)現(xiàn)通用描邊shader -文字描邊-字體描邊。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

前言

在制作游戲時(shí),可以遇到要對(duì)字體添加描邊的需求,unity 的UGUI自帶的OutLine組件,描邊效果不好,寬度過(guò)大會(huì)出現(xiàn)穿幫,頂點(diǎn)數(shù)量也會(huì)增加,性能不好,如果對(duì)于有幾百字,頂點(diǎn)數(shù)量會(huì)很多,而且無(wú)法擴(kuò)展功能
unity字體描邊是哪個(gè),unity,游戲引擎,著色器,技術(shù)美術(shù),游戲程序
可以看出Outline創(chuàng)建了4個(gè)方向的文字
unity字體描邊是哪個(gè),unity,游戲引擎,著色器,技術(shù)美術(shù),游戲程序
Unity5.2以前的版本要求,每一個(gè)Canvas下至多只能有2^16-1=65535個(gè)頂點(diǎn)(使用2個(gè)字節(jié)(16位)存儲(chǔ)頂點(diǎn)索引),超過(guò)就會(huì)報(bào)錯(cuò)
以上的種種原因,讓我們不得不自己編寫文字圖片的描邊shader
在網(wǎng)上找了一圈資料后,發(fā)現(xiàn)一篇不錯(cuò)的文章,這個(gè)應(yīng)該是自己實(shí)現(xiàn)文本shader最經(jīng)典的文章
但是好像都沒有對(duì)uv偏移進(jìn)行說(shuō)明(最難的地方)

效果展示

unity字體描邊是哪個(gè),unity,游戲引擎,著色器,技術(shù)美術(shù),游戲程序
unity字體描邊是哪個(gè),unity,游戲引擎,著色器,技術(shù)美術(shù),游戲程序

Shader實(shí)現(xiàn)基礎(chǔ)描邊

基本思路,將uv在片元著色器進(jìn)行偏移,比較a通道,偏移后的圖片.a-原來(lái)的圖片.a
這里只是用ase可視化演示一下,實(shí)際用shader代碼實(shí)現(xiàn)
unity字體描邊是哪個(gè),unity,游戲引擎,著色器,技術(shù)美術(shù),游戲程序

沿著8或12個(gè)方向進(jìn)行偏移,偏移的方向越多,描邊寬度大時(shí)不容易穿幫
在基礎(chǔ)描邊這里暫時(shí)聲明其它變量
shader屬性這里不聲明其它的屬性,在C#腳本中不使用material.SetColor(“_描邊顏色”, _描邊顏色);
因?yàn)檫@會(huì)導(dǎo)致材質(zhì)不同,無(wú)法讓unity動(dòng)態(tài)批合并,會(huì)增加drawcall

Properties
{
//這個(gè)特性可以和Unity組件中的屬性產(chǎn)生關(guān)聯(lián)
//表示該屬性是與每個(gè)渲染器相關(guān)的數(shù)據(jù)
//在Shader中使用此特性聲明的屬性會(huì)在每個(gè)渲染器實(shí)例中共享
    [PerRendererData]_MainTex ("Texture", 2D) = "white" {}
    _OutLineColor("OutLineColor",Color)=(1,0,0,0)
    _OutLineWidth("OutLineWidth",Float)=1
}

Tags設(shè)置透明渲染隊(duì)列和透明渲染模式,開啟透明Blend

SubShader
{
    Tags
    {
        "Queue"="Transparent" "IgnoreProjector"="true" "RenderType"="Transparent"
    }
    Lighting Off
    ZWrite Off
    Blend SrcAlpha OneMinusSrcAlpha

頂點(diǎn)著色器,基礎(chǔ)普通的頂點(diǎn)著色器

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

片元著色器
在12個(gè)方向進(jìn)行采樣,OffsetX取cos值,OffsetY取sin值作為權(quán)重

fixed SampleTex(v2f i,fixed ii,fixed color_a)
{
    const fixed OffsetX[12] = {1, 0.866, 0.5, 0, -0.5, -0.866, -1, -0.866, -0.5, 0, 0.5, 0.866};
    const fixed OffsetY[12] = {0, 0.5, 0.866, 1, 0.866, 0.5, 0, -0.5, -0.866, -1, -0.866, -0.5};
    fixed2 offset_uv = i.uv + fixed2(OffsetX[ii], OffsetY[ii])* _MainTex_TexelSize.xy * _OutLineWidth;
    fixed sample_a = tex2D(_MainTex, offset_uv).a;
    fixed a = sample_a;//-color.a;不減去color.a,因?yàn)樵谖淖诌吘塧=0-1的部分,會(huì)為0
    //比如向上偏移,下面邊緣的a為0-1,減去1,負(fù)數(shù),saturate后為0,這個(gè)值應(yīng)該保留,否則邊緣顏色由原來(lái)的片元決定,沒有混合過(guò)渡
    return a;
}
fixed4 frag(v2f i) : SV_Target
{
    fixed4 col = tex2D(_MainTex, i.uv);
    fixed sum_a = 0;//疊加各個(gè)方向采樣a的結(jié)果
    sum_a += SampleTex(i, 0, col.a);
    sum_a += SampleTex(i, 1, col.a);
    sum_a += SampleTex(i, 2, col.a);
    sum_a += SampleTex(i, 3, col.a);
    sum_a += SampleTex(i, 4, col.a);
    sum_a += SampleTex(i, 5, col.a);
    sum_a += SampleTex(i, 6, col.a);
    sum_a += SampleTex(i, 7, col.a);
    sum_a += SampleTex(i, 8, col.a);
    sum_a += SampleTex(i, 9, col.a);
    sum_a += SampleTex(i, 10, col.a);
    sum_a += SampleTex(i, 11, col.a);
    sum_a=saturate(sum_a);
    fixed4 outLineColor=fixed4(_OutLineColor.rgb,sum_a);
    fixed4 finalCol=lerp(outLineColor,col,col.a);//沒有文字的地方a為0,由描邊決定,文字邊界a為0-1由文字顏色和描邊共同決定
    return finalCol;
}

問(wèn)題:

  • 可以發(fā)現(xiàn)文字邊緣有其它的文本,只是因?yàn)槲谋緦?duì)于的紋理被打包到一個(gè)大的圖集中,uv偏移后,會(huì)采樣到臨近的文本像素
  • 觀察N的左側(cè)可以看出,描邊的區(qū)域有一部分超出范圍為裁剪了
    解決方案:
  1. 要在C#里面得到偏移之前原來(lái)的uv范圍,根據(jù)uv范圍,將不在范圍的片元a設(shè)置為即可
  2. 要對(duì)頂點(diǎn)進(jìn)行擴(kuò)展,讓三角形范圍變大,同時(shí)要等比例擴(kuò)展uv,只擴(kuò)展頂點(diǎn),僅僅只是圖片被放大了,還是會(huì)被裁剪,
    ,同時(shí)擴(kuò)展頂點(diǎn)和uv,這樣就不會(huì)被裁剪了
    unity字體描邊是哪個(gè),unity,游戲引擎,著色器,技術(shù)美術(shù),游戲程序

實(shí)現(xiàn)通用的shader

C#部分

在C#腳本要進(jìn)行頂點(diǎn)的擴(kuò)展,進(jìn)行uv的擴(kuò)展
使用C#腳本傳遞描邊顏色和文本顏色
大致看一下BaseMeshEffect

  1. 在Canvas中要開啟uv1和uv2
protected override void Start()
{
    UseUVChannels();
}
private void UseUVChannels()
{
    var shader = Shader.Find("DSShader/TextOutline");
    base.graphic.material = new Material(shader);
    AdditionalCanvasShaderChannels v1 = base.graphic.canvas.additionalShaderChannels;
    var v2 = AdditionalCanvasShaderChannels.TexCoord1;
    if ((v1 & v2) != v2)
    {
        base.graphic.canvas.additionalShaderChannels |= v2;
    }
    v2 = AdditionalCanvasShaderChannels.TexCoord2;
    if ((v1 & v2) != v2)
    {
        base.graphic.canvas.additionalShaderChannels |= v2;
    }
}

上面的 |=操作不明白可以學(xué)習(xí)一下|=位或操作
比如

int a = 5;  // 二進(jìn)制表示: 0000 0101
int b = 3;  // 二進(jìn)制表示: 0000 0011
a |= b;    // 執(zhí)行位或運(yùn)算,并賦值給 a,有1則1
Console.WriteLine(a);  // 輸出: 7 (二進(jìn)制表示: 0000 0111)

可以發(fā)現(xiàn)AdditionalCanvasShaderChannels枚舉定義的數(shù)字剛好是2^n為了位或操作

public enum AdditionalCanvasShaderChannels
{
  None = 0,
  TexCoord1 = 1,
  TexCoord2 = 2,
  TexCoord3 = 4,
  Normal = 8,
  Tangent = 16, // 0x00000010
}
[ExecuteAlways]
public abstract class BaseMeshEffect : UIBehaviour, IMeshModifier
{
    [NonSerialized]
    private Graphic m_Graphic;

    /// <summary>
    /// The graphic component that the Mesh Effect will aplly to.
    /// </summary>
    protected Graphic graphic
    {
        get
        {
            if (m_Graphic == null)
                m_Graphic = GetComponent<Graphic>();

            return m_Graphic;
        }
    }

已經(jīng)BaseMeshEffect 帶有[ExecuteAlways],子類會(huì)在編輯器模式運(yùn)行
我們要使用BaseMeshEffect , BaseMeshEffect 是一個(gè)抽象類,用于實(shí)現(xiàn)自定義的 Mesh 效果.用于擴(kuò)展和修改 UI 元素的網(wǎng)格Mesh數(shù)據(jù).通過(guò)繼承 BaseMeshEffect 類并實(shí)現(xiàn)其中的方法,可以對(duì) UI 元素的網(wǎng)格進(jìn)行自定義的修改和效果應(yīng)用.
2. 重載ModifyMesh,更改UIVertex數(shù)據(jù)

public class TextOutline : BaseMeshEffect
{
	List<UIVertex> _uiVertices = new List<UIVertex>();
	[Range(0, 6)]
	public float outLineWidth = 1;
	public Color EdgeColor = Color.red;
	public Color TextColor = Color.red;
	public override void ModifyMesh(VertexHelper vh)
	{
	    vh.GetUIVertexStream(_uiVertices);
	    ModifyUIVertexs(_uiVertices);//下面的函數(shù)
	    vh.Clear();
	    vh.AddUIVertexTriangleStream(_uiVertices);
    }
}

ModifyUIVertexs遍歷UIVertex,每次拿到3個(gè)頂點(diǎn)數(shù)據(jù)
偏移頂點(diǎn)pos的思路,判斷頂點(diǎn)是否大于三角形的中心點(diǎn),x或y大于則向上或向右偏移,加上描邊寬度outLineWidth

void ModifyUIVertexs(List<UIVertex> uiVertices)
{
    for (int i = 0; i <= uiVertices.Count - 3; i += 3)
    {
        UIVertex uiVertex1 = uiVertices[i];
        UIVertex uiVertex2 = uiVertices[i + 1];
        UIVertex uiVertex3 = uiVertices[i + 2];
        Vector3 pos1 = uiVertex1.position;
        Vector3 pos2 = uiVertex2.position;
        Vector3 pos3 = uiVertex3.position;

        Vector2 uv1 = uiVertex1.uv0;
        Vector2 uv2 = uiVertex2.uv0;
        Vector2 uv3 = uiVertex3.uv0;
        //得到三角形的中心點(diǎn),用于頂點(diǎn)的偏移
        Vector3 pos_center = (pos1 + pos2 + pos3) / 3;
        Vector2 uv_min = new Vector2(Mathf.Min(uv1.x, uv2.x, uv3.x), Mathf.Min(uv1.y, uv2.y, uv3.y));
        Vector2 uv_max = new Vector2(Mathf.Max(uv1.x, uv2.x, uv3.x), Mathf.Max(uv1.y, uv2.y, uv3.y));
        Vector4 uv_border = new Vector4(uv_min.x, uv_min.y, uv_max.x, uv_max.y);
        //得到uv的范圍,傳遞給shader判斷
        //以pos和uv都以pos2或uv2為原點(diǎn)
        Vector2 pos_base1 = pos1 - pos2;
        Vector2 pos_base2 = pos3 - pos2;

        Vector2 uv_base1 = uv1 - uv2;
        Vector2 uv_base2 = uv3 - uv2;
        
        uiVertices[i] = ModifyPosUV(uiVertex1, pos_center, pos_base1, pos_base2, uv_base1, uv_base2, uv_border);
        uiVertices[i + 1] = ModifyPosUV(uiVertex2, pos_center, pos_base1, pos_base2, uv_base1, uv_base2, uv_border);
        uiVertices[i + 2] = ModifyPosUV(uiVertex3, pos_center, pos_base1, pos_base2, uv_base1, uv_base2, uv_border);
    }
}

計(jì)算pos頂點(diǎn)的偏移很好理解,但是uv的計(jì)算比較復(fù)雜,要使用線性代數(shù)的知識(shí),對(duì)旋轉(zhuǎn)縮放矩陣有一定的理解

UIVertex ModifyPosUV(UIVertex uiVertex, Vector3 pos_centor,
    Vector2 pos_base1, Vector2 pos_base2,
    Vector2 uv_base1, Vector2 uv_base2, Vector4 uv_border)
{
    //偏移pos
    Vector3 pos = uiVertex.position;
    float offsetX = pos.x > pos_centor.x ? outLineWidth : -outLineWidth;
    float offsetY = pos.y > pos_centor.y ? outLineWidth : -outLineWidth;
    pos.x += offsetX;
    pos.y += offsetY;
    uiVertex.position = pos;
    Vector2 offset = new Vector2(offsetX, offsetY);
    //uv偏移
    Vector2 uv = uiVertex.uv0;
    Matrix2x2 pos_m = new Matrix2x2(pos_base1.x,pos_base2.x,pos_base1.y,pos_base2.y);
     pos_m=pos_m.Inverse();
    Matrix2x2 uv_m = new Matrix2x2(uv_base1.x, uv_base2.x, uv_base1.y, uv_base2.y);
    Vector2 uv_offset = uv_m * pos_m * offset;
    uv += uv_offset;
    //設(shè)置偏移后的uv,uv0.z設(shè)置為描邊寬度
    uiVertex.uv0 = new Vector4(uv.x, uv.y, outLineWidth, 0);
    //設(shè)置原始uv范圍
    uiVertex.uv1 = uv_border;
    //設(shè)置文本顏色
    uiVertex.uv2 = new Vector4(EdgeColor.r,EdgeColor.g,EdgeColor.b,EdgeColor.a);
    //Color=>Color32,UIVertex的color類型是Color32
    Color32 color32 = (Color32)TextColor;
    uiVertex.color =color32;
    return uiVertex;
}

下面重點(diǎn)講解uv偏移部分
這里要自己實(shí)現(xiàn)Matrix2x2類,實(shí)現(xiàn)矩陣×矩陣,矩陣×向量,矩陣取逆

	//uv偏移
    Vector2 uv = uiVertex.uv0;
    Matrix2x2 pos_m = new Matrix2x2(pos_base1.x,pos_base2.x,pos_base1.y,pos_base2.y);
     pos_m=pos_m.Inverse();
    Matrix2x2 uv_m = new Matrix2x2(uv_base1.x, uv_base2.x, uv_base1.y, uv_base2.y);
    Vector2 uv_offset = uv_m * pos_m * offset;
    uv += uv_offset;

對(duì)于uv映射

unity字體描邊是哪個(gè),unity,游戲引擎,著色器,技術(shù)美術(shù),游戲程序
Matrix2×2類

public class Matrix2x2
{
    private float[,] matrix = new float[2, 2];

    public Matrix2x2(float a, float b, float c, float d)
    {
        matrix[0, 0] = a;
        matrix[0, 1] = b;
        matrix[1, 0] = c;
        matrix[1, 1] = d;
    }

    public float Determinant()
    {
        return matrix[0, 0] * matrix[1, 1] - matrix[0, 1] * matrix[1, 0];
    }

    public Matrix2x2 Inverse()
    {
        float det = Determinant();
        float invDet = 1 / det;
        float a = matrix[1, 1] * invDet;
        float b = -matrix[0, 1] * invDet;
        float c = -matrix[1, 0] * invDet;
        float d = matrix[0, 0] * invDet;

        return new Matrix2x2(a, b, c, d);
    }

    public static Matrix2x2 operator *(Matrix2x2 m1, Matrix2x2 m2)
    {
        float a = m1.matrix[0, 0] * m2.matrix[0, 0] + m1.matrix[0, 1] * m2.matrix[1, 0];
        float b = m1.matrix[0, 0] * m2.matrix[0, 1] + m1.matrix[0, 1] * m2.matrix[1, 1];
        float c = m1.matrix[1, 0] * m2.matrix[0, 0] + m1.matrix[1, 1] * m2.matrix[1, 0];
        float d = m1.matrix[1, 0] * m2.matrix[0, 1] + m1.matrix[1, 1] * m2.matrix[1, 1];

        return new Matrix2x2(a, b, c, d);
    }

    public static Vector2 operator *(Matrix2x2 m, Vector2 v)
    {
        float x = m.matrix[0, 0] * v.x + m.matrix[0, 1] * v.y;
        float y = m.matrix[1, 0] * v.x + m.matrix[1, 1] * v.y;

        return new Vector2(x, y);
    }
}

Shader部分

在Properties只說(shuō)明_MainTex ,其它參數(shù)由C#傳入

Properties
    {
        [PerRendererData]_MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags
        {
            "Queue"="Transparent" "IgnoreProjector"="true" "RenderType"="Transparent"
        }
        Cull Off
        Lighting Off
        ZWrite Off
        Blend SrcAlpha OneMinusSrcAlpha

頂點(diǎn)和片元結(jié)構(gòu)體

struct appdata {
    float4 vertex : POSITION;
    float4 uv : TEXCOORD0;
    float4 uv1 : TEXCOORD1;
    float4 uv2 : TEXCOORD2;
    float4 color:COLOR;
};

struct v2f {
    float2 uv : TEXCOORD0;
    float4 vertex : SV_POSITION;
    float4 border : TEXCOORD1;
    float4 color:COLOR;
    float width: TEXCOORD2;
    float4 edgeColor: TEXCOORD3;
};

頂點(diǎn)z著色器

v2f vert(appdata v)
{
    v2f o;
    o.vertex = UnityObjectToClipPos(v.vertex);
    o.uv = TRANSFORM_TEX(v.uv, _MainTex);
    o.width = v.uv.z;//得到描邊寬度
    o.color = v.color;//得到文本顏色
    o.border = v.uv1;//得到原始uv范圍
    o.edgeColor=v.uv2;//得到描邊顏色
    return o;
}

采樣偏移uv對(duì)紋理采樣

fixed SampleTex(v2f i,fixed ii,fixed color_a)
 {
     const fixed OffsetX[12] = {1, 0.866, 0.5, 0, -0.5, -0.866, -1, -0.866, -0.5, 0, 0.5, 0.866};
     const fixed OffsetY[12] = {0, 0.5, 0.866, 1, 0.866, 0.5, 0, -0.5, -0.866, -1, -0.866, -0.5};
     float2 offset_uv = i.uv + float2(OffsetX[ii], OffsetY[ii]) * _MainTex_TexelSize.xy * i.width;
     fixed sample_a = (tex2D(_MainTex, offset_uv)).a;
     fixed a = sample_a;
     a *= isInRange(i.border.xy, i.border.zw, offset_uv);
     return a;
 }

判斷uv是否在原始uv范圍

fixed isInRange(fixed2 uv_min,fixed2 uv_max,fixed2 uv)
{
    fixed2 rs = step(uv_min, uv) * step(uv, uv_max);
    return rs.x * rs.y;
}

片元著色器

fixed4 frag(v2f i) : SV_Target
{
    fixed4 col = tex2D(_MainTex, i.uv).a*i.color;
    col.a *= isInRange(i.border.xy, i.border.zw, i.uv);
    fixed sum_a = 0;
    sum_a += SampleTex(i, 0, col.a);
    sum_a += SampleTex(i, 1, col.a);
    sum_a += SampleTex(i, 2, col.a);
    sum_a += SampleTex(i, 3, col.a);
    sum_a += SampleTex(i, 4, col.a);
    sum_a += SampleTex(i, 5, col.a);
    sum_a += SampleTex(i, 6, col.a);
    sum_a += SampleTex(i, 7, col.a);
    sum_a += SampleTex(i, 8, col.a);
    sum_a += SampleTex(i, 9, col.a);
    sum_a += SampleTex(i, 10, col.a);
    sum_a += SampleTex(i, 11, col.a);
    sum_a = saturate(sum_a);
    fixed4 outLineColor = fixed4(i.edgeColor.rgb,sum_a);
    fixed a=step(i.width,0.001);//寬度為0時(shí),a為1,顏色由原來(lái)顏色決定
    fixed4 finalCol = lerp(outLineColor, col, saturate(a+col.a));
    return finalCol;
}

完整的C#代碼

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class TextOutline : BaseMeshEffect
{
    List<UIVertex> _uiVertices = new List<UIVertex>();
    [Range(0, 6)]
    public float outLineWidth = 1;
    public Color EdgeColor = Color.red;
    public Color TextColor = Color.white;
    public override void ModifyMesh(VertexHelper vh)
    {
        vh.GetUIVertexStream(_uiVertices);
        ModifyUIVertexs(_uiVertices);
        vh.Clear();
        vh.AddUIVertexTriangleStream(_uiVertices);
    }
    protected override void Start()
    {
        UseUVChannels();
    }
    private void UseUVChannels()
    {
        var shader = Shader.Find("DSShader/TextOutline");
        base.graphic.material = new Material(shader);
        AdditionalCanvasShaderChannels v1 = base.graphic.canvas.additionalShaderChannels;
        var v2 = AdditionalCanvasShaderChannels.TexCoord1;
        if ((v1 & v2) != v2)
        {
            base.graphic.canvas.additionalShaderChannels |= v2;
        }
        v2 = AdditionalCanvasShaderChannels.TexCoord2;
        if ((v1 & v2) != v2)
        {
            base.graphic.canvas.additionalShaderChannels |= v2;
        }
    }
    void ModifyUIVertexs(List<UIVertex> uiVertices)
    {
        for (int i = 0; i <= uiVertices.Count - 3; i += 3)
        {
            UIVertex uiVertex1 = uiVertices[i];
            UIVertex uiVertex2 = uiVertices[i + 1];
            UIVertex uiVertex3 = uiVertices[i + 2];
            Vector3 pos1 = uiVertex1.position;
            Vector3 pos2 = uiVertex2.position;
            Vector3 pos3 = uiVertex3.position;

            Vector2 uv1 = uiVertex1.uv0;
            Vector2 uv2 = uiVertex2.uv0;
            Vector2 uv3 = uiVertex3.uv0;

            Vector3 pos_center = (pos1 + pos2 + pos3) / 3;
            Vector2 uv_min = new Vector2(Mathf.Min(uv1.x, uv2.x, uv3.x), Mathf.Min(uv1.y, uv2.y, uv3.y));
            Vector2 uv_max = new Vector2(Mathf.Max(uv1.x, uv2.x, uv3.x), Mathf.Max(uv1.y, uv2.y, uv3.y));
            Vector4 uv_border = new Vector4(uv_min.x, uv_min.y, uv_max.x, uv_max.y);
            
            Vector2 pos_base1 = pos1 - pos2;
            Vector2 pos_base2 = pos3 - pos2;

            Vector2 uv_base1 = uv1 - uv2;
            Vector2 uv_base2 = uv3 - uv2;

            uiVertices[i] = ModifyPosUV(uiVertex1, pos_center, pos_base1, pos_base2, uv_base1, uv_base2, uv_border);
            uiVertices[i + 1] = ModifyPosUV(uiVertex2, pos_center, pos_base1, pos_base2, uv_base1, uv_base2, uv_border);
            uiVertices[i + 2] = ModifyPosUV(uiVertex3, pos_center, pos_base1, pos_base2, uv_base1, uv_base2, uv_border);
        }
    }
    UIVertex ModifyPosUV(UIVertex uiVertex, Vector3 pos_centor,
        Vector2 pos_base1, Vector2 pos_base2,
        Vector2 uv_base1, Vector2 uv_base2, Vector4 uv_border)
    {
        //偏移pos
        Vector3 pos = uiVertex.position;
        float offsetX = pos.x > pos_centor.x ? outLineWidth : -outLineWidth;
        float offsetY = pos.y > pos_centor.y ? outLineWidth : -outLineWidth;
        pos.x += offsetX;
        pos.y += offsetY;
        uiVertex.position = pos;
        Vector2 offset = new Vector2(offsetX, offsetY);
        //uv偏移
        Vector2 uv = uiVertex.uv0;
        Matrix2x2 pos_m = new Matrix2x2(pos_base1.x,pos_base2.x,pos_base1.y,pos_base2.y);
         pos_m=pos_m.Inverse();
        Matrix2x2 uv_m = new Matrix2x2(uv_base1.x, uv_base2.x, uv_base1.y, uv_base2.y);
        Vector2 uv_offset = uv_m * pos_m * offset;
        uv += uv_offset;
        //設(shè)置偏移后的uv,uv0.z設(shè)置為描邊寬度
        uiVertex.uv0 = new Vector4(uv.x, uv.y, outLineWidth, 0);
        //設(shè)置原始uv范圍
        uiVertex.uv1 = uv_border;
        //設(shè)置文本顏色
        uiVertex.uv2 = new Vector4(EdgeColor.r,EdgeColor.g,EdgeColor.b,EdgeColor.a);
        //Color=>Color32,UIVertex的color類型是Color32
        Color32 color32 = (Color32)TextColor;
        uiVertex.color =color32;
        return uiVertex;
    }


}

public class Matrix2x2
{
    private float[,] matrix = new float[2, 2];

    public Matrix2x2(float a, float b, float c, float d)
    {
        matrix[0, 0] = a;
        matrix[0, 1] = b;
        matrix[1, 0] = c;
        matrix[1, 1] = d;
    }

    public float Determinant()
    {
        return matrix[0, 0] * matrix[1, 1] - matrix[0, 1] * matrix[1, 0];
    }

    public Matrix2x2 Inverse()
    {
        float det = Determinant();
        float invDet = 1 / det;

        float a = matrix[1, 1] * invDet;
        float b = -matrix[0, 1] * invDet;
        float c = -matrix[1, 0] * invDet;
        float d = matrix[0, 0] * invDet;

        return new Matrix2x2(a, b, c, d);
    }

    public static Matrix2x2 operator *(Matrix2x2 m1, Matrix2x2 m2)
    {
        float a = m1.matrix[0, 0] * m2.matrix[0, 0] + m1.matrix[0, 1] * m2.matrix[1, 0];
        float b = m1.matrix[0, 0] * m2.matrix[0, 1] + m1.matrix[0, 1] * m2.matrix[1, 1];
        float c = m1.matrix[1, 0] * m2.matrix[0, 0] + m1.matrix[1, 1] * m2.matrix[1, 0];
        float d = m1.matrix[1, 0] * m2.matrix[0, 1] + m1.matrix[1, 1] * m2.matrix[1, 1];

        return new Matrix2x2(a, b, c, d);
    }

    public static Vector2 operator *(Matrix2x2 m, Vector2 v)
    {
        float x = m.matrix[0, 0] * v.x + m.matrix[0, 1] * v.y;
        float y = m.matrix[1, 0] * v.x + m.matrix[1, 1] * v.y;

        return new Vector2(x, y);
    }
}

完整的Shader代碼文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-774852.html

Shader "DSShader/TextOutline"
{
    Properties
    {
        [PerRendererData]_MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags
        {
            "Queue"="Transparent" "IgnoreProjector"="true" "RenderType"="Transparent"
        }
        Cull Off
        Lighting Off
        ZWrite Off
        Blend SrcAlpha OneMinusSrcAlpha
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata {
                float4 vertex : POSITION;
                float4 uv : TEXCOORD0;
                float4 uv1 : TEXCOORD1;
                float4 uv2 : TEXCOORD2;
                float4 color:COLOR;
            };

            struct v2f {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
                float4 border : TEXCOORD1;
                float4 color:COLOR;
                float width: TEXCOORD2;
                float4 edgeColor: TEXCOORD3;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float4 _MainTex_TexelSize;
            
            v2f vert(appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                o.width = v.uv.z;
                o.color = v.color;
                o.border = v.uv1;
                o.edgeColor=v.uv2;
                return o;
            }

            fixed isInRange(fixed2 uv_min,fixed2 uv_max,fixed2 uv)
            {
                fixed2 rs = step(uv_min, uv) * step(uv, uv_max);
                return rs.x * rs.y;
            }

            fixed SampleTex(v2f i,fixed ii,fixed color_a)
            {
                const fixed OffsetX[12] = {1, 0.866, 0.5, 0, -0.5, -0.866, -1, -0.866, -0.5, 0, 0.5, 0.866};
                const fixed OffsetY[12] = {0, 0.5, 0.866, 1, 0.866, 0.5, 0, -0.5, -0.866, -1, -0.866, -0.5};
                float2 offset_uv = i.uv + float2(OffsetX[ii], OffsetY[ii]) * _MainTex_TexelSize.xy * i.width;
                fixed sample_a = (tex2D(_MainTex, offset_uv)).a;
                fixed a = sample_a ;
                a *= isInRange(i.border.xy, i.border.zw, offset_uv);
                return a;
            }

            fixed4 frag(v2f i) : SV_Target
            {
                fixed4 col = tex2D(_MainTex, i.uv).a*i.color;
                col.a *= isInRange(i.border.xy, i.border.zw, i.uv);
                fixed sum_a = 0;
                sum_a += SampleTex(i, 0, col.a);
                sum_a += SampleTex(i, 1, col.a);
                sum_a += SampleTex(i, 2, col.a);
                sum_a += SampleTex(i, 3, col.a);
                sum_a += SampleTex(i, 4, col.a);
                sum_a += SampleTex(i, 5, col.a);
                sum_a += SampleTex(i, 6, col.a);
                sum_a += SampleTex(i, 7, col.a);
                sum_a += SampleTex(i, 8, col.a);
                sum_a += SampleTex(i, 9, col.a);
                sum_a += SampleTex(i, 10, col.a);
                sum_a += SampleTex(i, 11, col.a);
                sum_a = saturate(sum_a);
                fixed4 outLineColor = fixed4(i.edgeColor.rgb,sum_a);
                fixed a=step(i.width,0.001);
                fixed4 finalCol = lerp(outLineColor, col, saturate(a+col.a));
                return finalCol;
            }
            ENDCG
        }
    }
}

到了這里,關(guān)于unity shader 實(shí)現(xiàn)通用描邊shader -文字描邊-字體描邊的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Unity3D Shader系列之描邊

    Unity3D Shader系列之描邊

    總結(jié)下描邊效果的實(shí)現(xiàn)方式,主要有以下幾種: ①法線外拓+ZTest Always ②法線外拓+Cull Front ③法線外拓+ZWrite Off ④法線外拓+模板測(cè)試 ⑤基于屏幕后處理 法線外拓的原理如下: 基本原理還是很簡(jiǎn)單的:模型渲染兩次,第一次渲染時(shí)將模型的頂點(diǎn)沿法線方向外拓,然后繪制描邊

    2023年04月08日
    瀏覽(89)
  • Unity文字描邊

    Unity文字描邊

    思路: 尋找邊界點(diǎn),均值平滑: Shader “UI-Effect/ImgOutline” { Properties { // [NoScaleOffset] _MainTex (“Main Texture”, 2D) = “black” {} }

    2024年02月12日
    瀏覽(88)
  • [Unity]給場(chǎng)景中的3D字體TextMesh增加描邊方案一

    取你的文本對(duì)象,簡(jiǎn)單地添加以下腳本:

    2024年02月05日
    瀏覽(91)
  • CSS實(shí)現(xiàn)文字描邊效果

    CSS實(shí)現(xiàn)文字描邊效果

    一、介紹 最近在一個(gè)項(xiàng)目的宣傳頁(yè)中,設(shè)計(jì)師使用了文字描邊效果,之前我確實(shí)沒有實(shí)現(xiàn)過(guò)文字的描邊效果,然后我在查閱資料后,知道了實(shí)現(xiàn)方法。文字描邊分為兩種:內(nèi)外雙描邊和單外描邊,也就是指在給文字加上描邊效果后,描邊的方向是向內(nèi)外同時(shí)占用文字空間還是

    2023年04月09日
    瀏覽(299)
  • 【CSS】文字描邊的三種實(shí)現(xiàn)方式

    【CSS】文字描邊的三種實(shí)現(xiàn)方式

    text-shadow –webkit-text-stroke svg MDN text-shadow 代碼 用 text-shadow 實(shí)現(xiàn)八個(gè)方向的文字陰影。 優(yōu)缺點(diǎn) 優(yōu)點(diǎn) 兼容性好 缺點(diǎn) 文字邊緣會(huì)有鋸齒。 如上圖,當(dāng)文字很大時(shí),尤其明顯。因?yàn)槲覀冎辉O(shè)置了8個(gè)方向的陰影,這些方向交界處容易出問(wèn)題。 文字必須設(shè)置顏色 如果我們把文字設(shè)

    2024年02月02日
    瀏覽(96)
  • CSS中如何實(shí)現(xiàn)文字描邊效果(Text Stroke)?

    CSS中如何實(shí)現(xiàn)文字描邊效果(Text Stroke)?

    前端入門之旅:探索Web開發(fā)的奇妙世界 歡迎來(lái)到前端入門之旅!感興趣的可以訂閱本專欄哦!這個(gè)專欄是為那些對(duì)Web開發(fā)感興趣、剛剛踏入前端領(lǐng)域的朋友們量身打造的。無(wú)論你是完全的新手還是有一些基礎(chǔ)的開發(fā)者,這里都將為你提供一個(gè)系統(tǒng)而又親切的學(xué)習(xí)平臺(tái)。在這個(gè)

    2024年02月09日
    瀏覽(91)
  • Unity中Shader序列圖動(dòng)畫(UV流動(dòng)的通用起始點(diǎn))

    Unity中Shader序列圖動(dòng)畫(UV流動(dòng)的通用起始點(diǎn))

    我們?cè)赟hader中實(shí)現(xiàn)序列幀動(dòng)畫??梢詫?shí)現(xiàn)一些簡(jiǎn)單特效或動(dòng)畫節(jié)省性能用。 我們?cè)谶@篇文章中,實(shí)現(xiàn)一下UV流動(dòng)的通用起始點(diǎn)。 先左到右,再?gòu)纳系较?Unity中 URP Shader 的紋理與采樣器的分離定義 屬性面板 _MainTex(“MainTex”,2D) = “white”{} 定義紋理 TEXTURE2D(_MainTex); 定義采樣器

    2024年01月17日
    瀏覽(110)
  • Unity 基于法線和深度實(shí)現(xiàn)完美描邊,可獨(dú)立控制物體描邊

    Unity 基于法線和深度實(shí)現(xiàn)完美描邊,可獨(dú)立控制物體描邊

    最近項(xiàng)目需要快速出一版卡通渲染風(fēng)格進(jìn)行吸量測(cè)試。但是原來(lái)的模型非常不適合使用back face 的描邊方案(很難看),不得已尋求其他的描邊方案,于是有了現(xiàn)在這篇基于法線和深度的后處理描邊。 優(yōu)點(diǎn): 描邊寬度一致。 重疊部分也能有描邊。 不會(huì)出現(xiàn)斷裂 缺點(diǎn): 后處理時(shí)

    2024年01月15日
    瀏覽(116)
  • Unity UGUI 邊緣泛光 描邊 的簡(jiǎn)單實(shí)現(xiàn)

    Unity UGUI 邊緣泛光 描邊 的簡(jiǎn)單實(shí)現(xiàn)

    先看效果 ?該效果是RawImage組件下實(shí)現(xiàn)。單純Shader實(shí)現(xiàn),不用c#輔助,當(dāng)然,肯定也有缺點(diǎn),在一些場(chǎng)合下或許不適用,我也希望能最大化適用,奈何技術(shù)有限。網(wǎng)上看過(guò)一些實(shí)現(xiàn)有些只適合3D,并且不適合棱角的,有些適用UI,效果也不錯(cuò),但是為了泛光范圍加大,性能指數(shù)

    2024年02月12日
    瀏覽(97)
  • [Unity] ShaderGraph實(shí)現(xiàn)Sprite圖片描邊/發(fā)光效果

    [Unity] ShaderGraph實(shí)現(xiàn)Sprite圖片描邊/發(fā)光效果

    使用版本為:2022.3.10f1? [原始圖]? ? ? [運(yùn)行前]? ? ? [運(yùn)行后] 更詳細(xì)的實(shí)現(xiàn)邏輯及步驟參考CodeMonkey的視頻: https://youtu.be/FvQFhkS90nI?si=zy6XRlqGnzIdQkqD OS:猴子老師,我永遠(yuǎn)的神?。?! 目錄 一、準(zhǔn)備工作 二、偏移效果與顏色疊加 三、單側(cè)描邊與原理 四、另一側(cè)與Sub管理 五、

    2024年01月20日
    瀏覽(109)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包