Dithering RevisitedOne of the things that's been a problem with this game is how the visual style works against the core mechanic. You need to be able to see and recognize faces, but 640x360 1-bit with dithering is pretty hard luck for showing facial details. This creates a situation where it's easy to question why someone would make such a low resolution black and white game in the first place. Questions are bad so this is something that's bothered me for a while.
To help with this, a few weeks ago I implemented a "zoom" feature when you look at a face. This feels as clunky as it sounds. Recently I decided the crappy zoom wasn't enough and that I needed to increase the game's resolution to 960x540. That's half 1080p and while it still feels like a low resolution, the faces are a lot easier to see. That pretty much settled it until Brent Werness (Koloth)
popped in here with a nice gift.
If you go back to my
previous post on dithering, you can see that my ideal algorithm would be an error diffuser like Floyd-Steinberg or Atkinson. Error diffusion techniques are all based on random memory access and so unsuited for shaders. What Werness built is a hybrid between noise thresholding and progressive error diffusion. And like lots of CPU->GPU translations, he's turned the algorithm inside out - instead of spreading one pixel's error to its neighbors, each pixel sucks up the error of its neighbors. When done correctly in phases this affects a diffusion of the errors.
ExamplesUsing the source image in
this great article on dithering:
Original companion cube image
Photoshop's 1-bit error diffusion dither at 75% (likely Atkinson)
The game's old pattern dither (blue noise)
Werness's method (2 phases, seeded with blue noise)
Comparing the last two, it's easy to see that Werness's method shows details much more clearly. It blows out the lights and darks like Photoshop does but that's a fair trade in my case. And it's more than just increasing contrast, nearby pixels compensate for error to increase accuracy at edges. Exactly what I need for detailed faces.
With a slightly more illustrative image. This is a sort of worst-case for error diffusion since there are zero details, but it helps to see the ranges:
Gradient
Photoshop's 1-bit error diffusion dither at 75%
The game's old pattern dither (blue noise)
The game's Werness at 75%
The Werness method has pretty poor reproduction at the low and high end of the gradient, so it helps to tweak the values a little more to stretch the available range:
The game's Werness at 90% with a preprocess level adjustment
Still blue noise is a better choice here, which highlights how dependent dithering is on the source material. In any case, Werness's method absolutely kills it for in-game facial details.
In-game ShotsDouble-sized pixels to match what you'd normally be playing at.
Some dude
Another dude
Pure wizardry. The important details are captured really well. Where important pixels had to be sacrificed for the pattern dithers, the error diffusion keeps them intact. Many thanks to Brent for sharing his work!