Very interesting that you used "x,z" as a key for the chunks, personally the first time I wrote a voxel engine I used a set of equations to convert a 2d vector into an integer used to represent chunks, it was a real headache to make a system which allowed for convertion between an integer and a 2d vector. In my defense it did save memory by allowing me to use normal arrays instead of dictionaries, which was important since I was developing in WebGL and JavaScript is wayyy slower than traditional languages, but your way is far easier, and I doubt it will have too much impact on performance given this is an engine optimized for these kinds of things. Regardless thank you for the tutorial! It was really helpful for someone like be who's never used Godot before.
Your channel is awesome, I also created an infinite terrain system for Unreal with LOD system and everything, but, Unreal has so many bugs that i decided to drop it and switch to Godot, it's so much more powerful.
I could never figure out how to procedurally generate a mesh in unreal. Every other engine it's easy, but it seems like they really don't want you to do that because all the lighting is pre baked. Is your code online anywhere? Any examples you know of? I swear I looked everywhere. I'll probably still use Godot, but I just have to know, it's been bugging me for a long time.
Great tutorial! Thanks for making the font bigger and going through each step. This is very helpful to learn. I plan to implement this in gd native and see how much faster it is. LOD next would be an interesting addition for the next tutorial. It won't matter on low poly, but if you increase the view distance and chunk resolution it would.
been trying that the whole weekend... but it seems gdnative has issues with nodes instantiated from gdnative. would be nice to know if you got it working somehow.
IMPORTANT: For whatever reason the game might crash when generating the terrain before the water. So in the chunk.gd, in the _ready function, start by calling the generate_water() and then generate_chunk()! If someone knows why this is happening, feel free too comment! :) Thanks @whoknowsyoubetter for pointing that out!
Hey AMAZING TUTORIAL But I have 2 questions [1] How do I make the height of the generation a bit lower because I would like flatter generation [2] How do I make trees or structures?
@@lionlight9514 in the chunk script line 40 or around "vertex.y = noise.get_noise_3d(vertex.x + x, vertex.y, vertex.z +z) * 80" just put something lower than 80 and its flatter
Thank you for another great tutorial! Exactly what I was after for my current project. I noticed you've not posted anything for a few months so hope you are well!
Planing to use this concept to generate full planets. Similar to the other project you posted, except I'm planning to make them a lot more high-poly with detailed shaders as well as allowing the player to walk on and around them. Should have the base concept handled... more worried about calculating the sky and sunlight settings based on view position / angle lol
what if my map is not infinite and I just want to generate all the chunks over time without having to regenerate them? Can I simply add all chunks as children and hide them when far from the player? I'm not worried about memory. I'm only worried that these hidden chunks may still cause some slowdown.
I'm uncertain about the safety of this threading approach - it doesn't allow one chunk to start being added while another is still being processed, which is good, but it just drops the attempt instead of queuing it up if one is still in-progress, with an end result that I don't think it can generate more than one chunk per _process call. And looks like it's possible to start adding another chunk after load_chunk has finished, but before load_done has completed, in which case the wait in the load_done from the first chunk would end up waiting for the second call to load_chunk to complete? Not sure of the results, if that happens.
I liked the tutorial, I followed it exactly and watched it twice, but the terrain never appears. Does anyone have a sample they can share? I must be making some minor logical mistake somewhere!
@@redeyeblues3723 He contacted me on discord. And hes problem was his _ready function, he misspelled it. So its very hard for me to isolate ur problem :/
*Many questions.* ... I'll ask one for now. Is there a particular reason you are sampling noise using a 3D _input_ vector? I have this tut figured out, and my own code is working, but I've settled on using the method "get_noise_2d" to sample the noise for setting the terrain verts Y axis. Since one only needs an X and Z to get OpenSimplex (or anything like perlin noise) to reliably produce samples that are continuous over the field, this seems like the more correct way to go about the task.
Hey dude, I am getting this problem where instead of the sand grass and water just divide throughout the map the materials just overlays one to another
Great tutorial! Thanks you. I have one question : I have no experience with threads in godot, but shouldn't you use mutexes for the dictionaries, since you read and write to them in different threads?
I did a quick check and it looks like adding, resizing, and removing is not thread safe. Writing to existing entries may be fine. docs.godotengine.org/en/3.1/tutorials/threads/thread_safe_apis.html
this is amazing. Could you do a video that is the most stripped back version possible -- like just a basic plain object (the one in blender) repeating? that would probably get an insane amount of views, if you made the defacto godot 3d plain repeating video tutorial. but that's also a specific request so i get it if not
Hey AMAZING TUTORIAL But I have 2 questions [1] How do I make the height of the generation a bit lower because I would like flatter generation [2] How do I make trees or structures?
you can change the noise.period and noise.octaves attributes to change the terrain properties, also the noise multiplier in the Chunk class, in the video he puts a constant of value 80
at 17 minutes when you tested it for the first time, mines broken. I wish you tested it after each code to show what each part is adding, and put the scripts online so we can compare.
oooooooooooooooooooooooooo this is so cool... everything works fine, just it doesn't works smooth as intended. Do you guys know why changing chunk_count the frame rate drops? As far as I understand secondary threads should manage everything leaving the main thread free to fly, but it works only with a certain ammout of chunks.
Did anyone found a more performant solution? I'm not used to multithreading but I did add new threads and it did not get much better, what if it was in C#?
All I get is a single tile being generated, did you paste in some code during some sped up segment that I might have missed? This is why I think it's good to have finished code to check against, as books usually include. I mean as I move around others are spawned, but I see them spawn for you even when you are stationary in a grid like fashion, I just get the central one.
No. I think its all there.. ull have to either do some debugging or rewatch the vid. Are the chunks being generated from the thread? If so, do they get added to the scene? If so, on the right position... and so on :)
@@codat3821 Derp, I found my issue. Last night tiredly I must have missed that I added the division by chunk_size inside of the int casting in the chunk updating method. ;p
The Terrain doesn't load in my case. The only error i get is this: E 0:00:00.543 _create_instance: Condition "r_error.error != Variant::CallError::CALL_OK" is true. Returned: __null modules/gdscript/gdscript.cpp:127 @ _create_instance() Does anyone has an idea what's the problem?
While trying to run it for the first time while at about the 20 minute mark in the video I received 2 errors. E 0:00:01:0926 Node not found: Rotation_Helper/Camera scene/main/node.cpp:1382 @ get_node() Player.gd:19 @ _ready() which when clicks takes me to line 19 of the player script and E 0:00:01:0928 Node not found: Rotation_Helper scene/main/node.cpp:1382 @ get_node() Player.gd:20 @ _ready()
very good, however there is an error always popping up on vertex.y = noise.get_noise_3d(vertex.X + x, vertex.y, vertex.z + z) * 80 where it says that all vertexes are not in the current scope?
Hey, awesome tutorial! Just a quick question, for whatever reason when I added water and run the project, the script would try to free main World node when the loading thread would start generating the chunk directly under the camera. Commenting out either generate_water() or generate_chunk() in chunk.gd prevents it from crashing. The error is: Attempt to call function 'add_chunk' in base 'previously freed instance' on a null instance.
@@whoknowsyoubetter well i also encountered that problem when i fooled around a little.. but as u said, generating the water first solves the problem. Thank u dude! :)
I experience this often in another Godot project. Maybe it has to do with threading and something is getting called before it is loaded, but only sometimes.
@@TokisanGames I get errors like this every time I try to implement threading. Not sure what I'm doing either because I'm not doing anything that should cause that. Let us know if you figure it out
Some questions: How do you layer additional 3D noise when it comes to modifying the geometry? An idea I have for procedural planets is the closer you get, the more subdivided the areas of the planet are, and another layer of noise modifies the geometry of the land more, giving the landscape more realism. And the closer you get, the more subdivided it gets, and another layer of noise further modifies the geometry. Ultimately, the closer you get, the more detailed that area you are looking at becomes. And as you move further away, the reverse happens: things get simplified the further away you get. In order to create life sized planets this process is probably going to be necessary. Another thing that is important is being able to give some degree of randomness to the colors of the landscape. I want to be able to use noise to give variety to the greens.
This was really great, thanks! Question though: After the player moves in one direction and the chunks behind them are removed in the clean up function, what if the player turns around and goes back to that same area? Wouldn't your code generate brand new terrain in those previously visited areas?
Steve Blair yes when the player moves back or anywhere else, the chunks are generated. Thata the whole point, otherwise you would run out of memory at some point.:)
@@codat3821 Right, that makes sense. I was thinking it would be nice to store those chunks to reload them when the player goes back, but with an infinite amount of chunks, that could go pretty badly
@@codat3821 If you can't have saved chunks, then what's the point really. You've made an awesome video showcasing how to essentially make minecraft in godot. Going back to previous chunks where u f.ex have made a structure would be awesome. If not this would only be useful in an exploration game where backpedaling isnt nessesary
Chunks are not generated randomly, he uses a noise map to generate them. The terrain information is kept in the noise map and the visited chunks will be always generated according to it.
You can still save stuff. Say you dropped some loot in an area and went back to it later. All you would have to do is store the external objects somewhere, and replace them based on their transition properties once the chunk is regenerated. Save the key of the chunk they belong to, and check keys for "lost items" whenever you generate a new chunk. Not hard at all.
Pretty good. There are other performance improvement can you recommend? Does it even heavy on the cpu? Edit: you wrote in 5:15 there is a link in the desc, but you forgot to add it :D
U can absolutly improve performance.. from the top of my head u can first try to avoid type casting (as we do in the keys in the dicts). U can also change the worldscript to not update the chunks every frame and instead only update the chunks whenever the player enters a new chunk in the grid.. :) Thank u for pointing the descriptions thingi!! :)
@@codat3821 Hi! just as a follow up question to this, is there any reason you know of why we couldn't just use a Vector2 for the keys instead of type casting? would that be better performance-wise?
hmm nice i do want a limited world size tho quite big ill have to find that out now.. also i need to find out how to generate more island like lands instead of these tiny mountain islands
Hello, have you found this? I tried it and chunks do not load, but maybe you could use several seeds: one for each type of object, not depending on randomize and randi or randf function. I will try this today
Very cool tutorial! Although, I have a question. When you go far away from a chunk and it unloads, when you come back, does that chunk look the same? If so, why? Is that information stored somewhere or is it just generated again?
Hi dude. The only information stored is the data from the noise map. and yes, it will look the same once u revisit it. though all chunks are regenereated. :)
This is a really great tutorial, but I think I messed up on the chunk generation and my computer nearly burned itself out trying to generate terrain. Is there a better way to force a hard limit on generation so it doesn't overflow?
Simply a different process running in prallel with the main one. Makes it possible to do multiple things the same time. As we do here, play the game while loading new chunks. Without threads, loading s chunk would make the game unplayable :)