Search Unity

Is it still possible to scroll sprite textures with material.mainTextureOffset?

Discussion in '2D' started by Sendatsu_Yoshimitsu, Jan 19, 2017.

  1. Sendatsu_Yoshimitsu

    Sendatsu_Yoshimitsu

    Joined:
    May 19, 2014
    Posts:
    666
    I found tons of old tutorials that achieved a scrolling/parallaxy background effect by making a single sprite background to cover the screen, then every frame doing something like this:

    Code (csharp):
    1.  
    2. Vector2 offset = new Vector2(Time.time * speed, 0);
    3. GetComponent<Renderer>().material.mainTextureOffset = offset;
    4.  
    Whenever I try to do the same, I get an error on my sprite renderer, "Material texture property _MainTex has offset/scale set. It is incompatible with SpriteRenderer". The only disparity I can find between my implementation and everyone else's is that older tutorials change their scrolling sprite's Texture Type from Sprite to Texture. I don't have a Texture option on my dropdown, and as far as I can tell that particular option was revised out of Unity quite a while ago.

    So is there an alternative implementation I'm missing? Messing with the offsets like this seems so useful, I can't imagine it was made completely impossible by the change.
     
  2. Hyblademin

    Hyblademin

    Joined:
    Oct 14, 2013
    Posts:
    723
    Try using the Default texture type.

    I haven't used offset with SpriteRenderer, since sprite slicing being added in Unity 4 took away the only reason I ever had to apply an offset to a sprite texture. It's too bad that that doesn't work...
     
  3. Sendatsu_Yoshimitsu

    Sendatsu_Yoshimitsu

    Joined:
    May 19, 2014
    Posts:
    666
    Hmm, it looks like Default is intended to be used as a shader/material on 3d meshes- that's the only context in which I can get it to apply, it looks like Default textures can't be set as sprites in a 2d sprite renderer.
     
  4. Hyblademin

    Hyblademin

    Joined:
    Oct 14, 2013
    Posts:
    723
    @Sendatsu_Yoshimitsu

    Sorry, I meant to not use a sprite renderer at all. As the fault describes, setting offset at the texture is apparently not compatible with SpriteRenderer. You can still use a textured quad (for instance) if you still want to use offset, perhaps as part of a UI canvas for scaling purposes.
     
    theANMATOR2b likes this.
  5. Sendatsu_Yoshimitsu

    Sendatsu_Yoshimitsu

    Joined:
    May 19, 2014
    Posts:
    666
    Ooh I see what you mean, that's a really good idea; thanks for the suggestion! :)
     
    Hyblademin likes this.
  6. Pawl

    Pawl

    Joined:
    Jun 23, 2013
    Posts:
    109
    Digging up this thread as it was a top search result when I was attempting to scroll a SpiteRenderer's material without success.

    I believe the best approach is to copy the default Sprite shader and modify it with your own scrolling texcoord offsets, which is what I've done below. I wish there was a proper way to "extend" or inherit from shaders, but the only way I know how to do this is copy the code and modify what you need. Fortunately, this is relatively straightforward.

    Code (CSharp):
    1. // A copy of builtin_shaders-2019.1.7f1/DefaultResourcesExtra/Sprites-Default
    2. Shader "Custom/Sprite Scrolling" {
    3.     Properties {
    4.         [PerRendererData] _MainTex("Sprite Texture", 2D) = "white" {}
    5.         _Color("Tint", Color) = (1,1,1,1)
    6.         _ScrollSpeed("Scroll Speed", Vector) = (0,0,0,0)
    7.         [MaterialToggle] PixelSnap("Pixel snap", Float) = 0
    8.         [HideInInspector] _RendererColor("RendererColor", Color) = (1,1,1,1)
    9.         [HideInInspector] _Flip("Flip", Vector) = (1,1,1,1)
    10.         [PerRendererData] _AlphaTex("External Alpha", 2D) = "white" {}
    11.         [PerRendererData] _EnableExternalAlpha("Enable External Alpha", Float) = 0
    12.     }
    13.  
    14.     SubShader {
    15.         Tags {
    16.             "Queue" = "Transparent"
    17.             "IgnoreProjector" = "True"
    18.             "RenderType" = "Transparent"
    19.             "PreviewType" = "Plane"
    20.             "CanUseSpriteAtlas" = "True"
    21.         }
    22.  
    23.         Cull Off
    24.         Lighting Off
    25.         ZWrite Off
    26.         Blend One OneMinusSrcAlpha
    27.  
    28.         Pass {
    29.             CGPROGRAM
    30.             #pragma vertex SpriteVertScrolling
    31.             #pragma fragment SpriteFrag
    32.             #pragma target 2.0
    33.             #pragma multi_compile_instancing
    34.             #pragma multi_compile_local _ PIXELSNAP_ON
    35.             #pragma multi_compile _ ETC1_EXTERNAL_ALPHA
    36.             #include "UnitySprites.cginc"
    37.  
    38.             float2 _ScrollSpeed;
    39.  
    40.             // A copy of SpriteVert() from builtin_shaders-2019.1.7f1/CGIncludes/UnitySprites.cginc
    41.             v2f SpriteVertScrolling(appdata_t IN) {
    42.                 v2f OUT;
    43.  
    44.                 UNITY_SETUP_INSTANCE_ID(IN);
    45.                 UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
    46.  
    47.                 OUT.vertex = UnityFlipSprite(IN.vertex, _Flip);
    48.                 OUT.vertex = UnityObjectToClipPos(OUT.vertex);
    49.                 OUT.texcoord = IN.texcoord;
    50.                 OUT.texcoord.x += _Time * _ScrollSpeed.x;
    51.                 OUT.texcoord.y += _Time * _ScrollSpeed.y;
    52.                 OUT.color = IN.color * _Color * _RendererColor;
    53.  
    54.                 #ifdef PIXELSNAP_ON
    55.                 OUT.vertex = UnityPixelSnap(OUT.vertex);
    56.                 #endif
    57.  
    58.                 return OUT;
    59.             }
    60.  
    61.             ENDCG
    62.         }
    63.     }
    64. }
    65.  

    Then you can update the shader param as usual, eg:
    Code (CSharp):
    1. [RequireComponent(typeof(SpriteRenderer))]
    2. public class ScrollingTexture : MonoBehaviour {
    3.     public Vector2 ScrollSpeed;
    4.  
    5.     private void OnEnable() {
    6.         GetComponent<SpriteRenderer>().material.SetVector("_ScrollSpeed", ScrollSpeed);
    7.     }
    8. }
    9.  

    Example Output
     
    Last edited: Jul 14, 2019
  7. louis_earl

    louis_earl

    Joined:
    Jun 20, 2018
    Posts:
    1
    Does your solution also happen to tile/repeat @Pawl ? Wondering if there's a way to get that working
     
  8. Pawl

    Pawl

    Joined:
    Jun 23, 2013
    Posts:
    109
    Not sure I fully understand your question, but I believe so. I was able to dynamically adjust the size of the pattern. The texture I used was of course four way symmetrical.
     
  9. opertoonist

    opertoonist

    Joined:
    Jul 11, 2012
    Posts:
    124
    This worked great for me, except the alpha remained in place while the texture scrolled—any way to get the alpha scrolling as well?
     
  10. GigaRoid

    GigaRoid

    Joined:
    Oct 7, 2013
    Posts:
    35
    Thank you. This shader helped me closer to fixing my problem with Sprite Shape.