I am looking to replicate the style of screen loading as seen on the ZX Spectrum in Unity. Not the stripes of colors in the background. Just the title image loading.

Specifically the way it looks in this video:

Animation of screen loading

Underwurlde Loading Screen - ZX Spectrum

I like the way it seems to load the image, top-down, from left to right, in chunks. But I am not sure how to accomplish this or what I should even search for to find the answer.

Ideally I would like to update the screen this way on each frame of the game, with the next frame "drawing" the screen overtop of the previous frame. It would also be great to be able to control the speed and amount of screen it loads per frame.

Does anyone have any tips on the best way to accomplish this?


1 Answer 1


We can write a shader that displays blocks of one texture over another, something like this:

Shader "Unlit/ZXLoad"
        _MainTex ("Loading Texture", 2D) = "white" {}
        _UnderTex ("Underlying Texture", 2D) = "black" {}
        _RowCount ("Rows", int) = 16
        _ColCount ("Columns", int) = 32
        _Progress ("Load Progress", Range(0, 1)) = 0.5
        Tags { "RenderType"="Opaque" }
        LOD 100

            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

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

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

            sampler2D _MainTex;
            sampler2D _UnderTex;
            float4 _MainTex_ST;
            int _RowCount;
            int _ColCount;
            half _Progress;

            v2f vert (appdata v)
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);                
                return o;

            fixed4 frag (v2f i) : SV_Target
                // Number each block in the grid 
                // from 0 to _RowCount*_ColCount - 1,
                // and find which block this pixel is in.
                float block = floor(i.uv.x * _ColCount) 
                            + floor((1.0f - i.uv.y) * _RowCount) * _ColCount;

                // If it's an "Early" block, already loaded by the
                // time we reach _Progress, sample the main texture.
                if (block < _Progress * _RowCount * _ColCount) {
                    return tex2D( _MainTex, i.uv);

                // Otherwise, sample the underlying texture.
                return tex2D( _UnderTex, i.uv);

You can use this to make a material that accepts two textures: one to show underneath and one on top, with a "Load Progress" slider you can dial back and forth to show more or less of the texture being "loaded". You can use this material on a quad or UI image/raw image component to display your pseudo-loading output.

Animation of adjusting "Load Progress" slider in Material Inspector

You can animate this any way you want in your C# script, using Material.SetFloat("_Progress", loadAmount) (or the integer version, for better performance) to animate the progress counter forward.

You can use a camera that writes its output to a RenderTexture to capture the images you want to display for each "frame", and use those textures as the loading / underlying textures of this material, swapping between them (and swapping their order in the material) on alternate renders.

  • \$\begingroup\$ Wow so simply but effective! I will try this out and see how it works for me. The only other way I was considering was to find a camera transition asset and do it with the camera. However, I have no idea which one would be more performance intensive. I am imagining that this type of loading will take 3-4 seconds and then remain on screen until there is user input. So I could see this as bogging down things. Thoughts? \$\endgroup\$ Sep 21 at 12:26
  • \$\begingroup\$ This shader is dirt cheap. If you've captured two static frames to use as textures and show the load transition in between, then for the duration of the transition you don't need any cameras continually rendering your game scene, just this single textured quad/image. That makes it one of the lowest-cost rendering effects you're ever likely to see. \$\endgroup\$
    – DMGregory
    Sep 21 at 12:31

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .