mdapt - merge dithering and pseudo transparency
0. Introduction
well it’s time for a solid start post. so let me start by explaining what it’s all about. in many old arcade or console games are dithering effects which are there to compensate platform weaknesses or generate specific effects like transparency by using an alternating pattern every frame. this works so well since back then the monitors (CRTs) had scanline bleeding and other certain features which merged the dithering through the display technology. but nowadays every pixel will displayed perfectly so dithering won’t look like it should be.
1. Algorithm
there are a few other shaders who are trying to simulate how a CRT displays an image. mdapt goes a different way and tries to detect specific patterns by analyizing the relation between the pixels. this way only those specific parts of the image are merged, which is a good base for further scaling e.g. with xBR.
mdapt can detect two basic patterns. the so called checkerboard pattern and vertical lines (see the screenshot section). it actually doesn’t matter of how many colors the pattern consists and mdapt doesn’t even use difference thresholds to determinie similarity. the algorithm just looks for a regular “up and down” between the pixels. there will always be errors since the dithering process itself is lossy and not invertible. but mdapt tries to balance it by checking if there are enough detections in one local area. if that’s the case it’s considered as dithering and will be merged. there are a few settings you can manipulate in the cg-files though, see section 3.
2. Download
Update 06/06/14: gdapt and mdapt support the new shader parameter feature which allows you to modify them using the Retroarch GUI.
- MDAPT: sigmoid function in pass2 uses smoothstep instead of tanh
- MDAPT: checkerboard merging is sharper by using only the orthogonal neighbors
- GDAPT: added a custom error prevention level. tradeoff between number of detections and false ones.
Update 02/20/14: You now can find some preconfigured .cgp-files I like to use on the shader repo along with official readme’s. mdapt updated to v2.7:
- reworked vertical line handling
- eliminated the need to check colors in pass1
- improved checkerboard ruleset in pass1
- fixed a bug in pass2 regarding calculation overflow with tangent hyperbolic
- removed some unneccessary parts in pass4
Update 02/05/14: Added a dumped down but more aggressive version called “gdapt”. It should replace the mdapt-2p version on the shader repo.
Update 01/21/14:
- better detection of border pixels in dithering areas
Update 12/11/13:
- added vertical-horizontal coherence in CB detection (reduces false detections)
Update 12/06/13:
- added a new vertical line rule in pass1 to fix some gaps
- replaced euclidean distance with a fast color metric
- strict option in pass0 automatically changes behavior in pass1
- replaced sigmoid function in pass2 with the more suitable tanh (approximation)
- removed a too aggressive checkerboard rule
Update 11/24/2013:
- added some new checkerboard rules to fix the gaps due to the new fuzzy logic
- the output pixel is now a weighted linear interpolation between the original pixel and the merged one
Update 11/21/2013:
- replaced binary logic with fuzzy one, fixes many false detections
Update 11/09/2013:
- fixed: holes in vertical line patterns
- fixed: checkerboard with two or three lines weren’t detected
- added a precalculation pass, no performance impact
- removed many false detections especially at text
- combined normal and strict version (you can switch the mode in pass0)
- moved pattern settings to pass4
Update 10/29/2013:
- fixed: 45° edges were interpreted as checkerboard dithering
Update 10/28/2013:
- eliminated all branches: performance improvement about 25%
3. Usage
mdapt consists of 5 passes (precalculation, pattern detection, isolation termination, pattern completion, blending). every pass works on scale factor 1 and should be considerably fast even for old systems. just use the cgp I wrote as a base and add additional shaders if you want.
to the settings: mdapt comes with two modes. the unrestricted one which is flexible in detecting patterns with any number of colors. and a strict one which only accepts patterns consisting of two different colors. the later one may reduce errors in graphically simple games (think gameboy, nes etc.) but don’t expect it to look good on games with pseudo transparency effects. you can switch between them via the strict def in pass0.
in pass4 you can deactivate the detection of checkerboard or vertical lines by commenting out the corresponding def line. pass2 is important for the error detection balance. there are two minimum values (int2 thresh) which determines how many detections must be in a local area to be considered as dithering. the standard values are working well for the most part.
4. Screenshots
my original post which started it all:
I played a few genesis games lately where I noticed that the dithering effect is often used to compensate the low number of possible colors in comparison to the snes. Yeah there are already many crt and ntsc filters available but if used with some sharp scaling filter like xBR or scaleX it looks like garbage of course.
So I thought about a pre-shader which keeps the resolution intact but blends the pixels only in those areas where dithering or pseudo transparency is present. This way you could use that image as input for a sharp high resolution shader. Too bad I have no experience with shader programming. I would need some time to read me into the subject but I thought people can help me out here with their knowledge.
Well just let me explain my firs naive idea. Consider a pixel C and his left and right neibors L and R. If the difference between L and R is under a given threshold they’re assumed equal and the output pixel C_new is a blending (with equal weights) of all three original pixels C,L,R. Otherwise we just keep the original pixel. That would merge dither with horizontal direction. questions is what to do if one would append the rules in the same way to vertical direction (with neigbor pixels U and D) and both directions are detected as dither. Merge all 5 pixels? Another problem would be fine lines or details like eyes where the neighbors are equal but it’s not supposed to be dither. Maybe check one addtional pixel in every direction to detect a pattern?
what do you think about it? feedback and help would be appreciated, thanks
ps: here are some example images of dithering in genesis games. http://retro-sanctuary.com/comparisons%20-%20differing.html