8:45 I really suggest going through "Minecraft terrain generation in a nutshell" by Henrik. It seems Minecraft uses 3 other values and spline points to solve the issue of biome transitions. It also has just in general a bunch of information on how to handle terrain generation in a way to make it look really good. It's what I plan on doing when I work on a voxel game again.
Was gonna comment the same! I remember thinking "It was such a huge problem for minecraft, how did he solve it so ezpz?" and then watched the rest of the video and saw him describe how it wasn't all ezpz xD
That video has a lot of great info, but it also goes best with some caveats: - It teaches a context-less "Perlin-first" mindset for noise, but Perlin has unnatural squareness issues and is just one of many noise algorithms to choose from. Better generally to use Simplex(-type) noise or employ reliable artifact mitigation measures with Perlin. See article titled "The Perlin Problem: Moving Past Square Noise". - It discusses smoothed white noise as being "gradient noise" which isn't entirely accurate. It would still be correct to count smoothness as a requirement for noise, though.
I love your game development series in rust! you are such a fun character, and it is lovely being able to see a game developer that doesn't focus purely on gameplay or purely on code when it comes to their devlogs, and to go on and explain (some of) the mechanics of how it works! Love it!
this has really opened my eyes quite a bit when it comes to world gen, have always struggled with getting decent biome based world generation, great vid broskie
Rust is awesome. I enjoyed your maths explanations, blending is hard - I would probably do a multi-pass method of generation or not include blending at all. Or use voronoi areas where the space between each voronoi is marked as a blend area. Not sure that's simpler than your solution. Keep it coming, sir!
Wow, really good progress! I loved your devlog! Your videos always put me on good mood, thank you so much for making them! Ser fram emot nästa devlog (men ta all den tid du behöver, förstås) :D
Here's an idea. Instead of trying to interpolate between biomes, each biome (which has its own terrain generation) have biome humidity and temperature ranges that overlap. So when you get values that can be applied to both a desert and grass biome the grass and sand blend nicer, and you can also change the color of the sand/grass based on the humidity. (You essentially create border biomes). You could also start with a smoother height map at first and use elevation as a factor; as atmospheric pressure can also determine a climate. I feel like this would be the best approach but idk how fast it would perform, and how well it would look. But this would also sorta remove biomes as there also wouldnt be a clear cut off. But it would allow for smoother transitions
I am calling it now, TanTan will be the first Developer to properly publish a fully complete game through Bevy and Rust! I love the biomes logic with temperature and humidity. Id definitely like to see how the math works behind this biome interpolation rule Love your videos man :D
@8:56 If performance wasn't important, I would have taken every percentage to a certain power. Also the percentage should be inversely proportional to the distance ofc, so use a negative power. This sharpens the transitions. If you have found a nice looking power, just implement it as a stack of multiplications, e.g. x^16 = x2=x*x;x4=x2*x2;x8=x4*x4;x16=x8*x8; Important note: normalize after taking the power! 😄
Any decent compiler will optimize the "power to a constant" - unrolling it manually will at best make the optimizer work harder to notice what you are doing, and reimplement it optimally for given arch. At worst, it will stay suboptimal and less readable. - It might be worth doing in a shader, but even there I doubt it. See num.pow(16) at godbolt with `-C opt-level=3`
@@Verrisin I tested it for OpenGL once for my RX580 and only the cases 2,3,4,8 were optimized. (cannot post a link here, as YT deletes it then; is my most upvoted answer on StackOverflow)
@@AntonioNoack Interesting. But, yeah, it makes sense the optimizer would be simpler to load shaders faster. (to be fair, I don't even know how to check what shaders get compiled to...)
To get rid of hard "edges" while switching the depth maps - simply "add" those depth maps to one "global" depth map. This way it will all blend "fluid"-ly
Why not do normal blending but square all probabilities(or some other exponent in the range of 1.1-10) and then normalize them? Blending would be more extreme, but around edges where multiple biomes apply, you still get roughly equal split, but one biome would start dominating faster after it goes above others. Higher the exponent, the more drastic the change. With say 70% desert, 30% snow, after squaring it's 0.49 desert, 0.9 snow, or 84% desert, 16% snow. By cubing, you'd get 93% desert, 7% snow. So any effect of snow would be dramatically decreasing as the exponent increases
yay another devlog from Tantan. Game looks like it's coming along nicely. With each upload its tempting me to challenge myself to do the same thing. Crate a fun simple game with nothing but code but my version would be with python the language I'm learning.
For the lag spikes when loading a new chunk; I would implement multi-threaded code. For one thread, you'd would contain normal game processes, and then on different thread, you would make that manage any new chunk loading. This way, your game doesn't suddenly drop in performance upon loading a new chunk.
Or more performant: clamped S-curves, e.g. 3t²-2t³ where t is clamped to between 0 and 1. Pass all your weights in, offset and clamped as required, then re-normalize the result so all biomes' weights once again sum to 1.
Really cool video, hopefully I'll be able to make something fractionally as awesome one day. Always nice to see another Linux user in the game dev space though 👍
Defining terrain by temperature or height seems odd to me.. look at the grand canyon where you can have negative values... also snow can remain on peaks for long periods of time even after weather goes warm. I would have considered adding some parameters like heat/cold accumulated in the soil which would increase or decrease over time depending on temperature/sun/weather... ex rain falling would cool soil a bit, night would cool soil a bit ... during winter peaks with snow would cool significantly so even when temperature goes above 0 degrees the snow would not melt because the soil is cold and gradually warms up over time. I was also thinking small rivers in desert or small lakes in oasis in desert, the water evaporating from lake or river can make the river sides/around lake area cooler, with grass etc
Man please keep uploading. Your struggle is greater than mine but I've been tearing my hair out doing Qongzi's Minesweeper tut. The repo is different from his tut and I don't want to just git clone it and voila it works. I'm trying to learn Rust. I can print out the values I insert into my mutable HashMap that I pass into the mutating function but after it returns? Hashmap is empty. I've been coming back to this code everyday trying to figure out WTH is going on and why a mutation is passing Rust's checks but it's coming out totally freaking empty. So to see hear about your struggles is super cool man and I appreciate it! Growing pains
Wow thats some impressve progress! I didn't look into the code but I wonder if you could pregenerate a lot of the calculations needed for biome blending etc. ahead of time so they don't affect FPS that much.
Brilliant to see you come back to voxels and working on this game! Hearing about the modularisation of the game was great. Did you actually add any unit tests?
maybe some sort of voronoi-like implementation could help streamline your biome blending process? if you're using 2d noise to instance your biomes, each voronoi cell represents the individual biome regions, and then you get clearly defined borders that you could apply some sort of special interpolation to... theoretically you'd end up with edges, could match on all possibly pairs of neighbors, and craft cases for each that optimize for both neighbors' features? no idea if this is helpful or even makes any sense lmao
I use a somewhat related process. I don't directly use Voronoi geometry, though, just the point distribution you might use with Voronoi. Scatter randomly placed points around the world such that they're never spread too far apart (e.g. a jittered grid -- like Voronoi noise usually uses). Sample the biome at each point (no blending yet). Then, for each block (or rather block column) in the world, loop over all sampling points within a certain radius of it. Use a smooth falloff curve e.g. max(0, R²-x²-y²)³ to contribute a weight to the biome it samples, then divide each biome's individual weight by the total weight so they all sum to 1. You can optimize this with various caching and range querying techniques (incl. querying all the points in range of the current chunk being generated).
While you might want to make it look and feel like cube world, please don't be like cube world and actually finish the game, I'm really hyped for your work!
WFC is a very interesting tool. One of the biggest holdups I would have to applying it to more natural-curvature-based terrain would be its strong preference for grid directions (moreso even than certain noise generators which I covered in another comment). I think translating the idea to randomly scattered points (Poisson, or at least jittered grid with the neighbor relationships recomputed), though, would make for some quite useful and visually appealing results when combined with the right rulesets and pre/post-processing steps.
I'm using bevy's rendering plugin, but I've made most of it from scratch with wgpu. If you want to do more custom rendering things in bevy, you need to write some wgpu code.
just an idea that compliments tons of dull work and content creation - try streaming :) you don't have to edit a whole week of footage, you just get angry at maths and it's good entertainment
Threads on windows are shitty and take like 10x longer to spin up on windows vs linux. You should create a pool of threads up front and assign work to these threads to handle rendering. I'd bet that's where your slowdown is on windows.
With each upload: rust calls me.
Respond to it then
scratch is way better Imo
$1000 to whoever makes a better game in rust? (not a challenge, a video idea)
@@Ray_uck "I MADE MY DREAM RUST GAME"
maybe you might make original content finally
8:45 I really suggest going through "Minecraft terrain generation in a nutshell" by Henrik. It seems Minecraft uses 3 other values and spline points to solve the issue of biome transitions. It also has just in general a bunch of information on how to handle terrain generation in a way to make it look really good. It's what I plan on doing when I work on a voxel game again.
Was gonna comment the same! I remember thinking "It was such a huge problem for minecraft, how did he solve it so ezpz?" and then watched the rest of the video and saw him describe how it wasn't all ezpz xD
That video has a lot of great info, but it also goes best with some caveats:
- It teaches a context-less "Perlin-first" mindset for noise, but Perlin has unnatural squareness issues and is just one of many noise algorithms to choose from. Better generally to use Simplex(-type) noise or employ reliable artifact mitigation measures with Perlin. See article titled "The Perlin Problem: Moving Past Square Noise".
- It discusses smoothed white noise as being "gradient noise" which isn't entirely accurate. It would still be correct to count smoothness as a requirement for noise, though.
Is anyone designing or know an open-source modular voxel game/engine in Rust? (Bevy?)
I love your game development series in rust! you are such a fun character, and it is lovely being able to see a game developer that doesn't focus purely on gameplay or purely on code when it comes to their devlogs, and to go on and explain (some of) the mechanics of how it works! Love it!
Loving the dedication. And your enthusiasm for Rust got me into learning Rust.
Looks very cool so far! That frustration into grinding into eureka moment programming gives you is always so good.
nah: create an height map and place the biomes on top of it
yes: make the terrain dependent by biome
TanTan logic
this has really opened my eyes quite a bit when it comes to world gen, have always struggled with getting decent biome based world generation, great vid broskie
Man am I glad I found this channel 3 days ago! This was definitely worth the wait!
Rust is awesome. I enjoyed your maths explanations, blending is hard - I would probably do a multi-pass method of generation or not include blending at all. Or use voronoi areas where the space between each voronoi is marked as a blend area. Not sure that's simpler than your solution. Keep it coming, sir!
Wow, really good progress! I loved your devlog! Your videos always put me on good mood, thank you so much for making them! Ser fram emot nästa devlog (men ta all den tid du behöver, förstås) :D
Absolutely absolutely!
Here's an idea. Instead of trying to interpolate between biomes, each biome (which has its own terrain generation) have biome humidity and temperature ranges that overlap.
So when you get values that can be applied to both a desert and grass biome the grass and sand blend nicer, and you can also change the color of the sand/grass based on the humidity. (You essentially create border biomes).
You could also start with a smoother height map at first and use elevation as a factor; as atmospheric pressure can also determine a climate.
I feel like this would be the best approach but idk how fast it would perform, and how well it would look.
But this would also sorta remove biomes as there also wouldnt be a clear cut off. But it would allow for smoother transitions
your name made me laugh because i was thinking, "Off brand pew-die-pie" when watching this video
I am calling it now, TanTan will be the first Developer to properly publish a fully complete game through Bevy and Rust!
I love the biomes logic with temperature and humidity. Id definitely like to see how the math works behind this biome interpolation rule
Love your videos man :D
Your best video in a while! Really enjoyed this one - this is the type of stuff that motivates me to keep working on my own game as a solo dev myself
spiritual successor to cube world, nice
Check out Veloren
@4:42 it's awkward to use soo huge numbers... I prefer first shifting, then masking. E.g. (color & 65280) >> 8 becomes (color >> 8) & 255.
That's so much cleaner, thanks!
I always doubt what to read or where to start with things like this but i love the way you explain things
@8:56 If performance wasn't important, I would have taken every percentage to a certain power.
Also the percentage should be inversely proportional to the distance ofc, so use a negative power.
This sharpens the transitions.
If you have found a nice looking power, just implement it as a stack of multiplications, e.g. x^16 = x2=x*x;x4=x2*x2;x8=x4*x4;x16=x8*x8;
Important note: normalize after taking the power! 😄
Any decent compiler will optimize the "power to a constant" - unrolling it manually will at best make the optimizer work harder to notice what you are doing, and reimplement it optimally for given arch. At worst, it will stay suboptimal and less readable.
- It might be worth doing in a shader, but even there I doubt it.
See num.pow(16) at godbolt with `-C opt-level=3`
@@Verrisin I tested it for OpenGL once for my RX580 and only the cases 2,3,4,8 were optimized.
(cannot post a link here, as YT deletes it then; is my most upvoted answer on StackOverflow)
@@AntonioNoack Interesting. But, yeah, it makes sense the optimizer would be simpler to load shaders faster.
(to be fair, I don't even know how to check what shaders get compiled to...)
To get rid of hard "edges" while switching the depth maps - simply "add" those depth maps to one "global" depth map. This way it will all blend "fluid"-ly
It amazes me the amount of work you put to make each video.
Nice to see this project return after so long! Very interesting!
Keep it up, love your rust/bevy videos!
Maths is hard - awesome progress. Upload on your own pace. You are in control.
Good work Tantan! I can't wait for your next update :D
Why not do normal blending but square all probabilities(or some other exponent in the range of 1.1-10) and then normalize them? Blending would be more extreme, but around edges where multiple biomes apply, you still get roughly equal split, but one biome would start dominating faster after it goes above others. Higher the exponent, the more drastic the change. With say 70% desert, 30% snow, after squaring it's 0.49 desert, 0.9 snow, or 84% desert, 16% snow. By cubing, you'd get 93% desert, 7% snow. So any effect of snow would be dramatically decreasing as the exponent increases
yay another devlog from Tantan. Game looks like it's coming along nicely. With each upload its tempting me to challenge myself to do the same thing. Crate a fun simple game with nothing but code but my version would be with python the language I'm learning.
Really nice progress so far. I really have to do something with voxels myself eventually :D
Your videos are always a treat!
For the lag spikes when loading a new chunk; I would implement multi-threaded code. For one thread, you'd would contain normal game processes, and then on different thread, you would make that manage any new chunk loading. This way, your game doesn't suddenly drop in performance upon loading a new chunk.
Looking forward for the optimization video and explanation about this different performance in the OS'
When doing biome interpolation, i think simply a sigmoid function could do the trick
Or more performant: clamped S-curves, e.g. 3t²-2t³ where t is clamped to between 0 and 1. Pass all your weights in, offset and clamped as required, then re-normalize the result so all biomes' weights once again sum to 1.
@@kjpg7413 nerd
I freaking love Rust too, man
Really cool video, hopefully I'll be able to make something fractionally as awesome one day. Always nice to see another Linux user in the game dev space though 👍
Defining terrain by temperature or height seems odd to me.. look at the grand canyon where you can have negative values... also snow can remain on peaks for long periods of time even after weather goes warm. I would have considered adding some parameters like heat/cold accumulated in the soil which would increase or decrease over time depending on temperature/sun/weather... ex rain falling would cool soil a bit, night would cool soil a bit ... during winter peaks with snow would cool significantly so even when temperature goes above 0 degrees the snow would not melt because the soil is cold and gradually warms up over time. I was also thinking small rivers in desert or small lakes in oasis in desert, the water evaporating from lake or river can make the river sides/around lake area cooler, with grass etc
Bevy, Bevy, Bevy, Bevy!
😅🤔🧐 Crazy, funny, informative and well produced. Great stuff!
you should use a space hashmap with a simple voronoi algorithm to determine which biome the block at x, z is in.
Are you aware that Veloren is written in rust and is also heavily inspired by cube world?
Yes absolutely! I've talked to some of the devs on Veloren, really nice people!
Instead of learning how to work with some plugin on a popular engine, you just created your own engine. True Chad
New Tantan video jeah! 👍
Looks good! Keep it up 👍
Love vowels, learning Rust... Awesome... no... Perfect!
Based on the graph at 5:09, I would make low temp high humidity a mountain instead of two snows.
oh good idea!
@@Tantandev thx, I also thought that the more jungle (high temp+humidity) surrounds it the more likely that it's a volcano.
@@Tantandev yes, think something like the Gobi desert or the colder parts of the Atacama desert. Mountainous, cold, and dry, not much snow.
Man please keep uploading. Your struggle is greater than mine but I've been tearing my hair out doing Qongzi's Minesweeper tut. The repo is different from his tut and I don't want to just git clone it and voila it works. I'm trying to learn Rust. I can print out the values I insert into my mutable HashMap that I pass into the mutating function but after it returns? Hashmap is empty.
I've been coming back to this code everyday trying to figure out WTH is going on and why a mutation is passing Rust's checks but it's coming out totally freaking empty.
So to see hear about your struggles is super cool man and I appreciate it! Growing pains
Wow thats some impressve progress! I didn't look into the code but I wonder if you could pregenerate a lot of the calculations needed for biome blending etc. ahead of time so they don't affect FPS that much.
I know one more trick. You can add some high-frequency noise to blend an it can make border nicer. Noise can be pre-baked.
Brilliant to see you come back to voxels and working on this game! Hearing about the modularisation of the game was great. Did you actually add any unit tests?
have you heard of veloren ?
maybe some sort of voronoi-like implementation could help streamline your biome blending process? if you're using 2d noise to instance your biomes, each voronoi cell represents the individual biome regions, and then you get clearly defined borders that you could apply some sort of special interpolation to... theoretically you'd end up with edges, could match on all possibly pairs of neighbors, and craft cases for each that optimize for both neighbors' features? no idea if this is helpful or even makes any sense lmao
I use a somewhat related process. I don't directly use Voronoi geometry, though, just the point distribution you might use with Voronoi. Scatter randomly placed points around the world such that they're never spread too far apart (e.g. a jittered grid -- like Voronoi noise usually uses). Sample the biome at each point (no blending yet). Then, for each block (or rather block column) in the world, loop over all sampling points within a certain radius of it. Use a smooth falloff curve e.g. max(0, R²-x²-y²)³ to contribute a weight to the biome it samples, then divide each biome's individual weight by the total weight so they all sum to 1. You can optimize this with various caching and range querying techniques (incl. querying all the points in range of the current chunk being generated).
hi. do you know about Veloren?
it is basically all you wanted
You coud maby look at the open source game Veloren how they did their bioms.( its also a voxel game made in rust)
Alright I'm gonna make Cube World too, though with more emphasis on food production than adventure
Stay awesome king!
Your Pop!_OS desktop is kinda dope 😎😎
Low temp low humidity should be tundra. How can there be snow if the humidity is low? The water comes from someplace.
jdh (eyes)
***makes a tetris os in rust***
Looks great! Have you seen the game Veloren? They also use a voxel engine in rust and it's open source.
I would use 3d noise for the booms than the blending would be automatic. With your integration every dessert looks the same and has the same hight.
What happened to the cool chunk loading animation? I thought that was very unique.
inspiring stuff as always
Block Bench 😍
Good job!
Hahaha it looks really cool...you make me a script guy want to do more in depth code haha. Kubernetes is my life hahaha.
what's the name of the code color theme that you're using in the video?
fn temperature(&self) -> f32 { -1.0 }
He did it bois, he broke thermodynamics
Nice!
While you might want to make it look and feel like cube world, please don't be like cube world and actually finish the game, I'm really hyped for your work!
Love your vids! I'm trying to build a 2D side scroller with ldtk and bevy currently. :)
Awesome video
@10:01 Excuse me but 0.003 is not 3%, it's 0.3% !
Yes
rust is cool
rust is more then a coding language, it’s a way of life
amazing !!
I fucking love rust. Your videos are motivating me even more to use it, but i just don't have ideas to use it for :(
this was so epic
You can do chunks like minecraft i think it will easier interpolate beetwaen two chunks
Jdh was mysteriously in the video
Have you thought about trying Wave Function Collapse for generation? What do you think of it?
That would depend on what kind of terrain he'd want, because wfc looks very different
WFC is a very interesting tool. One of the biggest holdups I would have to applying it to more natural-curvature-based terrain would be its strong preference for grid directions (moreso even than certain noise generators which I covered in another comment). I think translating the idea to randomly scattered points (Poisson, or at least jittered grid with the neighbor relationships recomputed), though, would make for some quite useful and visually appealing results when combined with the right rulesets and pre/post-processing steps.
So, you are refactoring so you won't have to refactor? :D
3:29 Caa ont road
Anyone else spot the jdh discord msg at 10:35!!! Two of my favourite creators rly want a Collab!!!!
Are you using Bevy's rendering plugins, or is everything done manually by using wgpu and OpenGL?
I'm using bevy's rendering plugin, but I've made most of it from scratch with wgpu. If you want to do more custom rendering things in bevy, you need to write some wgpu code.
@@Tantandev Thanks for the reply!
Looks awesome! Rust = best programming language
Awesome!
10:38 hey jdh
Do you read the comments ?
Paul Walker?
poggers ya feel me
nice ;D
just an idea that compliments tons of dull work and content creation - try streaming :)
you don't have to edit a whole week of footage, you just get angry at maths and it's good entertainment
Nice.
When I switched to pop os I saw a 2x increase in fps in Minecraft too 😂👍
rust is so badass. I... ARGHH!!!
when did johnny depp learn rust
My lawyer calls for heresy!
Don't know nothin about Rust, but if ya ever wanna get into Roblox Lua, i gotchu
Bicubic interpolation could work
Threads on windows are shitty and take like 10x longer to spin up on windows vs linux. You should create a pool of threads up front and assign work to these threads to handle rendering. I'd bet that's where your slowdown is on windows.
Oh also, windows sucks.
Good
8:54 way easier, its just the second order derivative. through a laplacian and there you are. just kidding, that problem is not easy.
monkee rust brain = make modular code 🐵👍
10:39 I spy jdh