now I'm thinking about how cool a hexagon tilemap based DLA would look. probably a shitton of work tho as there aren't many ready made algorythms for hex tilemaps and probably a bit more resource intensive as hegagons have 6 sides to stick to, and upscaling is a bit problematic too, but it might just make a difference and worth trying
Damn this video is quality. Presentation, information, visualisations, exemplifications, explanations, discussion… And it all culminates in a banging symbiosis
I enjoy watching these types of programming videos, often times these new and fast animation techniques independently discovered are used and formally discovered years in computational physics. For example, the secret sauce technique referenced in the blog is analogous to GGA which is a technique used in density functional theory.
man man ,you are genius ,everything about this video is literal perfection from the explanation to animation to your humor , i wish you would drop more of your informative videos
6:33 That was such a good way of showing how the limited resolution could drastically affect the result. It's not a very complicated concept, but you just showed it so well
a note on 5:20 - 6:50 Individual values of the BRDF can exceed 1, but the integral across all incoming directions for one outgoing direction (or vice versa) has to be <1 for the BRDF to conserve energy
Is it just me, or does the second technique look more like the way water accumulates? Like, the pattern looks less like the height map of the mountain and more like the pattern of erosion.
The production value of these is insane. The water splash at 4:04 was unexpected and fun, and the two robots representing brute force and analytical approaches were great.
Speaking of noise, the little accent notes that play with each visual display are pitch-matched to the background music.... right? I'm not just imagining that? There are so many I'm thinking you must have programmed something to automate it for you. Nice work.
As a German i have to say this is completely wrong He forgot to write the k as a capital letter While he wrote “kurzgesagt” you where supposed to write “Kurzgesagt” Sometimes we also say kurzgeschlossen that is always not written in capitals
So, I needed practice thinking in GPU terms anyways, so I did the very useless thing of implementing the DLA method entirely inside of shader code :p It was, I feel, good practice for thinking about GPU and shader algorithms, in terms of optimization and in terms of just . . . being able to do things at all. It completes a 1024x1024 texture in about 1.5 seconds when run inside a game engine, and therefore much faster if it wasn't throttled to 60 frames per second. I'm pretty sure a CPU implementation would run much, much faster, since I'm effectively calculating an entire field of pixels for just a few walkers at a time! Using colour as an output, I used the red channel to signal to my shaders which stage it was at, or what stage of pixels it was drawing from, pixels with green were "walkers", and the blue channel was my generations. I spawn a bunch of green pixels on empty pixels, and then every frame, every green pixel checks if it is next to a blue pixel, if it is, it takes on the maximum value of a neighbour blue pixel and adds 1/1024; the lowest value I was confident wouldn't suffer from float precision. And then the green pixel blanks its green channel, regardless of whether it made a hit. Every blank pixel checks to see if it is next to a green pixel, and if it is, it has a 25% chance of becoming green; I used cell-wise randomization to produce the same random number for the four neighbours of a green pixel, and the 25% check looks for different parts of the [0-1] interval, so I am guaranteed to have a single new green pixel replace the old one, thus justifying calling them "walkers". I start on an 8x8 grid and double in size each stage, while increasing the time interval of each stage by 1.5x; if the sim runs too long, you end up filling the entire grid. If it runs too short, you obviously don't get much. So I tuned it so that each of the initial "peaks" I seeded it with ended up filling a good portion of the grid by the time all 8 stages are done. The pipeline then goes -> upscaler 1 -> upscaler 2 -> results buffer -> upscaler 1; I originally found that the initial layers were always too blocky, no matter how aggressive the upscalers were. And since I'm doubling the grid, the effect of a NN upscaler is just . . . dividing the channels by 4. So instead I used a quick distance-based averager and ran it twice. The first upscaler estimates the height input before it upscales. I don't have a good way of counting the maximum generation that was produced, so I simply estimated the maximal generation at each stage, multiplied that by a bit so as to not risk losing information, (which would cascade), and then divided the blue channel by that, inverted the value, and then set the height of the pixel equal to (the result buffer) + (1.0 - the height in the result buffer) * (the height just calculated) * 0.75 ^ [stage]. Then it upscales. The second upscaler is also just an averager, I just needed a second pass. This ended up also solving another issue I had, which is that this method of terrain generation produces almost solely "hollow" terrain. I ended up with a lot of ring-shaped mountains! And then ring-shaped sub-structures. And ring-shaped islands on ring-shaped archipelagos. As long as I went big enough, rings. The rings are often still present, but not the predominant repeating feature of the landscape. The simulation shader of course also pipes to a crisp upscaler, which pipes back to the simulation shader. The crisp upscaler brings every pixel to the upperleft pixel in the matching 2x2 in the upscale, the lower left and upper right pixels check for neighbouring generations and then have a 1/3rd chance to populate themselves, and the bottom right pixel checks the current cell, the cell to the right, the cell below, and the cell down-below for neighbouring generations, and has a 1/3rd chance for each to populate itself. These 1/3rds are all cell-wise randomized, and thus one of the 1/3rds are guaranteed to trigger . . . and that's pretty much it. Thanks for the fun challenge, I'm still teaching myself shaders from scratch and wading into territory like this where, obviously, no one has wasted their time doing this before really forces me to grapple with the ideas and possibilities in shader programming.