Recreational coding: Lava Lamp Animation
If you’ve ever seen a lava lamp, you understand the mesmerizing spectacle of liquid blobs gracefully ascending and descending. How can we recreate this real life spectacle using code? This is what we’ll be covering in this blog post. The final result can be seen in the CodePen below. The reason of potential lag you might experience when running the animation is because it is performance-intensive, and we’ll address the issue at the end.
🎉 New Series
This is the first blog post of a new series I’m starting called Recreational coding. In this series, the goal is to code for fun and not for any practical purpose. Join me, as we explore the beautiful side of programming.
Grasping the complexity
Take a moment to reflect: How do we even begin coding something like this? How can we draw a fluid-like shape? If you can’t figure out how, allow me to reveal it to you. For a start, let’s think how we would draw a circle. We can divide our rendering area into a grid of pixels. We can imagine this grid as a coordinate plane. To then draw a circle we would need to fix a center and a radius. We can color the points inside the circle purple by checking if the point’s distance surpasses the circle’s radius. Below is a demo using p5.js which uses the Canvas API under the hood.
You can access the
script.js file in the editor tab to view the code. The
setup function contains the code for drawing the circle.
Do you see what we did here? We utilized a mathematical formula to draw the desired shape—a circle. Is there a mathematical function that can depict the fluidic shape we desire? Additionally, this function should be computationally feasible, enabling us to calculate it multiple times per second to create our animation. It appears that if nature serves as our inspiration, it also offers the solution. In simpler terms, we’ll be utilizing physics to derive the required mathematical function.
Before diving into the elegant physics, allow me to provide the historical context behind this. The fluidic, ball-like shapes we are aiming to create are called metaballs. The technique for rendering metaballs was pioneered by Jim Blinn in the early 1980s, and its original purpose was rather surprising: it was invented to model atom interactions for Carl Sagan’s 1980 TV series Cosmos. While one might assume it would be related to fluid dynamics or theories about fluids, it is actually derived from electrostatics—a theory of electric charges.
The concept originates from the theory of electric potential. In simple terms, the electric potential at a point in space is the amount of potential energy required to move a point charge (the charge used to test the potential) if it were placed at that point. The formula for calculating it is as follows:
is the magnitude of the electrostatic potential, is Coulomb’s constant, is the magnitudes of the the charge creating the field, is the separation distance between of the point from the center.
The formula indicates that as we move away from the center, the potential decreases. This makes sense because it takes more energy to move a point charge placed near to the center of the interested chage. We can implement this mathematical formulation in code and observe the ensuing outcome. Take note of how the blue hue, representing electric potential, diminishes as we distance ourselves from the charge’s center.
However, how does the above solve our problem of rendering metaballs? To see that, we have to add another charge at a little horizontal separation from the first. When you run the below code, you would notice that the electric potential is high between the center of the two charges and the electric potential surface formed looks like what we’re looking for. The fading peanut-shaped blue region indicates decreasing potential away from the center of both charges. But what would be the function which describes this shape which is formed due to the combined effect of both the charges on a point? How complex would it be compared to the function for electric potential due to a single charge?
You might already know it, but if you don’t, you’ll be pleasantly surprised to learn that the electric potential due to multiple charges at a point is simply the summation of the electric potential due to each charge. Take a moment to appreciate the beauty of this statement. It is not only simple to calculate the effects of multiple charges but also efficient enough to calculate for every point on the screen.
So, let’s incorporate this principle into our code. We introduce two point charges, charge1 and charge2. For every point in the coordinate space, we calculate the potential on a point due to both charges and appropriately color the representation to visually depict the outcome.
You’re already loving this post, aren’t you? But hold on until we complete some finishing touches. We want to move those charges. We give the charges/balls an initial random velocity and also implement a
move method which would be called regularly to update the position of the balls simulating the moving animation. We also implement bouncing off the edges of the screen by flipping the relevant component of velocity.
Furthermore, we make some style changes, such as altering the background color to black. We create a linear gradient from top to bottom for the color of the fluid, making the bottom portion brighter than the above. This is achieved by increasing the green value from 100 to 200 in
fill(225, gradient, 25, pointOpacity);. We also reduce the
pointOpacity after a certain threshold, which is optional. Check out the final animation below.
To be continued…
I hope you enjoyed constructing this gratifying animation. However, there are still some minor details to address. The animation currently appears pixelated, a concern we can address by reducing the
PIXEL_SIZE. Yet, reducing the
PIXEL_SIZE could impact performance. To tackle this, we need to innovate our rendering technique. In a forthcoming blog post, we’ll delve into implementing an alternative method known as marching squares, a widely used technique in computer graphics.
So, that covers everything I wanted to convey in this post. I value your curiosity for coding, and I hope you continue to take moments to appreciate the genuine beauty of programming. Goodbye and I can’t wait to see you in the next post.