实现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、 显示效果如下:
在这里插入图片描述

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

在这里插入图片描述
主帖图自动变成图集,这时候片元着色器计算的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,用来做归一化计算。
在这里插入图片描述
在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上。
在这里插入图片描述
此时效果如下:
在这里插入图片描述
修改后的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"

}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
UnitySprite Multiple功能是用来处理多个图片在一个图集中的情况的。在使用这个功能之前,你需要准备一个包含多个小图的大图集。然后,你可以通过以下步骤来拆分这个图集。 首先,打开Unity编辑器,并将大图集导入到项目中。将图集拖拽到场景中的一个空的游戏对象上,创建一个Sprite Renderer组件。然后,将Sprite Mode设置为Multiple,这样unity就会把图集视为一个多精灵图。 接下来,点击Sprite Editor按钮,这会打开Sprite Editor窗口。在窗口中,你会看到图集中所有小图的预览。你可以使用鼠标选择并拖拽来选择一个小图,并在预览面板中预览选择的小图。 在Sprite Editor窗口的左侧,你可以调整小图的位置和大小,以确保它们正确地对应着图集中的位置。你还可以裁剪小图来确保只显示你想要的部分。你可以使用切分工具来裁剪小图,也可以使用设置工具来调整其精确位置和大小。 一旦你完成了所有的拆分和调整,点击Apply按钮来应用更改。此时,unity会自动创建一个Sprite Asset,它会将图集中的每个小图作为一个独立的精灵。 现在,你可以在Unity中使用这些独立的精灵了。你可以将它们分别用于不同的游戏对象,也可以使用Sprite Renderer组件的Sprite属性来动态更换精灵。 总的来说,UnitySprite Multiple功能非常方便,它使得管理和使用图集中的多个小图变得简单而高效。无论是制作2D游戏还是创建用户界面,都可以通过这个功能来提高工作效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值