当前位置:   article > 正文

【Unity Shader】Sprite实现Image的环形填充_怎么在圆环内外部填充颜色 unity

怎么在圆环内外部填充颜色 unity

游戏中NPC脚下的地面上通常会显示其攻击范围。如果NPC具有视野属性,那么这个攻击范围就可能是任意角度。就需要Sprite如同Image组件一样可以360度填充。

不过Image的角度填充是在C#层实现的,无法套用在Sprite上。

 参照Unity内置shader,Sprites-Default.shader :

  1. Pass
  2. {
  3. CGPROGRAM
  4. #pragma vertex SpriteVert
  5. #pragma fragment SpriteFrag
  6. #pragma target 2.0
  7. #pragma multi_compile_instancing
  8. #pragma multi_compile_local _ PIXELSNAP_ON
  9. #pragma multi_compile _ ETC1_EXTERNAL_ALPHA
  10. #include "UnitySprites.cginc"
  11. ENDCG
  12. }

Sprite的shader相当简短,因为它的顶点/片元着色器全都是在UnitySprites.cginc里实现。参考默认片元着色器函数SpriteFrag的实现,自定义片元着色器:

  1. Pass
  2. {
  3. CGPROGRAM
  4. #pragma vertex SpriteVert
  5. #pragma fragment MySpriteFrag
  6. #pragma target 2.0
  7. #pragma multi_compile_instancing
  8. #pragma multi_compile_local _ PIXELSNAP_ON
  9. #pragma multi_compile _ ETC1_EXTERNAL_ALPHA
  10. #include "UnitySprites.cginc"
  11. fixed4 MySpriteFrag(v2f IN) : SV_Target
  12. {
  13. fixed4 c = SampleSpriteTexture (IN.texcoord) * IN.color;
  14. c.rgb *= c.a;
  15. return c;
  16. }
  17. ENDCG
  18. }

 根据角度填充圆形Sprite,首先根据UV坐标判断角度,角度大于限定值的区域不显示。夹角的计算很简单,还有一个更简单的方法就是Unity有现成的函数Vector3.Angle(Vector3 dirA, Vector3 dirB),把函数实现移植到shader中:

  1. fixed GetAngle(fixed2 from, fixed2 to){
  2. float denominator = sqrt((from.x*from.x + from.y*from.y) * (to.x*to.x + to.y * to.y));
  3. if (denominator < 0.000001)
  4. return 0;
  5. float dotNum = clamp(dot(from, to) / denominator, -1.0, 1.0);
  6. return degrees(acos(dotNum));
  7. }

判断当前UV坐标方向相对坐标系Y轴正方向的夹角,并把限定角度外的像素设置为透明:

  1. fixed4 MySpriteFrag(v2f IN) : SV_Target
  2. {
  3. fixed4 c = SampleSpriteTexture (IN.texcoord) * IN.color;
  4. fixed2 uvCenter = fixed2(0.5, 0.5);
  5. fixed absAngle = GetAngle(fixed2(0,1), IN.texcoord - uvCenter);
  6. c.a *= absAngle <= _Angle;
  7. c.rgb *= c.a;
  8. return c;
  9. }

 中心的角度比较尖锐,为了美观通常还会对近点进行裁剪,将圆心掏空。实现原理就是把距离圆心一定距离内的像素改为全透明:

  1. fixed4 MySpriteFrag(v2f IN) : SV_Target
  2. {
  3. fixed4 c = SampleSpriteTexture (IN.texcoord) * IN.color;
  4. fixed2 uvCenter = fixed2(0.5, 0.5);
  5. fixed absAngle = GetAngle(fixed2(0,1), IN.texcoord - uvCenter);
  6. c.a *= (absAngle <= _Angle) * distance(IN.texcoord, uvCenter)*2 > _NearClip;
  7. c.rgb *= c.a;
  8. return c;
  9. }

完整shader:

  1. Shader "Custom/SpriteFillCircle"
  2. {
  3. Properties
  4. {
  5. [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
  6. _Color ("Tint", Color) = (1,1,1,1)
  7. _Angle ("Angle", Range(0,180)) = 30
  8. _NearClip ("Near Clip", Range(0,1)) = 0.1
  9. [MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
  10. [HideInInspector] _RendererColor ("RendererColor", Color) = (1,1,1,1)
  11. [HideInInspector] _Flip ("Flip", Vector) = (1,1,1,1)
  12. [PerRendererData] _AlphaTex ("External Alpha", 2D) = "white" {}
  13. [PerRendererData] _EnableExternalAlpha ("Enable External Alpha", Float) = 0
  14. }
  15. SubShader
  16. {
  17. Tags
  18. {
  19. "Queue"="Transparent"
  20. "IgnoreProjector"="True"
  21. "RenderType"="Transparent"
  22. "PreviewType"="Plane"
  23. "CanUseSpriteAtlas"="True"
  24. }
  25. Cull Off
  26. Lighting Off
  27. ZWrite Off
  28. Blend One OneMinusSrcAlpha
  29. Pass
  30. {
  31. CGPROGRAM
  32. #pragma vertex SpriteVert
  33. #pragma fragment MySpriteFrag
  34. #pragma target 2.0
  35. #pragma multi_compile_instancing
  36. #pragma multi_compile_local _ PIXELSNAP_ON
  37. #pragma multi_compile _ ETC1_EXTERNAL_ALPHA
  38. #include "UnitySprites.cginc"
  39. float _Angle;
  40. float _NearClip;
  41. fixed GetAngle(fixed2 from, fixed2 to){
  42. float denominator = sqrt((from.x*from.x + from.y*from.y) * (to.x*to.x + to.y * to.y));
  43. if (denominator < 0.000001)
  44. return 0;
  45. float dotNum = clamp(dot(from, to) / denominator, -1.0, 1.0);
  46. return degrees(acos(dotNum));
  47. }
  48. fixed4 MySpriteFrag(v2f IN) : SV_Target
  49. {
  50. fixed4 c = SampleSpriteTexture (IN.texcoord) * IN.color;
  51. fixed2 uvCenter = fixed2(0.5, 0.5);
  52. fixed absAngle = GetAngle(fixed2(0,1), IN.texcoord - uvCenter);
  53. c.a *= (absAngle <= _Angle) * distance(IN.texcoord, uvCenter)*2 > _NearClip;
  54. c.rgb *= c.a;
  55. return c;
  56. }
  57. ENDCG
  58. }
  59. }
  60. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/107671?site
推荐阅读
相关标签
  

闽ICP备14008679号