Thursday 27 April 2023

Creating an old-skool plasma effect

The "plasma" effect. An absolutely classic demoscene effect, and one I've wanted to program for a long time. If you're unaware, it's a cool, gloopy effect that resembles a lava lamp, and it was used in a lot of demos back in the day. I'd always wondered how it was done, and today, I finally managed to figure it out, and it's surprisingly simple. I think the reason I never did it, is because all the tutorials I see online use some wacky, complicated formulas that make my head spin. But it turns out you don't need ridiculous formulas to achieve a similar effect!

The basic principle is simple. You need to set up an X and Y counter when drawing your screen, and for every pixel, work out three values: the sine of the X, the sine of the Y, and some other value based off any combination of the two. Add these values together, divide by 3, and that's the colour index to draw to the screen. Once the screen is fully drawn, increment a "frame counter", which you also add to the three values. This creates the movement effect. Then, loop all of this and do it again!

When it comes to the colours, you'll notice that the default VGA palette looks very weird with this effect. It has no continuity whatsoever, so you'll need to fill the palette with a gradient, starting from dark and becoming brighter throughout the 256 colours.

That's basically it! Pretty simple, right? You don't need to come up with any weird formulas, just mess around and try to find an effect that looks good to you. Since I'm programming in assembly, I use bit shifting instead of division, which is much faster to calculate. Of course, it means I can only divide by 4 instead of 3, but that's not a problem, as it still looks rather nice.

Something of great importance is the speed. Calculating sines is very processor intensive, so it's best to use lookup tables instead. Of course, it can still be quite slow, because you need to "clamp" the value to 360, meaning it has to wrap around once it's above 360. Unfortunately, this requires division, as you're finding the remainder of a number, so it's still a bit slow, but way faster than calculating it manually. To get around this, simply render less pixels! For my example, I'm rendering it at a quarter of the full resolution. By the way, "clamping" is my own figure of speech ;)

Finally, I've shared the source code over at GitHub, if you'd like to check it out!

And here's a picture of it in action, drawing 4 pixels a time, alongside a graphic:



No comments:

Post a Comment

Amiga module player for DOS - the first draft!

After one week, I've finally pulled off what I previously thought impossible - an entire module player, running in real mode DOS! I'...