Acid Glow by Loonies [web] & Logicoma [web]
Loonies and Logicoma present Acid Glow A 4k intro for Windows Winner of the TRSAC 2022 PC intro compo Credits: Blueberry: Synth, 303 emulation Booster: Music Ferris: Visuals Psycho: Framework, optimizations This intro is the debut of Jingler, a work-in-progress modular 4k synth. Follow the development at: https://github.com/askeksa/Jingler The emulated 303 synth and the other instruments and sound effects are implemented in the Zing programming language, which is part of the Jingler synth. The Zing compiler translates the Zing program into special bytecode which is embedded in the intro along with a small bytecode compiler that translates the bytecode into x86 code before execution. The algorithm for the 303 emulation is loosely based on the method used in JS303: https://github.com/thedjinn/js303 The final version includes a bit more variation in the visuals to give a greater sense of climax, plus some volume/panning adjustments in the music. Some words about the visuals from Ferris: About a month before the party I had the pleasure of attending a Jon Hopkins show in Oslo. It was absolutely excellent; obviously the audio was fantastic, but the visuals were great too, despite being little more than spotlights shining through copious amounts of fog. This really left an impression on me; I realized how effective such a simple setup could be, so I decided I'd keep that idea in my back pocket. Well, it didn't stay there long, as a few days later, Blueberry contacted me to see if I would want to do visuals for an intro for TRSAC to test his new 4k synth. Seeing as I didn't have anything else cooking at that point, and it would be my first IRL party in 3 years, I really didn't want to decline. As I was already thinking about it, I suggested that spotlights in fog might work well in 4k, but I wasn't sure it would carry a full intro. Fortunately, the plan was already to have Booster do an acid track to complement the acid compo at the party, where there would _also_ be spotlights in fog IRL, so this idea would actually be a perfect fit! Still, the party was only a few weeks away (which due to my current IRL situation is not nearly as much time as it used to be!), and I knew that implementing it the straightforward way would be too slow to get a decent number of lights on screen, so, while I did accept the offer, I was feeling a bit reluctant about it (and procrastinated a bit). However, experience has taught me that the most fun and satisfying thing to do generally, especially when things are uncertain, is to dig deeper and not just settle with the easiest thing to do, so a couple weeks before the party I finally bit the bullet and got started. OK, so point lights in fog are not difficult to render at all just using Riemann sums, and with importance sampling a relatively small number of samples per-light can be used. Still, I wanted to try and do something smarter so I could increase the number of lights (as <= 10 or so would have been too easy and likely not enough to build interesting forms from) and also hopefully reduce sampling artifacts, and it seemed like perhaps a purely analytical solution would be possible (at least for a relatively simple model, eg. single scattering with an isotropic phase function). I spent several days at the limits of my (admittedly crude) understanding of both participating media rendering and calculus; alas, I was unable to find a solution which was 1. entirely analytical, and 2. didn't crash the DX shader compiler. As the party drew closer and my patience dwindled, I started changing the approach, and ultimately found a set of compromises which I'm (relatively) happy with. The first major compromise is to use homogeneous fog (which can still look great if done correctly), and the second is assuming the product of the integrals of functions is the same as the integral of the products of those functions. Under these assumptions we can use an existing analytical solution ([0], and see [1] for a shadertoy implementation, cheers to greje656 for that!) for solving transmittance for each light as if it were a point light, and simply multiply that contribution by an integral representing the spotlight shape. The spotlight shape formulation I used was simply the dot product of the (normalized) light vector and the spotlight direction vector, raised to some power to make a wider/narrower cone. Assuming we only calculate the integral for this in front of the light (i.e. where the dot product is positive), this should be straightforward to compute. So, an analytical intersection between the light ray and a plane "behind" the light is performed, such that we can determine which segment of the ray to accumulate over (or if we can skip accumulation for this light altogether). Unfortunately, I was unable to find an analytical solution for the actual integral (though I'm not entirely convinced it's not possible; a different formulation and/or an approximation should be possible here, which may be worth exploring again, given more time and/or another use case), so I ended up just using a Riemann sum with a small (read: cheap/hacky) importance sampling approach. This introduces some noise which ends up looking quite pleasant in many cases, especially when the light is pointing towards the viewer, but it can also look not-so-great, especially when the light is perpendicular to the eye ray and the cone is narrow. I did experiment a bit with trading noise for undersampling artifacts, but ultimately decided I liked the noise better. Instead of just multiplying the integrals, I decided to leverage the fact that we calculate them separately by making the artistic choice to blend them, such that the point light solution is still faintly visible. This way we don't just get light contribution in the cones, but also in a somewhat-subtle "halo" in all directions, which I think looks quite nice. It also reduces noise a bit at the very tips of the cones, which can really help image stability in some cases. Overall, I think the hybrid analytical/sampling solution turned out OK in terms of the speed/size/noise tradeoff. I still feel somewhat unsatisfied with not finding a faster/less noisy solution, but it's certainly better than nothing, and even though I didn't quite get where I wanted to, I really enjoyed going for it and spending time trying to do something new and non-obvious (to me, at least). And, importantly, it's still much faster than just sampling for the entire integral, so it allowed enough lights to make interesting shapes which ultimately fit the music quite well. On that note, after getting some scenes together, it quickly became clear that I'm very much out of practice writing 4k shaders; the actual scene code ended up much larger than it could have been. I should have found a smarter/more parameterizeable approach for building scenes that would have reduced them to simpler parameter sets. Still, there was enough "air" in there to get it down (big thanks to Psycho for helping so much with reigning this in!) and along with a bit of byte hunting in the synth code/music data/main function (and also dropping rocket in lieu of some very basic if statements in the shader, as we didn't need that much sync) we eventually got it down enough for the compo. Special thanks to Blueberry for inviting me to participate in this project, to Booster for making a banger 4k track, Psycho for donating the framework and tips/bug hunting/optimization help (and all while being stuck at home with a broken elbow; you were missed at the party!), karo133ne for support (especially dealing with my frustration when things weren't working), name/direction suggestions, and of course buying me the Jon Hopkins tickets in the first place, the TRSAC orgas/compo team for yet again making a *fantastic* party and their patience getting our intro working on (one of) the compo machines, and, related, Gekko for donating a "spare soundcard" in the form of an enormous blinky box which fortunately had less line noise than the external sound card that that particular machine had previously! [0]: Vincent Pegoraro, Mathias Schott, and Steven G. Parker. 2009. An analytical approach to single scattering for anisotropic media and light distributions. In Proceedings of Graphics Interface 2009 (GI '09). Canadian Information Processing Society, CAN, 71–77. [1]: https://www.shadertoy.com/view/XtjfzD
[ back to the prod ]