[HN Gopher] Surface-Stable Fractal Dithering
       ___________________________________________________________________
        
       Surface-Stable Fractal Dithering
        
       Author : bj-rn
       Score  : 171 points
       Date   : 2025-01-23 22:50 UTC (1 days ago)
        
 (HTM) web link (github.com)
 (TXT) w3m dump (github.com)
        
       | pvg wrote:
       | Related discussion a couple of months ago
       | https://news.ycombinator.com/item?id=42084080
       | 
       | Lots of related links including one to a tweetier version of this
       | work.
        
       | crazygringo wrote:
       | Link to part of video that shows it in action:
       | 
       | https://youtu.be/HPqGaIMVuLs?si=P11cFnSLcv57Wj3K&t=1236
        
       | simlevesque wrote:
       | That looks crazy good ! I'm speechless.
        
       | con____rad wrote:
       | Unordered dithering gives better form shading as there is no
       | structure overlaying the shape,I would love to see "Recursive
       | Wang Tiles for Real-Time Blue Noise
       | ps://www.youtube.com/watch?v=ykACzjtR6rc" combined with that
       | technique
        
         | egypturnash wrote:
         | Damn, the demo around 3:30 is lovely.
        
         | tom_ wrote:
         | https://www.youtube.com/watch?v=ykACzjtR6rc
        
         | aeontech wrote:
         | Wow, that's a very cool paper and demo!
        
         | shiandow wrote:
         | That does seem lovely, I might experiment with that at some
         | point.
         | 
         | You don't need to make things all that difficult just to get
         | some random looking blue noise though. You can get some pretty
         | reasonable randomized ordered dithering by just rotating the
         | 2x2, 4x4, 8x8 blocks of the bayer matrix randomly. Though this
         | makes more sense if you view it as adding octaves of the 2x2
         | bayer matrix together randomly.
        
       | londons_explore wrote:
       | I am pondering a different approach:
       | 
       | * Use error diffusion dithering in screen space
       | 
       | * Generate motion vectors for every pixel from the previous frame
       | 
       | Now, to make the next frame:
       | 
       | * Take the previously displayed (dithered) image and apply the
       | motion vectors.
       | 
       | * Now use that as the threshold map to do error diffusion
       | dithering on the next frame.
       | 
       | The threshold doesn't really matter for error diffusion dithering
       | - since any error will be propagated to the next pixel. However,
       | if you use a previous frame as a threshold map, it will encourage
       | pixels not to 'flicker' every frame.
        
       | Ono-Sendai wrote:
       | What is the point of this?
        
         | kevingadd wrote:
         | If dithering isn't stable in motion it creates distracting
         | 'shimmering' and other effects as the camera or objects move,
         | which can be unpleasant to look at.
         | 
         | Unstable dithering is also potentially harder to compress in
         | videos.
        
           | Ono-Sendai wrote:
           | Yeah but if your dithering is noticable in the first place
           | you're doing it wrong.
        
             | Rohansi wrote:
             | Unless you want it as an artistic style.
        
           | cma wrote:
           | If this is surface stable it should also work for stereo/VR
           | without much stereo disparity, where normal dithering would
           | have a mismatch. And PCVR is often streamed over video codecs
           | now so what you said aboutvideo compression should help there
           | too.
        
             | AndrewStephens wrote:
             | I was also wondering how well it would look in stereo. My
             | guess is it would still look strange (the "depth map" would
             | also appear dithered) but the effect would be interesting
             | to experiment with.
        
         | Retr0id wrote:
         | As far as I can tell, it's purely artistic.
        
         | abetusk wrote:
         | To create a dithering effect for 3D scenes.
         | 
         | Doing a straight 2D dither on each frame will result in noisy
         | artifacts and won't be "stable".
         | 
         | Doing an "ordered" dithering produces a "porch screen" artifact
         | effect, where there's a stable pattern in screen space that can
         | be seen.
         | 
         | Trying to naively map dithering patterns as textures on 3D
         | objects again results in unstable patterns as the dithering is
         | dependent on the distance of the screen to the object and
         | produces noise.
         | 
         | This is a proposed solution that maps a dithering pattern as a
         | texture that doesn't have the "porch screen" effect and is
         | stable.
         | 
         | The video linked [0] to in the repo talks about experiments and
         | shortcomings from the above I just listed. This work is in
         | response to some challenges the developer of the "Return of the
         | Obra Dinn" game experienced when trying to create a dithering
         | effect in game [1] [2].
         | 
         | [0] https://www.youtube.com/watch?v=HPqGaIMVuLs&t=201s
         | 
         | [1] https://news.ycombinator.com/item?id=42084080
         | 
         | [2]
         | https://forums.tigsource.com/index.php?topic=40832.msg136374...
        
           | Aardwolf wrote:
           | I do wonder if it would be possible now to not map this to
           | textures, but to pixels in screen space.
           | 
           | Because it looks like high-res 3D mapped textures with
           | circular dots on them now, rather than low-res screen pixel
           | dithering.
           | 
           | I remember seeing the video about the difficulties of
           | dithering stability in "Return of the Obra Dinn".
           | 
           | The solution here has it rendered on textures, but the dots
           | still all have similar size in screen space, so mapping this
           | to actual screen space might still be possible (as in, no
           | circular dots on textures, but low-res pixels on screen being
           | turned on/off directly)?
        
       | adamrezich wrote:
       | Technically, this is very cool. Aesthetically, though, the end
       | result doesn't look very good, at least in my opinion. The Obra
       | Dinn visual style is attempting to find a compromise between
       | having the game look like its visuals are prerendered 3D scenes,
       | dithered for an old 1-bit display. As the video explains, a lot
       | of work had to go into striking a balance between the intended
       | aesthetic, and playability, because it turns out that the
       | dithered aesthetic is difficult to work with. This, though, just
       | kind of ends up looking like a pseudo-halftone style applied to
       | high-res polygonal models. Maybe it would look better at 320x240
       | or something?
        
       | JKCalhoun wrote:
       | I got the itch to try and create an Atkinson dithering paint
       | program.
       | 
       | What do I mean by that? Imagine a grayscale paint program (like,
       | say, Procreate, just all grays) but all the pixels go through an
       | Atkinson dither before hitting the screen.
       | 
       | To the artist you're kind of darkening or lightening the dither,
       | so to speak, in areas of the canvas with your brush/eraser. (Kind
       | of crowding or thinning the resulting B&W pixels).
       | 
       | An hour spent with Claude to make this happen in HTML5 caused me
       | to set the experiment aside. It was okay, but only did the dither
       | after the mouse was released. I wasn't driven enough to try to
       | get it to dither in real-time (as the brush is being stroked).
       | 
       | The mouse is a terrible painting tool too -- with a touch
       | interface on an iPad (again, like Procreate) it might be worth
       | pursuing further. It would need to be very performant as I say --
       | so that you could see the dither as the brush is moving. (This
       | might require a special bitmap and code where you store away the
       | diffusion error so that you can update only a portion of the
       | screen -- where the brush has move - rather than having to re-
       | dither the entire document 60 fps.)
        
         | itishappy wrote:
         | Error diffusion is not ideal for real time work, and it cannot
         | be parallelized. Consider storing a precomputed blue noise
         | texture.
        
           | AndrewStephens wrote:
           | This is correct. Atkinson dithering looks cool (at least to
           | my eyes) but is not the best choice for real time work. In
           | particular, it cannot be implemented in a shader, although
           | you can approximate it. But computers are fast enough that a
           | CPU-bound algorithm can still work at interactive speeds. Not
           | sure how well it would work in an editor though - in theory
           | changing a single pixel at the top left of the image could
           | cause a chain reaction that could force the whole image to be
           | re-dithered.
           | 
           | I did an implementation of Atkinson dithering for a web
           | component in case anyone is feeling the itch to dither like
           | it is 1985.
           | 
           | Demo: https://sheep.horse/2023/1/improved_web_component_for_p
           | ixel-...
           | 
           | Source: https://github.com/andrewstephens75/as-dithered-image
        
             | crazygringo wrote:
             | > _in theory changing a single pixel at the top left of the
             | image could cause a chain reaction that could force the
             | whole image to be re-dithered._
             | 
             | For a paint program, I think it would be acceptable if
             | painting with the brush never changed existing pixels, only
             | pixels newly painted with the brush, and you'd apply
             | dithering only to newly added pixels in the brush stroke as
             | the mouse dragged. The fact that you might be able to kinda
             | see the discontinuities at the edge of the brush feels like
             | it would be a feature, not a bug -- that you can see the
             | brush strokes.
             | 
             | The really interesting effect would come when you
             | implemented a dodge or burn tool...
        
               | AndrewStephens wrote:
               | The trouble is that dithering works by smearing the error
               | over an area of pixels in a way that your brain unsmears
               | into something close to the original image. If you start
               | manipulating some pixels but not nearby areas then you
               | will get very visible artifacts.
               | 
               | Maybe that is OK if you are drawing straight lines and
               | boxes but any kind of detail is going to be destroyed.
        
               | crazygringo wrote:
               | Well sure, that's why you work in grayscale and only
               | dither in the end if you want to maximize quality and
               | detail.
               | 
               | I'm talking about from an artistic perspective. The way
               | you see the brush strokes in certain styles of painting,
               | it would add character to see where two dithered areas of
               | the same lightness had a slightly visible discontinuity.
               | I think it could be a very cool artistic effect.
        
             | JKCalhoun wrote:
             | > in theory changing a single pixel at the top left of the
             | image could cause a chain reaction that could force the
             | whole image to be re-dithered.
             | 
             | My thought is to store the error for each pixel in a
             | separate channel. When a portion of the bitmap is "dirtied"
             | you could start in the top left of the dirty rectangle, re-
             | Atkinson until, once outside the dirty rect, you compute
             | the same error as the existing error for a given pixel. At
             | that point there would follow the same dither pattern and
             | you can stop.
             | 
             | As you say, it's conceivable you would have to go to the
             | very end of the document. If the error is an integer though
             | I feel like you would hit a point where you can stop early.
             | Maybe I am misunderstanding how error diffusion works or
             | grossly misjudging how wild mismatched the before/after
             | errors would be.
        
               | itishappy wrote:
               | Neat idea, be curious to see it implemented! You can
               | probably get away with just stopping at the bounds of the
               | dirty area. Sure, the error would accumulate, but they'd
               | be localized to a single pixel. I doubt it would be
               | visible.
               | 
               | One issue I suspect you'll encounter is that redrawing a
               | restricted area during movement will cause that area to
               | flicker weirdly while the rest of the image stays
               | relatively stable.
        
         | cobalamin wrote:
         | I distinctly remember that "Paintbrush" in Windows 3.1 had
         | something very similar to this. Check it out in the Win3.1
         | emulator: https://archive.org/details/win3_stock -- open
         | Paintbrush, go to Options -> Image Attributes and set "Colors"
         | to "Black and White".
         | 
         | However, the dithering there is not fixed to the background but
         | depends on your brushstroke / mouse position.
        
       | jnurmine wrote:
       | As I watched the video I got an idea.
       | 
       | Could this somehow be repurposed such that the points would be
       | "check points" for a generative texture algorithm, with zoom
       | level somehow taken into account (distance of dots maybe)?
       | 
       | Then one could, in a computer game, for example look at a brick
       | wall. At first, as one is further back, the surface from tiles
       | look somewhat matte smooth. But when one gets closer, the
       | features become more and more coarse with more and more detail,
       | eventually even some tiny tiny holes in the surface are visible,
       | and so on.
       | 
       | Another example: sand, it looks smooth from afar but as one zooms
       | in, actual grains of sand become visible.
        
         | djmips wrote:
         | That's level of detail (LOD) and there are various ways of
         | implementing it. This dither technique incorporates LOD but I'm
         | not sure how it would be useful for the type of LOD you are
         | suggesting unless perhaps you think it might be applicable as a
         | procedural technique in which case some of the observations
         | might be an inspiration.
        
       ___________________________________________________________________
       (page generated 2025-01-24 23:01 UTC)