Alpha pixels being cut out in simple uv shift shader

We have clouds in a game that are being animated by shifting the x uv during runtime. They are using sprite renderers! I wrote a very simple shader that accomplishes this except there’s one issue, where the original transparent pixels are is being cut out. Is there a property or something or is this a limitation of sticking with the sprite renderer? (I understand I can create a quad mesh with the texture but there are some nice freebies with using sprites such as packing).

2347208--158878--Clouds.gif
Note the bottom pixels being cut out where the original clouds are transparent!

Here’s the shader I wrote, maybe I am doing something dumb :slight_smile:

Shader "Custom/ShiftXUV"
{
    Properties
    {
        _MainTex ("Sprite Texture", 2D) = "white" {}
        _maxSpeed ("Max Speed", Float) = 0
    }
    SubShader
    {
        Tags
        {
            "Queue"="Transparent"
            "IgnoreProjector"="True"
            "RenderType"="Transparent"
            "PreviewType"="Plane"
            "CanUseSpriteAtlas"="True"
        }

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

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
         
            struct appdata
            {
                float4 vertex : POSITION;
                half2 uv : TEXCOORD0;
                fixed3 speedAmount : COLOR;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
                half2 texCoord : TEXCOORD0;
                fixed3 speedAmount : COLOR;
            };

            sampler2D _MainTex;
            uniform float _maxSpeed;
            uniform float _time;
         
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
                o.texCoord = v.uv;
                o.speedAmount = v.speedAmount;
                return o;
            }
         
            fixed4 frag (v2f i) : SV_Target
            {
                float2 uv = i.texCoord;
                uv.x = frac(uv.x + i.speedAmount.x * _maxSpeed * _time);

                fixed4 col = tex2D(_MainTex, uv);
                col.rgb *= col.a;
                return col;
            }
            ENDCG
        }
    }
}

Thanks!

Nothing strikes me as wrong in the shader in terms of what would cause what you’re seeing, though I don’t do anything with sprites.

A few notes though:

  • I would try to do most of the UV offset code in vert instead of in frag. This might solve the transparency issue you’re seeing as well. Don’t do a frac() on the whole uv in the vert shader though, rather uv + frac(speed * max * time);
  • You’re using float _time, I assume this is something you’re passing in yourself? You can just use _Time.y (it’s a float4, use capital T, .y component not .x) instead as that’s passed to all shaders automatically. Unity - Manual: Built-in shader variables
  • Using a sprite atlas on panning materials is semi-dangerous. Once it’s atlased there’s no knowing where the actual bounds of the texture are so things like frac() to wrap the UVs as the texture is no longer between uvs 0.0 and 1.0, it might be between 0.25 and 0.375.
1 Like

Thanks for the tips!

I didn’t know about _Time.y and you’re absolutely right that I’ll run into issues once I actually atlas the different images. Unfortunately, even if I shift uvs in the vert function, I still have the alpha cut out where the original alpha pixels were so that doesn’t solve that issue. :frowning:

Hi,

if it helps you, your shader works for me and my “cloud” :slight_smile:
I made a arbitrary form with transparency and saved it as png. Afterwards I imported it as sprite and put it into the scene with your shader set in the sprite renderer and the shader works for me. No artifacts or similar.
Maybe there is some problem with the image you are using or how you imported it.

2349803--159085--Cloud.png

I’ll give it a shot!