Coding Adventure: TerraformingJun 02, 2021
hi everyone welcome back to another episode of
adventures making planets in the past i have always taken the approach of starting with a sphere and then sampling a 3d noise function at each point and stretching those points in or out at function of that noise value by mixing and superimposing different noise functions and experimenting with different equations, we can get some pretty interesting results, but this approach has a limitation: each point can only have one height associated with it, which of course means that there is no caves, tunnels or overhangs of any kind. This is the approach.
I went with him when he was playing with this little project inspired by the wild outside and while it's nice to take a ride on a moon made of math, it's kind of sad to know that there's no chance of finding a lava tube to explore, for example. , or dig your own. little cave for shelter so in this video i want to try and create a little planet and
terraformingtool so i can make caves and tunnels and shape t the terrain to my heart's content as a starting point. I am going to use an old project of mine where after some difficulties I managed to implement an algorithm called marching cubes.
I have a whole video on that, but the basic idea is this: we take eight points at the corners of some imaginary cube and each of these points has a random value associated with it from our noise function values above zero mean that those points are in open space I like to think of them as air points whereas when the value is below zero those are rock points because they are inside the planet between the air and the rock is where we want to draw the surface mesh of our planet now with eight points there are 256 possible configurations but it's really only 15 unique cases and the rest are just various symmetries of those and as you can see these surfaces are built with triangles because computers love to draw triangles so to make our planet we will have a 3D grid of values classified as air or rock and it will match across that space cube by cube building the mesh d e surface for each as we go along.
The algorithm for this running cube was published in 1987 for the purpose of visualizing the results of medical scans, but it's also perfect for games i'll show the code for this quickly for anyone who might be curious, so most of it is really just one giant table describing how to connect the triangles for each of those 256 configurations I mentioned and I'll be forever grateful I didn't. to figure this out myself because there are a lot of numbers at the core of the algorithm though i wrote in something called hlsl and that allows a lot of cubes to be processed in parallel on the gpu here we start by calculating the coordinates of the eight corners of the current cube and then here we search each of its values and we use it to determine which of the 256 configurations this cube is in, then from that giant table we can figure out which edges of the cube th The surface that passes through these edges is arranged in groups of three and we need connecting them to form the triangles, so I have these two little arrangements that allow us to take one edge and find the two points at each end. we do that here for each of our three edges, finally we need to decide where we want to place the vertices along each edge and for now I've put them all at the midpoints so let's do something with this.
I have written this little script. that just calculates the values for a sphere and stores them in a 3D texture. I want to take a quick look at the portions of that texture just to make sure it's working correctly. These lighter regions are off the surface. Everything drawn in black is below the surface and the red line shows the boundary between the two so where the value is zero I thought it looked good so if I tell the corresponding cube script to get your data from this texture we should end up with a beautiful 3d sphere and here it is is a very blo However the sphere looks weird and while the blocking isn't necessarily bad I'd like to smooth it out a bit so instead of placing each vertex at the midpoint of an edge, let's make a little function called calculate vertex position and what that function will do is look at the value of both points that have been given, one will be positive and the other will be negative and it will determine where it should be the zero along the edge and that's where the vertex will go that little change takes us from this to this which looks nice smooth so I'll quickly go back to where we're calculating those sphere values and let's try spraying some layers of noise on top this is what our 3d texture looks like now so let's once again use our matching cubes to build a mesh that looks like we're finally getting somewhere unfortunately with this technique we occasionally get random rocks floating in the air and while it should be possible to remove them with some kind of flood-fill algorithm, I suspect it would b The rather slow, much more practical, is just to shake it around with some mindless physics, so just for fun I thought I'd ask an ai to try and offer some explanations for this floating rock phenomenon.
Let's see what he was able to find. with airborne rocks because they are not dense enough to stay on the ground there is less gravitational pull on airborne rocks because they are high up and tend to float this phenomenon cannot be explained although some theories suggest it is a mirage caused by very hot sunbeams this is because the magnetic forces within the rock repel each other and push the rock up into the air and finally I was hit with some hard facts rocks don't float on air too they are. heavy for that anyway, clearly there are plenty of excuses for our rocks to float, so let's tag this as a feature and move on to the more pressing concern that this terrain mesh is already using over a million vertices, many of them probably they are duplicates though ugh because i'm not sure how to share vertices between the cubes as i don't quite understand all this fancy parallel gpu stuff if i'm honest but since i need to read the mesh data back into the cpu anyway to generate the collision mesh we are now in c-sharp land so I can simply loop through all the vertices and remove duplicates using a dictionary which is surprisingly fast this has the side effect of smoothing out the shading which I really want for this project so that's ok and if I display the mesh information again it looks like we have reduced the vertex count to about 180 000.
From anyway i have now made a simple player controller that works for planets where the direction of gravity obviously depends on where you are standing, it has some issues at the moment but i am working on it now, my main goal here is an ability to
terraformingso I can click to tunnel, for example, but it would be pretty inefficient to regenerate the entire plan et every time a change is made I need to break it into parts. I've been working on the code for quite some time, so with much anticipation and trepidation I'm finally ready to try it out.
Well, I guess it goes without saying that that's not remotely what I had in mind, but it shouldn't be too hard to fix. That's still not quite right, but it looks like we're headed in the right direction. It just needs a few adjustments. I'm not sure how, but it looks like I've turned the planet into some kind of weird mushroom. I have an idea of what might be going wrong, great though. Now nothing happens. It seems that he was actually doing something. interesting monstrosity well i guess you could call that a greek ed programming showcase i need to take a break to come back to this the next day luckily i was able to track down the problem pretty quickly and get it working at last my bug as usual was pretty dumb but just in case anyone cares to know this is what happened on the c-sharp side of things unity provides two types of 3d vectors one for integers and one for floating point numbers i have a vector3 int with some data I wanted to send to my compute shader so I thought I'd just use this handy vector array function, but it complained that it didn't like the type of variable I was giving it and without really thinking I just turned it into a 3 vector normal like this and that made the wavy red line disappear, which of course is all I'm really trying to achieve when programming in the shader. dor.
I was using the equivalent of a 3 inch vector that there is an intri, so this is what was happening first. I have some data. stored in a vector3 inches and in binary that data looks like this then I send it to a normal vector3 so that annoying error goes away and even though it's the same values in there the actual binary data of course looks quite different because now it's in floating point t but I hardly ever think about the raw binary data in my daily schedule so even though technically I knew these exact bits would end up on the gpu for my little chunk id variable which didn't trigger any alarms on my head now when you expected a value of 22 for example you would actually get 1 102 53 376 which as you saw resulted in some problems the solution to all of this by the way was to just use the correct function for the job which is not set to vector as the error message was trying to hint at, but setting up the schedule can be a joy sometimes anyway with those snippets in place.
I've been working on terraforming a bit. of the player to see where it hits the surface and in a little sphere around that point, then I add or subtract values from the map depending on whether the left or right mouse button is held down and then of course any affected parts need to be regenerated the performance is still not that great with the main bottleneck i think i'm reading the data from the gpu back to the cpu to build the collision mesh if i take this experiment much further i'll definitely need to address that but a more pressing concern is that if I try to terraform with my feet I immediately plummet across the surface into the depths, so I've added some extra checks to the player controller for when nearby terrain is modified and it's still a bit wonky , but it is definitely a step forward.
The thing that bothers me the most right now is how boring the planet is to look at, so the first thing I'm going to do to try to liven it up a bit is to generate a sphere to act as a simple ocean layer. moment, so it's going to need some work. I'll start by figuring out how far we're looking through the water to the ground below and we can do this using the camera depth texture which tells us how far away from the camera each pixel is. the screen is the water i has not been included here because it uses a transparent shader and only solid geometry is included so in the water shader we can take the depth value of the current pixel and subtract the distance to the water pixel we are currently drawing and that allows us to visualize the distance we're looking through the water what we can do now is take that value and use it to blend between a shallow color and a deep color like this and this is what it looks like it already looks a lot better.
However, I think the water is still completely opaque, so I've been tinkering with the code a bit to make it more transparent when viewed from a steeper angle and also to make it quite transparent in shallow regions like what along the coast. maybe you made it a bit too clear now, but you can always tweak it later. I'd like to make the sunlight reflect off the water, so I'll use this code for my old video of the planet to calculate a specular glow. It's a bit intense. in t At the moment I'll bring it down to something more reasonable I think I'd like it to be more stylized so instead of letting the intensity fade smoothly I'll break it up into three bands with this bit of code and that takes us from this to this looks a bit strange because obviously the water shouldn't be so flat as to give us such a perfectly round highlight so I'll try panning a normal map like this across the surface to fake some little ripples if I increase the influence of that normal map we should see it start to break up the reflected light quite nicely these fake ripples only affect the light so i want to add some bigger ripples that actually move the vertices of the mesh i have been playing with the vertex shader for a I've been playing with sine waves for a long time, but if anyone knows a good approach to handling waves on a sphere, I'd love to hear it because what I ended up with here looks pretty ridiculous, oh Though if I climb down like this they do at least do a good job of breaking up that perfectly spherical outline the ocean had before itlast thing i want to add to the water for now is some simple lines of foam around the shoreline but for that we need to know how far the shoreline is remember this 3d map texture we have this actually gives a good approximation of how far is the closest surface of any point in space, the values are not literally distances because they change at different speeds in different places, but if we visualize them on the surface of the water we can see that the darker values are all over the show, for so we can easily isolate a small band like this.
I then played around with it for a while applying sine waves that move over time and breaking them up with some noise until I eventually stumbled upon a result that I was at least reasonably happy with. I'm a little hesitant to show the code for this because it's a real mess. I wrote this the other day and I have no idea what half of these numbers are anymore. I'm supposed to do it anyway, I'm just going to play around with this a bit and try to figure out where to go from here. I also wanted to show the weird looking results I got when I accidentally increased the resolution of my water mesh beyond what it allows the default mesh settings, but that was easy to fix with this line of code.
I think what I will do next. is to add an atmosphere to the planet, luckily I've already made a project and video detailing that exact subject, so I can drag and drop the files from there, only problem is that the atmosphere is eating the water. and this goes back to the fact that the water is not included in the depth texture, but after some research I found that I could set up a second camera dedicated to drawing only the depth texture of the water, the two depth textures can simply be combine into one and now the atmosphere works so all we have to do is find a nice spot to have a picnic and watch the sunrise.
Something else I could probably add relatively easily are the clouds from another one of my old videos. This will take a bit more work because the planets weren't really designed with planets in mind, basically the clouds are contained within a big box in the sky, but I've been adjusting this to use a sort of spherical shadow at the moment, the The results are a little iffy but I feel like I'm heading in the right direction, maybe after a little more work I think it looks a lot better now, although if you look closely there's still a bit of weirdness, also the Performance is far from amazing, especially for dense cloud cover and ideally clouds. it needs to blend into the atmosphere so that at sunset for example it has a nice orange glow but my first attempt had little success i think instead of trying to bring these two shades together sometime in the future i'll work on a fresh version and improved of both that work well with each other, so for now the clouds are essentially stuck on top, so the lighting doesn't really work when it's not data.
I did reduce the detail of the clouds a bit to try and make them fit a little better with the rather low poly terrain looking at it, although I wonder if the clouds shouldn't have a completely different style, for example, I just remembered this old experiment looking at my hard drive, maybe something else along those lines. it might work anyway for now i just want to add some color to the terrain an idea i had was to go back to taking our stock 3d map and make a copy at first that is unaffected by terraforming then sampling that in the shader of the terrain we can find out if we are inside a tunnel that the player has carved and make it a different color.
Tunnels are usually pretty dark, so I've created something called a sticky light that you can cast to light up an area. also calculate the slope of the terrain essentially just taking the dot product of the direction from the center of the planet to the current pixel and the normal vector of that pixel, then we can do some simple coloring based on that slope value for example giving the flat regions a grassy green color and the steeper areas a rockier brown color i've also added some noise to the colors to give a bit of variety with that done we're going to take our intrepid little astronaut on a it's been a lot of fun working on this , but obviously there's still a big challenge left in terms of making the world really interesting to explore because it essentially looks the same right now wherever you go, that's something I might try to address in the future time will tell for now, I hope you enjoyed the video though and thanks for watching cheers well that's stuck in my head you
If you have any copyright issue, please Contact