Despite the limitations of the "console" the result is quite impressive: https://miro.medium.com/max/384/1*xgIPZgLgcJGBnRhFeJIJLQ.gif
Given that the original article is blurring glyphs, one thing that might be worth exploring is decomposing the glyph into primitive shapes. For example "b" can be a rect for the stem, an ellipsoid for the main bowl, and another ellipsoid (with negative sign) for the inner countour of the bowl. It doesn't have to be perfect because you're only rendering the blurred shapes. And no doubt you could have some kind of automated process that refines the decomposition when it can use more primitive shapes.
Though our techniques are different, it's interesting (and not terribly surprising) that they both use some of the same techniques under the hood, specifically distance fields, and that we cite some of the same people.
I should mention that of course shadows and blurs are not the same thing, but sometimes you can use one for the other in a pinch :)
[1] https://raphlinus.github.io/graphics/2020/04/21/blurred-roun...
Line of Sight is calculated on a 2-d topographical map, where each 2d point is a height-map. The question is: does location "X" have a line-of-sight to location "Y" ?? You solve this question by marching rays from X towards Y, and seeing if any intermediate 2d point has a height that would block the sight.
I bring this up because line-of-sight has been SIMD-optimized and is highly efficient to calculate now. Line-of-sight is similar enough that the large body of research behind that problem can probably serve as inspiration to algorithms in this 'ray marching shadows' algorithm.
Its quite possible that your calculation here is "just" a 2-value line of sight: where 0 means "sight is not blocked" and 1 means "sight is blocked".
------
Ray Marching itself seems innately "sequential", because you need to calculate the closest "solid object" to know how far to march.
In contrast, the naive "try every pixel" approach is easily parallelized if you understand prefix-sum style computations (see: https://en.wikipedia.org/wiki/Prefix_sum). If you could easily group pixels into 1-bit objects (see PEXT or PDEP: https://www.felixcloutier.com/x86/pdep), I'm sure that a SIMD-parallel version would be outstandingly fast to compute for "small" 256-pixel (aka: AVX2) bit-vectors.
-------
EDIT: Now that I think of it: the computation of the distance field is likely sequential. But the use of the distance-field is probably read-only / parallel. A SIMD-line of sight style algorithm using the distance field could be "scheduled" using a sequential algorithm, but then computed with SIMD techniques.
For example, you fill the background with 100% white, and then draw a 10px stroke at 90% gray, 9px at 80%, 8px at 70%, etc. This is, most importantly, an extremely fast way to generate a distance field for text from JavaScript in the browser.
I mention this because the mystery of the getDistance() function is often one of the tricky parts of demos like these.
> I mention this because the mystery of the getDistance() function is often one of the tricky parts of demos like these.
I agree! In the demos I use a library I wrote to generate 2D distance fields: https://github.com/ryankaplan/gpu-distance-field
It's also pretty fast :)
Edit: oh wait, you measure the pixel color :) nice
You might require dozens of samples to get a similar result using a multisampling technique like you describe.
This looks great when combined with area light sources, like you suggest, but in my experience it's too slow for interactive demos.
I'd love to be proven wrong on this :)
For anyone getting interested in distance functions and ray marching, whether it is in 2D or 3D, Inigo Quilez [1] is the authority in this field.
I find that his articles are best for folks who already know a thing or two about computer graphics. Here's a post that I think is pretty good for beginners: http://jamie-wong.com/2016/07/15/ray-marching-signed-distanc...
As Raph is mentioning in a side thread, there are lots of assumptions! (Some of them similar to the randomized assumptions behind alpha, generally).
[1] http://graphics.stanford.edu/~boulos/papers/prefilter_rt08.p...
On my Mediatek device, each demo worked great... Until I scrolled up the screen and then suddenly I saw a "Chrome error icon" in the demo... I refreshed the page and the demos were replaced with white boxes. I killed and restarted chrome and now the demos appeared to work till you interacted with them and they became black boxes.
Had to restart the phone to regain full functionality.
get graphics.ts:822
value graphics.ts:950
value graphics.ts:1234
value graphics.ts:493
value renderer.ts:355
value renderer.ts:471
onFrame app.ts:631
t app.ts:501
QCba index.ts:4
QCba index.ts:3
f src.515687e2.js:1
parcelRequire src.515687e2.js:1
<anonymous> src.515687e2.js:1
graphics.ts:822:14firefox, ubuntu 20.04
Uncaught Exception { name: "NS_ERROR_FAILURE", message: "", result: 2147500037, filename: "https://ray-marching-talk.netlify.app/src.c9ac1cf4.js", lineNumber: 20, columnNumber: 0, data: null, stack: "k@https://ray-marching-talk.netlify.app/src.c9ac1cf4.js:20:425... } canvas-scene.ts:1
Uncaught Exception { name: "NS_ERROR_FAILURE", message: "", result: 2147500037, filename: "https://ray-marching-talk.netlify.app/src.c9ac1cf4.js", lineNumber: 20, columnNumber: 0, data: null, stack: "k@https://ray-marching-talk.netlify.app/src.c9ac1cf4.js:20:425... } canvas-scene.ts:1
Uncaught Exception { name: "NS_ERROR_FAILURE", message: "", result: 2147500037, filename: "https://ray-marching-talk.netlify.app/src.c9ac1cf4.js", lineNumber: 20, columnNumber: 0, data: null, stack: "k@https://ray-marching-talk.netlify.app/src.c9ac1cf4.js:20:425... } canvas-scene.ts:1
Uncaught Exception { name: "NS_ERROR_FAILURE", message: "", result: 2147500037, filename: "https://ray-marching-talk.netlify.app/src.c9ac1cf4.js", lineNumber: 20, columnNumber: 0, data: null, stack: "k@https://ray-marching-talk.netlify.app/src.c9ac1cf4.js:20:425... } canvas-scene.ts:1
Uncaught Exception { name: "NS_ERROR_FAILURE", message: "", result: 2147500037, filename: "https://ray-marching-talk.netlify.app/src.c9ac1cf4.js", lineNumber: 28, columnNumber: 0, data: null, stack: "t@https://ray-marching-talk.netlify.app/src.c9ac1cf4.js:28:748... } app.ts:269
https://www.redblobgames.com/articles/visibility/
it's been around for a while now, 2012 I guess