Trouble with simple shader

Hey guys, so I’m currently trying to workaround the inability to infinitely repeat a sprite background using the sprite default texture by making a normal texture shader and adjusting the material.mainTextureOffset property. However, every once in a while, there is some pretty gnarly distortion on the pixels (as shown in the picture attached)

The shader is below. The screen above is 320x160px and the test sprite show on screen is a scaled up version (using transform.localscale and a spriterenderer) of a 32x32px sprite (so that it covers the whole screen)

I would love to hear any ideas, as shader code really isn’t my forte, and I’m kind of banging my head against the wall trying to get this to work

Shader "Unlit/Unlit_Mine"
{
    Properties
    {
        [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
    }
    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 _ PIXELSNAP_ON
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                #ifdef PIXELSNAP_ON
                o.vertex = UnityPixelSnap (o.vertex);
                #endif
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                fixed4 col = tex2D(_MainTex, i.uv);
                return col;
            }
            ENDCG
        }
    }
}

bump!

You are just adding your offset all the time? Did you try looping smaller numerical space, using modulo or something else? Like cyclic repeating 0-1, instead of going to big numbers…

Yeah, so the ppu in my game is 16, so I’m adding in increments of 0.0625f (which is 1/16). This is the code I use to adjust the offset:

currentScroll.x += (scrollSpeed.x * dirSwitcherAdjuster.x * Time.deltaTime);
currentScroll.y += (scrollSpeed.y * dirSwitcherAdjuster.y * Time.deltaTime);
currentScroll.y %= 1;
currentScroll.x %= 1;
thisMaterial.mainTextureOffset = currentScroll;

currentScroll is a vector2 that I directly pass into the mainTexture offset. It starts at 0, 0

scrollSpeed is a vector2 that has the actual amount I want to move the texture per second (in increments of 0.0625f). So if I wanted the texture to scroll halfway horizontally per second, I would store 0.5f in scrollspeed.x

dirSwitcherAdjuster is me taking Mathf.Sin of an increment of time (usually 5-10 seconds) and multiplying it with scrollSpeed to move the texture in the opposite of its initial direction

I have a suspicion that using dirSwitcherAdjuster is giving the shader some weird floating point values for the pixels, since it’s not a multiple of 0.0625f, but I’m really not sure…

I mean, just the multiply by the delta time is going to make it not be steps of 0.0625f, because Unity doesn’t work on perfectly fixed time steps.

If you want to ensure the offsets are perfectly the steps you want, keep the math as you have it, then quantize the value before setting it on the offset.
thisMaterial.mainTextureOffset = Mathf.Floor(currentScroll * 16f) / 16f;

Hey bgolus, thanks for the idea!

I still get the weird distortion when quantizing the steps, so that makes me think there is a problem with the way the texture/sprite is read into/processed by the shader itself. Do you see anything in the shader code that might lead pixel art to become distorted like in the picture? Maybe some problem with lines 49/50 above?

Scratching my head as to why pixels could get distorted/moved as they do

Your shader is super simple and shouldn’t be a problem. That TRANSFORM_TEX macro is a super simple multiply & add that’s been used for nearly 15 years by Unity. My only guess is that maybe these lines aren’t working as expected:

currentScroll.y %= 1;
currentScroll.x %= 1;

They should work fine, but I’d double check the values in currentScroll to see if it’s actually wrapping as expected. If not, try changing those lines to:

currentScroll.y = currentScroll.y % 1f;
currentScroll.x = currentScroll.x % 1f;

The one other thing that I can think of is UV interpolation isn’t perfect. When using point sampled textures at a low resolution, if you have the texture offset such that it’s lined up with a screen pixel center rather than edge, you might be getting some noise there.

But the artifacts you’re seeing don’t quite match that. It looks much more like what you’d see from the modulo not working as expected. I have some faint memory of float % int not behaving the same as float % float, hence my recommendation above.

Thanks so much for the ideas, bgolus! I actually found out that the issue isn’t with the shader, it’s actually with my computer! I have a somewhat old rig, and while it’s run the rest of my game with no problems, doing anything relatively graphics intensive starts messing up the display!

1 Like

Yay, hardware corruption!

If it makes you feel better, I have a brand new computer and it’s already happening to me too!
(It’s a bad GPU. It’ll get RMA’d once the world isn’t dealing with a plague.)

1 Like

Haha, well that sucks, but at least it’ll get fixed! For all the crazy stuff our PC’s can do, they sure are finnicky sometimes

Thanks again for your help though, bgolus! I really appreciate it!