The Flashback '94 Shader Pack for Unity is a collection of shaders and scripts that emulate the graphical limitations of game consoles from the 1990s.
To improve performance when rendering triangles, older graphics hardware didn't correct textures for perspective. Instead, it just distorted them in two dimensions to fit the onscreen shape of each triangle. This saved a lot of number-crunching, but it caused textures to warp when viewed at an angle, producing a telltale 'zigzag' effect on floors and walls.
Although most early graphics processors used fixed-point or floating-point math (numbers with decimal places), some consoles were only able to pass integer values (whole numbers) from one component to another. This meant that each vertex in a 3D model would 'snap' to its nearest integer position instead of moving smoothly, resulting in a weird gelatinous effect as the vertices 'snapped' independently of each other.
Your fancy-pants gaming PC can render 18 gorillion colors in 4K resolution at 144 frames per second, but not even the most beastly of 90s consoles could manage such epoch-defining feats of computation. Most consoles rendered 3D graphics at a very small resolution like 320x240 and upscaled it to fit a TV screen. On top of that, they had to use fewer bits to store color information, which limited color precision and caused those 'banding' artifacts that opposing tribes of brand devotees used to get into gigantic flame wars over.
Haha, isn't it great how we don't have flame wars anymore?
When you add the Flashback '94 Shader Pack to your Unity project, you'll see some new folders in your Assets window:
If you want to apply one of these shaders to an object, first create a material, then go to its shader dropdown and select a shader from Flashback 94/Object Shader.
The possible shaders are:
All Flashback '94 object shaders use affine texture mapping, and they all have a Vertex Snapping attribute that determines how aggressively the individual vertices 'snap' when moving. The other shader attributes are named according to what they do, and behave in much the same way as Unity's built-in legacy shaders.
New in version 2.0 are two shaders for use with Unity's projector system. Because the vertex-lit rendering pipeline doesn't support real-time shadows, using a projector to create a blob shadow is the only way to ground characters and dynamic objects in the environment. Simply create a material using one of the Flashback 94/Projector shaders, and add it to the Material attribute of a Projector object.
The two shaders are:
For both shaders, the projected texture should have its Texture Type attribute set to 'Advanced' and its Wrap Mode set to 'Clamp'. The mip maps that Unity automatically generates can cause visual artifacts with projectors, so either enable Border Mip Maps or just disable Generate Mip Maps entirely.
Both shaders support falloff textures, so you can use a horizontal gradient to vary the strength of the projector by distance. Intensity is based on grayscale value (white is full strength, black is off), so the color of the gradient doesn't matter. They also have a Vertex Snapping attribute, which must be the same as the target surface to prevent clipping artifacts.
Projectors in Unity can be tricky to get right, so if you want to see a correct implementation, just take a look at the Example_BlobShadow material in the Example Content/Materials directory.
To add the image effect to your scene, simply select your main camera, click Add Component in the inspector, then choose Flashback 94 and Post Process.
You can use the Bits Per Color Channel slider to adjust the color depth of the camera, and the Downsampling Type dropdown to choose how you want to scale the framebuffer:
The Enable Antialiasing checkbox lets you decide whether the framebuffer should be antialiased during resizing. Switch it off for that authentic 'pixels so big you could park a cyberpunk police gunship on them' look.
The Example Content folder contains the source for the Flashback '94 WebGL demo. Feel free to play with the example materials to see how they work.
Surprisingly - even to me, and I made the friggin' thing - the shortcomings of this shader pack are similar to those of the original hardware, and require similar workarounds.
Firstly and most importantly, these shaders all began their lives as open-source Cg implementations of Unity's built-in 'VertexLit' shader. The vertex lighting model was invented by Celtic druids in 2200 BC and therefore comes with a few caveats:
Vertex-lit shaders will not work on modern consoles, but they will work just fine on iOS/Android and any PC/Mac/Linux computer recent enough not to use punch cards.
These shaders cannot cast or receive real-time shadows, as this would require per-pixel lighting. You can, however, get around this by using the included projector shaders to create blob shadows. Or, if you're a wizard, you can add your own Quake 2-style geometric projection shadows and leave a passive-aggressive review implying that I'm lazy/stupid/a communist for not including them myself.
They cannot be lit by more than 8 lights at a time. Your scene can have more lights in it, of course, but an object with one of these shaders applied will only receive lighting from the 8 brightest lights around it. Hey, if 8 lights were enough for Hideo Kojima, they'll be enough for you.
Unity does not provide light position data when rendering lightmapped objects, so if you use lightmaps with these shaders, you won't get any specular highlights.
Another thing to keep in mind is the quirky way that affine texture mapping works. If you're far enough away from an object and looking right at it, all is well. But if the camera sits directly above a single large polygon, the texture will turn into a Kubrickian slit-scan acid trip.
The way to get around this is the same as it was in the 90s: always make sure any large flat surfaces are subdivided into a grid. The sampling gets less accurate the further it gets from a vertex, so adding more vertices will ease the pain. Yes, you're technically adding more polygons where you don't need them, but if that turns out to be a performance bottleneck then you're probably developing for 90s hardware anyway.
Other workarounds include designing your textures so that any straight lines lie on polygon edges, where the distortion is least severe. You may even want to create separate geometry for critical details, which is how things like road lines were done in many racing games.
Finally, always make sure that any textures you're using with these shaders have their Filter Mode property set to 'Point'. This will ensure they have that crisp, pixelated look that graphics researchers once spent years of their lives trying to eliminate. Guess the joke's on them, huh?
Thanks for taking a look at the Flashback '94 Shader Pack for Unity! I hope you like it, and if you like it enough to maybe give me actual for-realsies money for it, I would appreciate that immensely.
Other people who made this possible:
Now what are you still doing here? Go make your elders proud!