Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

UV Texture Coordinates Bounds using Sprite Packer

Discussion in 'Shaders' started by joaobsneto, Apr 26, 2016.

  1. joaobsneto

    joaobsneto

    Joined:
    Dec 10, 2009
    Posts:
    152
    I'm writing a shader to make a colored glow on Unity UI Images like Fireworks/Photoshop Glow Effect. I found some examples on the internet and I can make it work fine in the Editor, but when I run the game on Android, it does not work. I spend a lot of time figuring what may be the problem and I realized that in the Editor mode the Sprite Packer was disabled and the shader works fine with a single sprite, but when the sprite is packed the shader doesn't work. The issue must be on those lines of code:

    Code (Cg):
    1. const half2 centerPos = half2(0.5, 0.5);
    2. half dist = max(2*distance(IN.texcoord, centerPos)-shinestart,0);
    The idea of the shader is to make a radial effect and it needs the center of the image.The texcoord is relative to the Atlas image, so the centerPos is not the center of the image, but the center of the Atlas itself. Can I have the access to the current sprite's bounds and center position?

    Thanks!
     
    howong likes this.
  2. joaobsneto

    joaobsneto

    Joined:
    Dec 10, 2009
    Posts:
    152
    I found the solution with help of this thread: http://forum.unity3d.com/threads/relative-texcoord-when-using-sprite-atlas.400450/#post-2615298
    You have to send the sprite bounds to the shader using scripting language.
    Here's the shader, if you have any tips to make it better, please, send me.

    Code (CG):
    1.  
    2. Shader "Sprites/ShinyDefault"
    3. {
    4.     Properties
    5.     {
    6.         [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
    7.         _Color ("Tint", Color) = (1,1,1,1)
    8.        
    9.         _LightColor("LightColor", Color) = (1,1,1,1)
    10.         _ShineWidth("ShineWidth", Range(0,1)) = 0
    11.         _Rect ("Rect Display", Vector) = (0,0,1,1)
    12.        
    13.         _StencilComp ("Stencil Comparison", Float) = 8
    14.         _Stencil ("Stencil ID", Float) = 0
    15.         _StencilOp ("Stencil Operation", Float) = 0
    16.         _StencilWriteMask ("Stencil Write Mask", Float) = 255
    17.         _StencilReadMask ("Stencil Read Mask", Float) = 255
    18.  
    19.         _ColorMask ("Color Mask", Float) = 15
    20.  
    21.         [Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip ("Use Alpha Clip", Float) = 0
    22.     }
    23.  
    24.     SubShader
    25.     {
    26.         Tags
    27.         {
    28.             "Queue"="Transparent"
    29.             "IgnoreProjector"="True"
    30.             "RenderType"="Transparent"
    31.             "PreviewType"="Plane"
    32.             "CanUseSpriteAtlas"="True"
    33.         }
    34.        
    35.         Stencil
    36.         {
    37.             Ref [_Stencil]
    38.             Comp [_StencilComp]
    39.             Pass [_StencilOp]
    40.             ReadMask [_StencilReadMask]
    41.             WriteMask [_StencilWriteMask]
    42.         }
    43.  
    44.         Cull Off
    45.         Lighting Off
    46.         ZWrite Off
    47.         ZTest [unity_GUIZTestMode]
    48.         Blend SrcAlpha OneMinusSrcAlpha
    49.         ColorMask [_ColorMask]
    50.  
    51.         Pass
    52.         {
    53.         CGPROGRAM
    54.             #pragma vertex vert
    55.             #pragma fragment frag
    56.  
    57.             #include "UnityCG.cginc"
    58.             #include "UnityUI.cginc"
    59.  
    60.             #pragma multi_compile __ UNITY_UI_ALPHACLIP
    61.            
    62.             struct appdata_t
    63.             {
    64.                 float4 vertex   : POSITION;
    65.                 float4 color    : COLOR;
    66.                 float2 texcoord : TEXCOORD0;
    67.             };
    68.  
    69.             struct v2f
    70.             {
    71.                 float4 vertex   : SV_POSITION;
    72.                 fixed4 color    : COLOR;
    73.                 half2 texcoord  : TEXCOORD0;
    74.                 float4 worldPosition : TEXCOORD1;
    75.             };
    76.            
    77.             fixed4 _Color;
    78.             fixed4 _LightColor;
    79.             fixed4 _TextureSampleAdd;
    80.             fixed4 _Rect;
    81.             float4 _ClipRect;
    82.             half _ShineWidth;
    83.  
    84.             v2f vert(appdata_t IN)
    85.             {
    86.                 v2f OUT;
    87.                 OUT.worldPosition = IN.vertex;
    88.                 OUT.vertex = mul(UNITY_MATRIX_MVP, OUT.worldPosition);
    89.  
    90.                 OUT.texcoord = IN.texcoord;
    91.                
    92.                 #ifdef UNITY_HALF_TEXEL_OFFSET
    93.                 OUT.vertex.xy += (_ScreenParams.zw-1.0)*float2(-1,1);
    94.                 #endif
    95.                
    96.                 OUT.color = IN.color * _Color;
    97.                 return OUT;
    98.             }
    99.  
    100.             sampler2D _MainTex;
    101.             float4 _MainTex_TexelSize;
    102.        
    103.            
    104.             fixed4 frag(v2f IN) : SV_Target
    105.             {
    106.                
    107.                 const half v = 4;
    108.                 half xVal = v*_MainTex_TexelSize.x*_ShineWidth;
    109.                 half yVal = v*_MainTex_TexelSize.y*_ShineWidth;
    110.                 half2 offX = half2(xVal, yVal);
    111.                 half2 offY = half2(xVal, -yVal);
    112.                 half colorGlow = (tex2D(_MainTex, clamp(IN.texcoord + offY, _Rect.xy, _Rect.zw))).a +
    113.                                 (tex2D(_MainTex, clamp(IN.texcoord - offY, _Rect.xy, _Rect.zw))).a +
    114.                                 (tex2D(_MainTex, clamp(IN.texcoord + offX, _Rect.xy, _Rect.zw))).a +
    115.                                 (tex2D(_MainTex, clamp(IN.texcoord - offX, _Rect.xy, _Rect.zw))).a;
    116.                 const float C = 0.796;
    117.                 colorGlow = saturate(2*sin(colorGlow*C));
    118.                 half4 color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd) * IN.color;
    119.                 color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect);
    120.                 half2 centerPos = half2((_Rect.x+_Rect.z)/2, (_Rect.y+_Rect.w)/2);
    121.                 half maxDist = sqrt(pow((_Rect.z-_Rect.x)/2,2) + pow((_Rect.w-_Rect.y)/2,2));
    122.                 half shinestart = (1-_ShineWidth)*maxDist;
    123.                 half dist = max(distance(IN.texcoord, centerPos)-shinestart,0);
    124.                 half whitePower = color.a*(dist/((max(_ShineWidth,.01)*maxDist)));
    125.                 color.rgb = lerp(color.rgb, _LightColor.rgb, whitePower);
    126.                 color = lerp(color,_LightColor, colorGlow);
    127.                 #ifdef UNITY_UI_ALPHACLIP
    128.                 clip (color.a - 0.001);
    129.                 #endif
    130.                 return color;
    131.             }
    132.         ENDCG
    133.         }
    134.     }
    135. }
    136.  
    And in the scripting language, you have to set the _Rect property. You have to set only when you chance the sprite image:

    Code (CSharp):
    1.  
    2. image = GetComponent<Image> ();
    3.         Sprite sprite = image.sprite;
    4.         Vector4 result = new Vector4(sprite.textureRect.min.x/sprite.texture.width,
    5.             sprite.textureRect.min.y/sprite.texture.height,
    6.             sprite.textureRect.max.x/sprite.texture.width,
    7.             sprite.textureRect.max.y/sprite.texture.height);
    8.         image.material.SetVector ("_Rect", result);
    The result:
    shine_shader.fw.png
     
  3. Ruzihm

    Ruzihm

    Joined:
    Aug 4, 2013
    Posts:
    4
    Thank you so much for this!! This tutorial was exactly what I needed. This was what I used to convert from local uv to atlas uv:

    Code (CSharp):
    1. float2 localuv = (i.uv - _Rect.xy) / (_Rect.zw - _Rect.xy);
     
    pvnetto likes this.