GMS 2 SNES Style "Pixelate" Transition


How would one go about making a transition in which the game becomes gradualy pixelated, as seen in the video below? (timestamped)
I'm thinking maybe you could incrementally decrease the application surface's resolution, but there's likely a more efficient way, right?

(sorry for the crappy formatting, I'm new to forums lol)
I realize this has already been solved, but for the sake of anyone searching this later (in case a link ever gets taken down), I'll explain how it works as opposed to a "just download this" answer. Here's a basic rundown of how the effect is done in SMW:
  • A counter starts at 0 and increases every 2 frames
  • The game skips checking every [counter] pixels. At 1, every other pixel is skipped; 2, every third pixel is drawn; 3, every fourth; etc.
  • The skipped pixels are filled in with the color from one of the corners (appears to be the bottom left, but I'm not sure. In practice, it doesn't really matter)
  • Note that the effect only applies to the background layer
This effect was much easier to do on the SNES, since there was built-in support for this kind of graphical feature. It's not much harder to do with a shader, though, and only requires very simple math if you use an input texture that is a squared power of two.
  • The resolution of the texture needs to be passed as a uniform since that is required for correct calculation of pixel positions. Necessary because fragment coordinates are normalized to 0.0-1.0
  • Use mod() function to floor skipped fragments to the color in the top-left pixel
  • Pass that updated fragment position to the gl_FragColor
//float PixelScale
//    How large each pixel in the final image should be.
//    Set as a float for math purposes, but is rounded down for proper scaling.
//float TextureResolution
//    The resolution of the input image, rounded up to the nearest power of 2.
//    Used in calculating pixel size and texture coordinate offset.
varying vec2 v_vTexcoord;
varying vec4 v_vColour;

uniform float PixelScale;
uniform float TextureResolution;

void main()
    vec2 pixelSize = vec2(1.0/TextureResolution);
    vec2 texcoordOffset = mod(ceil(v_vTexcoord.xy * TextureResolution), max(1.0, floor(PixelScale)));
    vec2 position = v_vTexcoord - (texcoordOffset * pixelSize);
    gl_FragColor = v_vColour * texture2D(gm_BaseTexture, position);
Last edited: