3D World Generation #8: Floating Origins for Bigger Worlds (JavaScript/Three.js)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

Oh wow, this is super exciting! I am watching your videos now. I look forward to more with great interest :)

👍︎︎ 8 👤︎︎ u/creampan 📅︎︎ Oct 07 2020 🗫︎ replies

really good content, suscribed !

👍︎︎ 3 👤︎︎ u/jjibe 📅︎︎ Oct 07 2020 🗫︎ replies

Space Engine somehow achieves it really well, since the scale is 1:1. Nice video!

👍︎︎ 3 👤︎︎ u/DeMooniC_ 📅︎︎ Oct 07 2020 🗫︎ replies

Subscribed!

👍︎︎ 2 👤︎︎ u/Smart_Doctor 📅︎︎ Oct 07 2020 🗫︎ replies

It's quite a lot of work to handle all the various scaling and precision issues with generating and rendering a planet sized object. I made a terrain viewer that's flat rather than a sphere, but allows unlimited panning and zooming. I had to implement both a floating origin and a custom integer block-based coordinate system to make it work. In the end I was able to set it up to move the camera at max speed for 8 hours overnight and in the morning the mesh and texturing still looked fine. I'm sure it's even more difficult for a spherical planet!

👍︎︎ 1 👤︎︎ u/fgennari 📅︎︎ Oct 08 2020 🗫︎ replies

It is exciting to see your discovery process in this video. I like that show fixes to your problems that you stumbled upon, but did not use. like the fixed arithmetic. Shows a more realistic process, than only the succes stories. I will definitely follow watch your other videos and follow your progression.

One question which might come to light watching your other videos, but ill ask it anyway:

Why do you use js for this project? Correct me if I am wrong, but aren't there more suited languages available for this? Or do you have any specific reasons, like web applicability for example?

👍︎︎ 1 👤︎︎ u/mootnaf 📅︎︎ Oct 08 2020 🗫︎ replies

Awesome. Maybe this wont be usefull for me right now, but the knowledge its always welcome

👍︎︎ 1 👤︎︎ u/Mediocre-Performer-1 📅︎︎ Oct 08 2020 🗫︎ replies
Captions
in this project we'll look at what happens when you try to scale the small world we've been building into gigantic earth and beyond size planets specifically we'll be covering using floating origins to build even bigger procedural worlds the problem we're trying to solve is what happens when i take my dinky little world that i've been building up until now and try to jack it up to earth sized and beyond the answer it looks like crap so today we're going to be exploring why it looks like crap and how to start fixing those issues now just to recap we've been building out a series on 3d world generation and procedural terrain in javascript and 3js there's an entire series to catch up on if you haven't already starting with basic mesh generation using height maps planetary scale level of detail advanced texturing techniques and approaches to threading it might seem that we're pretty much done now with the whole planet generation thing time to go make no man's sky or maybe not the reality is is the planets that we're building so far have been more like dinky little asteroids and moon sized ones so how do we build something bigger before we begin make sure you've subscribed to this channel and on twitter so that you're notified when new videos are released and you can also get previews of what's coming up so then how do we make this significantly bigger easy we just go back into the code here and there's a constant up here in terrain.js for a planetary radius right now it's set to about 4000 meters or so let's jack it up by adding a bunch of zeros obviously since you're watching a video about why and how to fix this just cranking the number up is going to fail so we'll load it up and at first glance this seems to be working out planet is goddamn huge now we really have to crank the camera speed to get in but as we zoom down to the planet's surface we start seeing some major problems going right up to the ground now this is probably about as low as you'd go to place a character down and this looks like garbage the ground is shaking and shimmering and just going nuts so what went wrong let's take a step back and refactor the code a bit before diving in since we're going to be playing with the planetary radius often let's move some of the variables that are scattered throughout the code specifically i'm talking about the constants declared at the top of terrain.js the ones hardcoded into graphics.js and the top of texturesplatter.js the problem is every time we want to go change save the height of the terrain or the size of the planet we have to remember to go screw around in multiple places instead we'll create this terrainconstant.js file and just cram everything in here now if we want to go change the terrain height it's super easy just change it here now we can load it up and see the change i can go back in here change the radius of the planet from 4000 to 8000 and voila again it's all good even the scattering implementation picks up the changes alright with that out of the way let's go back to figuring out why this looks so bad let's check the size of the planet back up now we'll wait for it to load and let's move around a bit first thing you'll notice is the texturing seems off but switching to wireframe you can see that it's not just the textures as i pan the camera around slowly look at the mesh the triangles themselves are jiggling around and going a bit crazy keep in mind that i'm not moving the camera at this point so there's no recalculation of the mesh happening to understand what's going on we need to take a step back and understand the representation of numbers in a computer all of our meshes are using floating point numbers floating point numbers are fantastic tools in programming they're super useful at representing things like positions directions texture coordinates but they do have their limitations understanding these weaknesses is the key to fixing this problem let's look at how a floating point number is defined a 32-bit float consists of a sine bit eight bits of exponent and 23 bits of mantissa or in other words the fractional part the problem is with the mantissa or the fractional component there's only 23 bits of precision there which in general means that you get roughly six to seven digits of numerical precision let's run through some quick examples say i have the number 10 so the corresponding float looks like this which means basically it's 2 to the power 3 times 1.25 which equals 10. now let's do 10.001 this is a little bit more complicated that number isn't perfectly represented by a floating point number so this ends up being 2 to the power 3 times 1.250125 etc and notice that it's not exactly 10.001 it's actually 10.0010004 and a bunch of crap this is an important point floating point numbers just try to get you as close as they can so now let's watch this fail really hard and fast when working with positions let's start with a position let's say that you're at 10.0 on the x-axis now in floating point if you recall everything is fine and you get 10.08 exactly if i move a millimeter that's going to be 10.001 and a bunch of crap so close enough that's fine so far everything is good enough for a game we're off by like a millionth who cares but now let's scale that up to planetary numbers so the new x coordinate is now one hundred thousand remember when i said they only had about six to seven digits of precision that means if you add .001 or one millimeter to a hundred thousand in floating point you end up with a hundred thousand you completely lose the point zero zero one because there just isn't enough precision to handle it you might be thinking but javascript has 64-bit floats not 32-bit yes javascript does but the bottleneck here is the gpu not the cpu and we're dealing with 32-bit floats there and using doubles everywhere also doesn't fundamentally fix the problem it's just a duct tape solution let's talk about some strategies to fix this one super common approach is using fixed point numbers these are basically integers that you treat as if they have a fixed fractional component they're amazing for reliability but that's a deep change to the code to support this instead let's go back to that original example of 10.0 notice how near the origin adding all these small numbers works fine near the origin doing calculations is going to easily give you sub millimeter accuracy but the further you move away the worse the accuracy is so i'm going to make a big jump here what this means is if instead of calculating our meshes and world as if they're at some static point in space we calculate everything relative to the position of the camera this is called having a floating origin and the gist of the approach we'll use today is that when we go to generate a chunk of train let's say the camera is here at position xyz which is super super far away from the origin if we were to generate the mesh in absolute coordinates at this point it's going to be a mess because of precision issues instead we'll treat the camera as the origin and move the world around it instead so we'll be generating the mesh right by the camera and then as the camera moves we'll actually just offset that chunk of terrain in the opposite direction in the end it comes out to exactly the same thing visually but it allows everything close to the camera to use small numbers that can be represented more precisely by floating point numbers let's get this all into code the first thing we need to do is go modify the worker code to generate meshes relative to a new origin all the mesh generation code is done here in the terrain builder threaded worker.js file we get a message down here from the main thread that tells us to build mesh and this rebuild function takes care of generating all of the new positions normals that kind of stuff there's also a bunch of parameters here that are passed down from the terrain class stuff like the local the world matrix the mesh resolution radius of the planet etc we'll just add a new parameter called origin and this will be the origin that will build the particular chunk of terrain relative to after that it's a few simple changes to the position generation previously we used to generate all of the mesh coordinates in a local space and then rely on setting a group transform to move them to the right world space position that's nice and simple but it's also part of the problem so back here in the terrain class we're not going to set the group's transform anymore we'll be generating the mesh and transforming it ourselves now in the loop down here we take the position and apply the local the world matrix to move it into world space and then subtract the origin here this effectively brings the positions back close to the origin since we pass the origin through the parameters we have to actually go back and thread this through these parameters are passed from terrain builder threaded so here in rebuild chunk we've got all the parameters being packaged up for the worker most of these are actually passed through from above so we'll add the origin here on this line and then we need to go up a level in terrain.js there's a function here in create terrain chunk which is responsible for calling the builder to create new terrain chunks and it's here that we can add the new origin parameter all we need to do is pass in the current camera position now remember how all of the world geometry is generated relative to the camera that means we need to render as if the camera is centered at the origin so in terrain shader we need to modify the view matrix specifically we'll need to create a new terrain camera matrix that will be mostly a copy of the current view matrix but set at the origin there's one last little change that we need to do here and that's in terrain chunk.js we need to set the position of each chunk relative to the current camera taking into account the origin if you remember our drawing each chunk was generated around the origin and as the camera moves we need to calculate the delta between the terrain's origin point and the current camera position what that means is we'll need an update function here in the terrain chunk class and we'll just subtract the current camera position from the origin and set that as the position for this chunk and that's it just some relatively painless changes and once we load it up the train isn't all jittery anymore we can zoom in and out now and there's no catastrophic issues with the mesh now obviously this isn't the only hurdle we need to fix the train still looks like garbage since the texturing follows the camera around since the position is local to the camera i think we can fix that in the future more easily by passing down some repeating world space coordinates or something like that the seams are still there in the terrain yeah i'll fix those at some point they just need a skirt or something to fix those and if we zoom out far enough well first off the planet doesn't really look like a planet now does it it looks like a splotchy green and brown thing but even just ignoring that if we go far enough this happens kind of looks like it's really hairy or it's on fire or something i don't know anyway we've hit the limits of the far clipping plane so we need to do something about that too baby steps we'll get there eventually next video in the series will address more of these issues hope you enjoyed this if you haven't already subscribe both here and on twitter you'll get notifications for when new videos drop and previews of what's coming up soon i also chat with people and try to get a sense of what you want to see next make sure to like the video and leave a comment about what you want to see covered in a future tutorial the code is all up on github so knock yourself out like always do whatever you want it's free to use if you don't understand something feel free to ask cheers everyone
Info
Channel: SimonDev
Views: 11,464
Rating: 4.9859896 out of 5
Keywords: simondev, game development, programming tutorial, threejs, threejs tutorial, 3d world generation, javascript, javascript tutorial
Id: qYdcynW94vM
Channel Id: undefined
Length: 12min 6sec (726 seconds)
Published: Mon Oct 05 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.