
Show HN: Metaballs - winkerVSbecks
http://varun.ca/metaballs
======
slavik81
From the grandparent article:

> Well, for 40 bouncing circles, on a 700x500 grid, that would be on the order
> of 14 million operations. If we want to have a nice smooth 60fps animation,
> that would be 840 million operations per second. JavaScript engines may be
> fast nowadays, but not that fast.

The math is super-cool, and efficiency is important for finding isosurfaces in
higher dimensions, but those aren't really scary numbers for normal programs.
Just tinting the screen at 2880x1800 is ~2 million operations per frame. GPUs
can handle it.

A simple way to render is to draw a quad for the metaball, using the metaball
kernel function in the fragment shader. Use additive blending while rendering
to a texture for the first pass, then render the texture to screen with
thresholding for the second pass. The end result is per-pixel sampling of the
isosurface.

Admittedly, it's kind of a brute-force solution, but even the integrated GPU
on my laptop can render thousands of metaballs like that at HiDPI resolutions.

(Specifically, I use a Gaussian kernel for my metaballs. It requires exp,
which is more expensive computationally than a few multiplies. I render 1500
of them at 2880x1671 at 5ms per frame on an Intel Iris Pro [Haswell].)

Though, the work scales with fragment count, so a few large metaballs may be
as costly many smaller ones. For large numbers of metaballs, you probably also
want to use instancing so you'd need OpenGL ES 3.0 / WebGL 2.0 which are
fairly recent.

But 40 metaballs with a simple kernel at 700x500? That's easy for a GPU.

~~~
skeoh
I believe 2D canvas rendering is performed on the CPU rather than the GPU.

~~~
ZenPsycho
much of it is offloaded to the GPU by recent browsers

~~~
slavik81
The important bit is getting the metaball function into the fragment shader.
I'm not really a web guy, but I know you can do that with WebGL.

For a canvas with a more limited API, you can still do it _if_ images are GPU
accelerated with a composite mode like "lighter". If that's the case, you can
do basically the same thing by first rendering the metaball function to an
image once, and then drawing that image for each metaball. Doing it via an
image introduces extra aliasing artifacts, but might get around the API
limitations.

Edit: I suppose you would still want to find a GPU-accelerated threshold
function for the step after that.

------
femto113
Feels more organic to me if the original metaball gets smaller as the other
one moves out (like its stealing material). Haven't worked out the correct
math but a quick PoC is here:

[https://codepen.io/femto113/pen/MEZava](https://codepen.io/femto113/pen/MEZava)

~~~
fergyfresh
That is weirdly satisfying to watch...

~~~
Raphmedia
Would make a great loader icon.

------
mikewhy
Reminds me of this demo from years ago:
[https://tympanus.net/Development/CreativeGooeyEffects/menu.h...](https://tympanus.net/Development/CreativeGooeyEffects/menu.html)

Article for more detail: [https://tympanus.net/codrops/2015/03/10/creative-
gooey-effec...](https://tympanus.net/codrops/2015/03/10/creative-gooey-
effects/)

~~~
andai
Oh wow, it's a gaussian blur and basically a threshold function (boosting the
contrast) using SVG filters! I didn't know this was possible. Very clever!

------
dmschaab
Interesting approach! Coincidentally, I published an article [0] on this very
topic last month. It uses sampling, so it's close to the approach mentioned in
the Jamie Wong article you (and I) linked to, but with a path-tracing step
capable of producing an SVG path definition. I'd be interested to see how the
performance of these two methods stack up to each other for a given quality
level.

[0]
[https://eightsquaredsoftware.com/articles/metaball.html](https://eightsquaredsoftware.com/articles/metaball.html)

~~~
pault
FYI the demos are impossible to use on an iOS device since trying to drag the
time slider causes the browser back animation to start.

~~~
dmschaab
Thanks for pointing that out. I did test on an iPad, but perhaps it had a non-
current version of Mobile Safari or navigation gestures were disabled.

------
panic
In
[https://codepen.io/winkerVSbecks/pen/NazWxg](https://codepen.io/winkerVSbecks/pen/NazWxg),
there's a "hitch" as the discs touch due to a first-derivative discontinuity.
Here's a version which extrapolates the u1 and u2 variables, making the
transition much smoother:
[https://codepen.io/panic_/pen/BwvjmK](https://codepen.io/panic_/pen/BwvjmK).

~~~
zaroth
This is just calling out for a propagation wave effect through the parent ball
at the moment of separation.

------
bpicolo
That bubble slider is super cute.
[https://codepen.io/chrisgannon/pen/GZNgLw](https://codepen.io/chrisgannon/pen/GZNgLw)

~~~
thoughtpalette
I'm extremely impressed with the implementation. I'm not sure what I would say
if presented with a design like this slider for web. Wouldn't have imagined it
would work this beautifully as well.

Amazing showcase.

~~~
bpicolo
It definitely moved the opposite way I expected it to, but this way grew on
me, hah.

It's not a perfect UI element - you can't actually see the options without
scrolling through it all, but I could imagine something similar being a pretty
cool little thing in the right context

------
microcolonel
Good to see you on the front page, Varun. :- )

It's possible to do this _somewhat_ efficiently beyond two balls with GLSL and
lots of uniforms (or a UBO), since metaballs from the graphics perspective are
really just distance fields.

If you want more than a few balls, you can do it in two passes: one to produce
the distance field, and one to threshold it.

As an added benefit, it's straightforward to generalize these approaches to
any two-dimensional continuous function.

~~~
yoklov
I did something fairly similar to this here:
[https://codepen.io/thomcc/pen/vLzyPY](https://codepen.io/thomcc/pen/vLzyPY)
(I need to look into why this isn't running at 60fps anymore on my laptop, it
certainly used to...)

The big difference is that it prerenders a gradient for each ball (it uses
html5 canvas for that, but doing it with webgl is completely doable, although
a bit more work), which is used as a distance field.

~~~
microcolonel
> _I need to look into why this isn 't running at 60fps anymore on my laptop,
> it certainly used to..._

Runs at 60fps for me on a Chromebook from 2014. I suspect you're looking at it
on macOS, which has had very poor (arguably the poorest of any x86 platform)
OpenGL drivers for the last four or five years.

~~~
yoklov
I am, but it certainly was at 60fps on my laptop when I wrote it, which was
also a mac.

------
winkerVSbecks
For everyone complaining about the lack of meatballs… here are some:
[https://codepen.io/winkerVSbecks/full/oGJLwo/](https://codepen.io/winkerVSbecks/full/oGJLwo/)

------
Const-me
The math can be optimized by at least an order of magnitude.

Trigonometry functions are expensive, especially the reverse ones.

If v=0.5, see [1] for how to find out sine/cosine of a maxSpread * v. For
angleBetweenCenters + maxSpread * v, see [2] for how to find sine + cosine of
a sum of angles.

If you’ll do all that math in the symbolic form (you can use Maple or
Mathematica or something similar), you’ll get the equivalent formulae for
p1-p4 that won’t use any trigonometry, only simple math and probably a square
root.

[1]
[https://en.wikipedia.org/wiki/List_of_trigonometric_identiti...](https://en.wikipedia.org/wiki/List_of_trigonometric_identities#Half-
angle_formulae) [2]
[https://en.wikipedia.org/wiki/List_of_trigonometric_identiti...](https://en.wikipedia.org/wiki/List_of_trigonometric_identities#Angle_sum_and_difference_identities)

~~~
Const-me
Implemented a 2D angle class for cases like that, where you would otherwise
use these slow trigonometry functions. It’s C++ but should be easy to convert
to JavaScript or any other OO language.

[https://gist.github.com/Const-
me/46f90ce7fc2bc65dc12a41442ed...](https://gist.github.com/Const-
me/46f90ce7fc2bc65dc12a41442ed51f73)

------
santaclaus
> Metaballs, not to be confused with meatballs

I once reviewed an academic paper at a major CS conference that misspelled
metaballs as meatballs throughout.

~~~
jlg23
A nice example of the the impotence of proofreading![1]

[1]
[https://www.youtube.com/watch?v=OonDPGwAyfQ](https://www.youtube.com/watch?v=OonDPGwAyfQ)

~~~
ninju
And the __importance __(oh...I see what you did there...well played)

------
mileycyrusXOXO
I just started learning GLSL shaders. As practice, I wrote a psuedo-metaball
joystick. I didn't know about metaballs, but now that I do I can do some more
research and improve my next iteration.

Touch blob joystick shader:
[https://www.shadertoy.com/view/4lfcRf](https://www.shadertoy.com/view/4lfcRf)

------
spitfire
[https://www.youtube.com/watch?v=L_lD7iqG8nA](https://www.youtube.com/watch?v=L_lD7iqG8nA)

About 2 minutes in there's an excellent realtime metaballs implementation that
ran smoothly on a 486-66mhz. Metaballs were an extremely popular effect in the
early 90's.

~~~
twic
I wonder what the first demo to use metaballs was. Two candidates:

[http://www.pouet.net/prod.php?which=1023](http://www.pouet.net/prod.php?which=1023)

[http://www.pouet.net/prod.php?which=911](http://www.pouet.net/prod.php?which=911)

How about first on the C64? Here's Booze in 2010:

[http://www.pouet.net/prod.php?which=56003](http://www.pouet.net/prod.php?which=56003)

------
shove
Paper.js is truly a great source of vector drawing tricks. Curious how
difficult it would be to extend this technique beyond two circles. Might have
to dust off some old experiments ... :)

------
philipov
Oh no... I shook it a bunch and it broke apart ;_;

------
zokier
Metaballs are always nice, but I think this page (that was linked in the
article) that shows compass&straight-edge constructions to be especially
nifty:

[http://www.mathopenref.com/consttangentsext.html](http://www.mathopenref.com/consttangentsext.html)

~~~
emmelaich
See the Euclidea and Pythogorea phone apps for a puzzle game based on
geometric principles.

------
theoh
During or just before WW2, Roy Liming developed analytic techniques for
calculating a similar class of blend or fillet. They were taken up in aircraft
design, a field that I can't imagine ever using implicit surfaces! I think it
was Edgar Schmued's design for the P-51 Mustang that famously used Liming's
work.

Liming wrote a book, but it's rare. Some technical discussion towards the end
of this page:
[http://homepages.inf.ed.ac.uk/rbf/CVonline/LOCAL_COPIES/BOWY...](http://homepages.inf.ed.ac.uk/rbf/CVonline/LOCAL_COPIES/BOWYER1/c6.htm)

------
ladon86
Was this the technique used in World of Goo?

~~~
easytiger
I believe (the amazing) World of goo used stretched bitmaps* ( at least in the
prototype )

* [https://www.gamasutra.com/view/feature/2438/how_to_prototype...](https://www.gamasutra.com/view/feature/2438/how_to_prototype_a_game_in_under_7_.php)

------
asadlionpk
This actually refreshes my memory. I had to implement some metaballs myself
some years back for a fluid simulation.

I had to struggle with metaball rendering on canvas back then. It was so slow.
Now I guess a pixel shader in webGL can do a better job.

Check this out too:
[https://asadmemon.com/SPHjs/](https://asadmemon.com/SPHjs/) source:
[https://github.com/asadm/SPHjs](https://github.com/asadm/SPHjs)

------
christotty
An alternative method (with potentially different applications) that I found
interesting. The visual aids in both articles are very good.

[http://jamie-wong.com/2014/08/19/metaballs-and-marching-
squa...](http://jamie-wong.com/2014/08/19/metaballs-and-marching-squares/)

------
fzaninotto
We've use the blur+contrast approach successfully in EventDrops [1], a time
series visualisation based on d3.js. It all happens client-side, with OK
performance. Not sure the SVG approach brings more in this case.

[1] [https://marmelab.com/EventDrops/](https://marmelab.com/EventDrops/)

------
a_e_k
Andrew Glassner published a paper on something extremely similar back in 2015:

"Globs: A Primitive Shape for Graceful Blends Between Circles"

[http://jcgt.org/published/0004/03/01/](http://jcgt.org/published/0004/03/01/)

------
davidkuhta
This is pretty awesome.

I wonder how much would need to be adjusted to provide a scaling factor to the
first metaball such that the area was constant (Thus ending up with two
equally sized metaballs) or even utilizing the speed of the pull in
determining the second balls size.

------
memco
This is cool. Just watched a related talk from Casey Muratori about this
yesterday:
[https://www.youtube.com/watch?v=SDS5gLSiLg0](https://www.youtube.com/watch?v=SDS5gLSiLg0)

------
macca321
What's the practical, commercial use for something like this? It looks like it
must take a lot of time and effort to get this right.

Or is this university stuff? Or even spare time stuff?

------
corprew
I clicked through this hoping that someone had done a 'Show HN' for a literal
plate of meatballs.

------
robodale
I keep seeing Metaballs as Meatballs.

~~~
alexyskywalker
I did too! All the way until I read this comment

------
staticelf
I am from Sweden and read "meatballs" when I clicked. Just imagine my
disappointment.

Cool stuff though.

------
fibo
there is a popular vvvv shader that implements metballs, see
[https://vvvv.org/blog/debug2-2](https://vvvv.org/blog/debug2-2)

------
Osmium
Could this extend to 3D?

~~~
kowdermeister
Yes, there's a Three.js demo:

[https://threejs.org/examples/#webgl_marchingcubes](https://threejs.org/examples/#webgl_marchingcubes)

~~~
Osmium
That's marching cubes though, which is different from the parametric/Bézier
approach in the article?

~~~
kowdermeister
Marching cubes is the rendering technique, it's based on distance fields which
is a similar idea to iso-surfaces.

With the SVG/Bézier approach I doubt you could do 3D, true :)

------
mgalka
Surprised I've never seen metaballs before. Very cool.

------
mar77i
I prefer Regular Ordinary Swedish Metaballs™

------
retor
That's one spacey metaball! (sorry...)

------
fenollp
>CodePen requires a referrer to render this. Your browser isn't sending one.

Interesting.

~~~
icebraining
Apparently it's to prevent phishing. You should be able to click on "Edit on
Codepen" to see it.

(Not affiliated with them, I just found
[https://blog.codepen.io/2017/10/05/regarding-referer-
headers...](https://blog.codepen.io/2017/10/05/regarding-referer-headers/))

------
fairpx
I would love to incorporate this in some of the UI design work we do for
startups. Are there more similar libraries available? We could reference it to
our network of clients (mostly developer driven startups) to help translate
some of the design ideas we propose. If you know of other similar projects
like Metaballs, please do share below or ping me (details in my bio)

------
alex_suzuki
I was disappointed that this was not about meatballs, for I am hungry.

