实现Sprite的Circle Fill效果及打了图集出现的问题

实现Sprite的Circle Fill效果及打了图集出现的问题

1、 实现Sprite的Circle Fill效果,基本的Shader如下:

Shader "Sprites/SpriteCircleFill"
{
    Properties
    {
     _MainTex("MainTex", 2D) = "white" {}
     _Color("Tint", Color) = (1,1,1,1)
     [MaterialToggle] PixelSnap("Pixel snap", Float) = 0
     _Fill("Fill",Range(0,1)) = 0
    }

        SubShader
     {
         Tags
         {
             "Queue" = "Transparent"
             "IgnoreProjector" = "True"
             "RenderType" = "Transparent"
             "PreviewType" = "Plane"
             "CanUseSpriteAtlas" = "True"
         }

         Cull Off
         Lighting Off
         ZWrite Off
         Fog {Mode Off}
         Blend SrcAlpha OneMinusSrcAlpha

         Pass{
         CGPROGRAM
         #pragma vertex vert		 
         #pragma fragment frag	
         #pragma multi_compile DUMMY PIXELSNAP_ON
         // #include "UnitySprites.cginc"
         #include "UnityCG.cginc"

        struct appdata_t
        {
            float4 vertex:POSITION;
            float4 color:COLOR;
            float2 uv:TEXCOORD1;
        };

       struct v2f
       {
           float4 vertex:SV_POSITION;
           fixed4 color:COLOR;
           half2 uv:TEXCOORD1;
       };
       
       fixed4 _Color;
      sampler2D _MainTex;
      float4 _MainTex_ST;
      float _Fill;

       v2f vert(appdata_t IN)
       {
           v2f OUT;
           OUT.vertex = UnityObjectToClipPos(IN.vertex);
           OUT.uv = IN.uv.xy * _MainTex_ST.xy + _MainTex_ST.zw; // uv 缩放和偏移
           OUT.color = IN.color * _Color;
           #ifdef PIXELSNAP_ON
           OUT.vertex = UnityPixelSnap(OUT.vertex);
           #endif
           return OUT;
       }

       fixed4 frag(v2f IN) :COLOR
       {
           fixed4 resultColor = tex2D(_MainTex, IN.uv) * IN.color; // 对主帖图进行采样
           fixed2 p = fixed2(IN.uv.x - 0.5, IN.uv.y - 0.5); // 可以理解为 对Sprite进行了上下和左右的区分.
           if (_Fill < 0.5)
           {
               float compare = (_Fill * 2 - 0.5) * 3.1415926;
               float theta = atan(p.y / p.x);
               if (theta >= compare)
               {
                   resultColor.a = 0;
               }
               if (p.x > 0) // Sprite 的左半部分全透明
               {
                   resultColor.a = 0;
               }
           }
           else
           {
               float compare = ((_Fill - 0.5) * 2 - 0.5) * 3.1415926;
               float theta = atan(p.y / p.x);
               if (p.x > 0)
               {
                   if (theta > compare) // 满足Sprite的左半部分,并且弧度值在范围内的片元,透明.
                   {
                       resultColor.a = 0;
                   }
               }
           }
           return resultColor;
       }
       ENDCG
       }
     }
         Fallback "Transparent/VertexLit"
}

2、 显示效果如下:
实现Sprite的Circle Fill效果及打了图集出现的问题_第1张图片

这是没有打图集或者Unity非运行状态下的情况,使用的贴图,就是一张原贴图,但是在打了图集运行状态下,会出现以下情况:

实现Sprite的Circle Fill效果及打了图集出现的问题_第2张图片
主帖图自动变成图集,这时候片元着色器计算的UV坐标还是在[0,1]范围内,但是此张贴图在图集里边的UV坐标范围也许是[0,0.13],[0.17,0.3],分别对应该张贴图在图集下的UV左下角和右上角的坐标。处理这个问题,只有对UV进行归一化处理,将[0,0.13],[0.17,0.3]映射到[0,1]范围内。
3、 归一化处理:
这个时候,就应在Shader中加入两个属性,一个是贴图在图集中的实际UV坐标_UVRect,以及在图集中的缩放_UVScale,用来做归一化计算。
实现Sprite的Circle Fill效果及打了图集出现的问题_第3张图片
在CG代码片段定义两个变量和Properties关联
在这里插入图片描述
在片元着色器中进行归一化处理,并且是在贴图采样后进行计算.
float2 center = (_UVRect.zw - _UVRect.xy) / 2; // 计算的这个贴图的中心点
IN.uv = IN.uv - _UVRect.xy - center;
IN.uv = IN.uv * _UVScale;
IN.uv = IN.uv + center;
IN.uv = IN.uv / (_UVRect.zw - _UVRect.xy);
这个时候,只在Shader的顶点着色器中获取的UV坐标还存在问题,是针对原贴图进行的采集,所以需要在初始化的时候,设置贴图在该贴图下的UV坐标,在C#中写入:
public class SpriteFill : MonoBehaviour
{
private void Start()
{
SpriteRenderer sprite = transform.GetComponent();
Vector4 uvRect = UnityEngine.Sprites.DataUtility.GetOuterUV(sprite.sprite);
Rect originalRect = sprite.sprite.rect;
Rect textureRect = sprite.sprite.textureRect;
float scalex = textureRect.width / originalRect.width;
float scaley = textureRect.height / originalRect.height;
sprite.material.SetVector(“_UVRect”, uvRect);
sprite.material.SetVector(“_UVScale”, new Vector4(scalex, scaley, 0, 0));
}
}
采用了UnityEngine.Sprites.DataUtility.GetOuterUV函数,计算缩放的时候,采用了sprite.rect和sprite.textureRect的宽和高,但是一定要注意图集的TightPacking设置取消勾选,否者sprite.textureRect会出现异常,宽和高返回结果会为0。缩放不正确,归一化计算不正确。该脚本挂载在要进行Fill的Sprite上。
实现Sprite的Circle Fill效果及打了图集出现的问题_第4张图片
此时效果如下:
实现Sprite的Circle Fill效果及打了图集出现的问题_第5张图片
修改后的Shader如下:
Shader “Sprites/SpriteCircleFill”
{
Properties
{
_MainTex(“MainTex”, 2D) = “white” {}
_Color(“Tint”, Color) = (1,1,1,1)
[MaterialToggle] PixelSnap(“Pixel snap”, Float) = 0
_Fill(“Fill”,Range(0,1)) = 0
_UVRect (“UVRect”,vector) = (0,1,0,1)
_UVScale(“UVScale”,vector) = (1,1,0,0)
}

    SubShader
 {
     Tags
     {
         "Queue" = "Transparent"
         "IgnoreProjector" = "True"
         "RenderType" = "Transparent"
         "PreviewType" = "Plane"
         "CanUseSpriteAtlas" = "True"
     }

     Cull Off
     Lighting Off
     ZWrite Off
     Fog {Mode Off}
     Blend SrcAlpha OneMinusSrcAlpha

     Pass{
     CGPROGRAM
     #pragma vertex vert		 
     #pragma fragment frag	
     #pragma multi_compile DUMMY PIXELSNAP_ON
     // #include "UnitySprites.cginc"
     #include "UnityCG.cginc"

    struct appdata_t
    {
        float4 vertex:POSITION;
        float4 color:COLOR;
        float2 uv:TEXCOORD1;
    };
    
   struct v2f
   {
       float4 vertex:SV_POSITION;
       fixed4 color:COLOR;
       half2 uv:TEXCOORD1;
   };
   
   fixed4 _Color;
   sampler2D _MainTex;
   float4 _MainTex_ST;
   float _Fill;
   float4 _UVRect;
   float4 _UVScale;

   v2f vert(appdata_t IN)
   {
       v2f OUT;
       OUT.vertex = UnityObjectToClipPos(IN.vertex);
       OUT.uv = IN.uv.xy * _MainTex_ST.xy + _MainTex_ST.zw;
       OUT.color = IN.color * _Color;
       #ifdef PIXELSNAP_ON
       OUT.vertex = UnityPixelSnap(OUT.vertex);
       #endif
       return OUT;
   }

   fixed4 frag(v2f IN) :COLOR
   {
       fixed4 resultColor = tex2D(_MainTex, IN.uv) * IN.color;
       float2 center = (_UVRect.zw - _UVRect.xy) / 2;
       IN.uv = IN.uv - _UVRect.xy - center;
       IN.uv = IN.uv * _UVScale;
       IN.uv = IN.uv + center;
       IN.uv = IN.uv / (_UVRect.zw - _UVRect.xy);
       fixed2 p = fixed2(IN.uv.x - 0.5, IN.uv.y - 0.5);

       if (_Fill < 0.5)
       {
           float compare = (_Fill * 2 - 0.5) * 3.1415926;
           float theta = atan(p.y / p.x);
           if (theta >= compare)
           {
               resultColor.a = 0;
           }
           if (p.x > 0)
           {
               resultColor.a = 0;
           }
       }
       else
       {
           float compare = ((_Fill - 0.5) * 2 - 0.5) * 3.1415926;
           float theta = atan(p.y / p.x);
           if (p.x > 0)
           {
               if (theta > compare)
               {
                   resultColor.a = 0;
               }
           }
       }
       return resultColor;
   }
   ENDCG
   }
 }
     Fallback "Transparent/VertexLit"

}

你可能感兴趣的:(unity,游戏引擎)