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

Trouble with simple shader

Discussion in 'Shaders' started by Narkata55, Apr 2, 2020.

  1. Narkata55

    Narkata55

    Joined:
    Feb 25, 2017
    Posts:
    63
    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

    Code (CSharp):
    1. Shader "Unlit/Unlit_Mine"
    2. {
    3.     Properties
    4.     {
    5.         [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
    6.     }
    7.     SubShader
    8.     {
    9.         Tags
    10.         {
    11.             "Queue"="Transparent"
    12.             "IgnoreProjector"="True"
    13.             "RenderType"="Transparent"
    14.             "PreviewType"="Plane"
    15.             "CanUseSpriteAtlas"="True"
    16.         }
    17.         Cull Off
    18.         Lighting Off
    19.         ZWrite Off
    20.         Fog {Mode Off}
    21.         Blend SrcAlpha OneMinusSrcAlpha
    22.  
    23.         Pass
    24.         {
    25.             CGPROGRAM
    26.             #pragma vertex vert
    27.             #pragma fragment frag
    28.             #pragma multi_compile _ PIXELSNAP_ON
    29.             #include "UnityCG.cginc"
    30.  
    31.             struct appdata
    32.             {
    33.                 float4 vertex : POSITION;
    34.                 float2 uv : TEXCOORD0;
    35.             };
    36.  
    37.             struct v2f
    38.             {
    39.                 float2 uv : TEXCOORD0;
    40.                 float4 vertex : SV_POSITION;
    41.             };
    42.  
    43.             sampler2D _MainTex;
    44.             float4 _MainTex_ST;
    45.  
    46.             v2f vert (appdata v)
    47.             {
    48.                 v2f o;
    49.                 o.vertex = UnityObjectToClipPos(v.vertex);
    50.                 o.uv = TRANSFORM_TEX(v.uv, _MainTex);
    51.                 #ifdef PIXELSNAP_ON
    52.                 o.vertex = UnityPixelSnap (o.vertex);
    53.                 #endif
    54.                 return o;
    55.             }
    56.  
    57.             fixed4 frag (v2f i) : SV_Target
    58.             {
    59.                 // sample the texture
    60.                 fixed4 col = tex2D(_MainTex, i.uv);
    61.                 return col;
    62.             }
    63.             ENDCG
    64.         }
    65.     }
    66. }
     

    Attached Files:

  2. Narkata55

    Narkata55

    Joined:
    Feb 25, 2017
    Posts:
    63
  3. Olmi

    Olmi

    Joined:
    Nov 29, 2012
    Posts:
    1,553
    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...
     
  4. Narkata55

    Narkata55

    Joined:
    Feb 25, 2017
    Posts:
    63
    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:

    Code (CSharp):
    1. currentScroll.x += (scrollSpeed.x * dirSwitcherAdjuster.x * Time.deltaTime);
    2. currentScroll.y += (scrollSpeed.y * dirSwitcherAdjuster.y * Time.deltaTime);
    3. currentScroll.y %= 1;
    4. currentScroll.x %= 1;
    5. 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...
     
  5. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    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;
     
  6. Narkata55

    Narkata55

    Joined:
    Feb 25, 2017
    Posts:
    63
    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
     
  7. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    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:
    Code (csharp):
    1. currentScroll.y %= 1;
    2. 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:
    Code (csharp):
    1. currentScroll.y = currentScroll.y % 1f;
    2. currentScroll.x = currentScroll.x % 1f;
     
  8. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    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.
    https://forum.unity.com/threads/noisy-vertex-color-glitch.631534/#post-4230877

    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.
     
  9. Narkata55

    Narkata55

    Joined:
    Feb 25, 2017
    Posts:
    63
    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!
     
    bgolus likes this.
  10. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    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.)
     
    Narkata55 likes this.
  11. Narkata55

    Narkata55

    Joined:
    Feb 25, 2017
    Posts:
    63
    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!