扇形技能指示器


扇形技能指示器

網上基本有兩種方法寫扇形指示器:

  1. 生成Mesh拼接
  2. Shader繪制

Mesh拼接

我這邊用Unity自帶的Gizmos簡單的繪制一下Mesh

注意:Gizmos.DrawMesh()中的Mesh必須包含vertices和normals

生成vertices

/// <summary>
/// 生成vertices
/// </summary>
/// <param name="precision">三角形數量</param>
/// <param name="originPos">原點</param>
/// <param name="forward">朝向</param>
/// <returns>vertuces</returns>
private Vector3[] GetVectors(int precision, Vector3 originPos, Vector3 forward)
{
    // 一共需要三角形數量+2的頂點數
    Vector3[] meshVectors = new Vector3[precision + 2];
    // 每個三角形的角度
    float meshRadius = angle / precision;
    // 起始三角形朝向
    forward = Quaternion.AngleAxis(-angle / 2, Vector3.up) * forward;
    // 特殊設置0與1的頂點位置
    meshVectors[0] = originPos;
    meshVectors[1] = originPos + forward * radius;
    // 后續定點按規律生成
    for (int i = 2; i < precision + 2; i++)
    {
        // 旋轉一個三角形的朝向
        forward = Quaternion.AngleAxis(meshRadius, Vector3.up) * forward;
        // 設置定點
        meshVectors[i] = originPos + forward * radius;
    }
    return meshVectors;
}

生成Triangles

/// <summary>
/// 生成triangles
/// </summary>
/// <param name="precision">三角形數量</param>
/// <returns>triangles</returns>
private int[] GetTriangles(int precision)
{
    // 每個三角形三個triangle
    int[] meshTriangles = new int[precision * 3];
    // 按規律生成
    for (int i = 0; i < precision; i++)
    {
        int id = i * 3;
        meshTriangles[id] = 0;
        meshTriangles[id + 1] = i + 1;
        meshTriangles[id + 2] = i + 2;
    }
    return meshTriangles;
}

利用OnDrawGizmos繪制三角形

public float angle; // 角度
public float radius; // 半徑
public int precision; // 三角形數量(越多約成圓,效率越低)
public GameObject origin; // 原點GameObject(表示原點位置用)
private void OnDrawGizmos()
{
    Mesh mesh = new Mesh();
    mesh.vertices = GetVectors(precision, origin.transform.position, origin.transform.forward);
    mesh.triangles = GetTriangles(precision);
    // 生成normals
    mesh.RecalculateNormals();
    Gizmos.color = Color.red;
    // 畫線框(Mesh會擋住線框的繪制)
    for (int i = 1; i < mesh.vertices.Length; i++)
    {
        Gizmos.DrawLine(mesh.vertices[0], mesh.vertices[i]);
        Gizmos.DrawLine(mesh.vertices[i], mesh.vertices[i - 1]);
    }
    // 畫Mesh
    Gizmos.DrawMesh(mesh);
}

Shader繪制

屬性

_Inner ("Inner Texture", 2D) = "white" {} // 內圈貼圖
_Outer ("Outer Texture", 2D) = "white" {} // 外圈貼圖
_Color ("Color", Color) = (1, 1, 1, 1)    // 顏色
_Angle ("Angle", Range(0, 360)) = 60	  // 角度
_OutLine ("Out Line", Range(0, 1)) = 0.1  // 外圈寬度

核心剔除代碼

fixed4 frag(fragmentInput i) : SV_Target 
{
	// 距離超過半徑則剔除
    float distance = pow(i.uv.x - 0.5, 2) + pow(i.uv.y - 0.5, 2);
    if (distance > 0.25f) {
        discard;
    }

    float x = i.uv.x;
    float y = i.uv.y;
    float deg2rad = 0.017453; // 角度轉弧度

    if (_Angle > 180) {
        if(y > 0.5 && abs(0.5 - y) >= abs(0.5 - x) / tan((180 - _Angle / 2) * deg2rad)) {
        	discard;
        }
        else {
        if(y > 0.5 || abs(0.5 -y) < abs(0.5 - x) / tan(_Angle / 2 * deg2rad)) {
        	discard;
        }
    }
	// 外圈顯示比例
    float outDis = 0.25 * pow((1 - _OutLine), 2);

    if (distance > outDis) {
    	// 外圈繪制
    	return tex2D(_Outer, i.uv) * _Color;
    }
    else {
    	// 內圈繪制
    	return tex2D(_Inner, i.uv) * _Color;
    }
}
Shader "Unlit/SectorShader" 
{
    Properties {
        _Inner ("Inner Texture", 2D) = "white" {}
        _Outer ("Outer Texture", 2D) = "white" {}
        _Color ("Color", Color) = (1, 1, 1, 1)
        _Angle ("Angle", Range(0, 360)) = 60
        _OutLine ("Out Line", Range(0, 1)) = 0.1
    }

    SubShader {
        Tags { "Queue"="Transparent" "RenderType"="Transparent" "IgnoreProjector"="True" }
        Pass {
            ZWrite Off
            Blend SrcAlpha OneMinusSrcAlpha
            CGPROGRAM
 
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            sampler2D _Inner;
            sampler2D _Outer;
            float4 _Color;
            float _Angle;
            float _OutLine;
 
            struct fragmentInput 
            {
                float4 pos : SV_POSITION;
                float2 uv : TEXCOORD0;
            };

            fragmentInput vert (appdata_base v)
            {
                fragmentInput o;

                o.pos = UnityObjectToClipPos (v.vertex);
                o.uv = v.texcoord.xy;

                return o;
            }
 
            fixed4 frag(fragmentInput i) : SV_Target 
            {
                float distance = pow(i.uv.x - 0.5, 2) + pow(i.uv.y - 0.5, 2);
                if (distance > 0.25f)
                {
                    discard;
                }
                
                float x = i.uv.x;
                float y = i.uv.y;
                float deg2rad = 0.017453; // 角度轉弧度

                if (_Angle > 180)
                {
                    if(y > 0.5 && abs(0.5 - y) >= abs(0.5 - x) / tan((180 - _Angle / 2) * deg2rad))
                    {
                        discard;
                    }
                }
                else
                {
                    if(y > 0.5 || abs(0.5 -y) < abs(0.5 - x) / tan(_Angle / 2 * deg2rad))
                    {
                        discard;
                    }
                }
                
                float outDis = 0.25 * pow((1 - _OutLine), 2);
                
                if (distance > outDis)
                {
                    return tex2D(_Outer, i.uv) * _Color;
                }
                else
                {
                    return tex2D(_Inner, i.uv) * _Color;
                }
            }
            
            ENDCG
        }
    }  
    FallBack "Diffuse"
}


免責聲明!

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



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