- Home /
How to make a smooth voxel world
Hi, I'm a self taught programmer and highschooler who's been working on a project for a bit now and iv'e been stuck on something for a while, i want to generate smooth voxel terrain, but so far I could only make "minecrafty" blocky style terrain. iv'e done research on marching cubes and things like that but i just cant figure out how use it, i'm using a multidimensional array to place the cube voxels. now i need to figure out how to create smooth terrain out of it, then hopefully i can make a way to add and delete terrain from there. Any help would be amazing.
Answer by Zarenityx · Jul 31, 2018 at 08:17 PM
Marching Cubes is one of the simplest algorithms out there (actually it's simpler than even the face-testing minecraft-style system), but it trips a lot of people up because what you are doing is looping through corners, not blocks, and additionally there can be the concept of signed distance, which helps smooth out your terrain.
The basic idea is this:
-Each of your voxels has a distance value. 0 means it's on the surface of your terrain, negative means inside, positive means outside. Odds are, most of the points on your voxel grid will not be exactly 0.
-Instead of looping through the voxels themselves, imagine a grid that's offset by half a voxel, so each cell has 8 voxels, one for each corner.
-Each corner can either be inside (or on) or outside the terrain. The real surface of the terrain is somewhere in that cell, at the point where the density in between the voxels is 0.
-Each corner also has a value. These values are powers of two, so you have a corner for 1,2,4,8,16,32,64, and 128.
-If a corner is inside/on (negative/0) the surface, that value gets added. If it's outside (positive), it doesn't. Since each corner can only be either inside or outside, this is binary. There are 8 corners, so that's a byte. You might have a cell where the corners are OOOOIOII (O for outside, I for inside). This can be represented as 00001011 in binary, or the decimal number 11.
-As you can probably see, there are 256 possible cell types. Each one corresponds to a specific surface. For instance, 0 and 255 are empty, since they are completely outside or completely inside, but 1 has a single triangle.
-All of these surfaces are based on trying to find a surface that has a vertex for each edge where one side is inside and one side is outside. This table can be precomputed or hardcoded. This is the longest part of making marching cubes, but it isn't hard. There are also existing tables already that you can adapt.
-Loop through your array, taking 2x2x2 voxel sections and treating them as cells. Find the byte value of the cell based on which voxels are inside and which are out.
-This byte value is the index to the array you precomputed earlier. Use it to get the mesh data (if any) that you should add to the chunk's mesh.
-For real smoothness, move the vertices along their edges corresponding to the distance of the voxels at the corners. A vertex between a -0.25 and 0.75, for instance, would be placed 0.25m away from the inside voxel (and 0.75 away from the outside one).
Also, I'm almost certain you've seen This paper, but it's a really good description of how it works. This video is a great visual example as well, and you could probably get an idea of how to make this just by watching it enough times.
I'm also a self-taught coder who started in elementary school so I get the feeling of wanting to make stuff like this but having getting really stuck at the implementation. So much of the literature has a higher barrier to understanding than it reasonably should.
Anyways, I wish you the best of luck on this project! Voxels are a whole lot of fun...
(Also, once you get this concept down in C#, check out this awesome magical spell that can work with voxels (and other stuff) really fast.
Answer by GPxKiller · Jul 24, 2019 at 07:16 PM
Hello @Zarenityx ,
What s the way to go for having voxel with values between -1 and 1. Why do we must loop with 2x2x2 voxels grid?
thx
The page linked to in the other answer (http://paulbourke.net/geometry/polygonise/) holds the key to understanding why one uses a 2x2x2 cube to generate the isosurfaces. See Figure 2 and 3. You can use -1 and 1 for voxel values, if you use an isovalue of 0. Or, you can use 0 and 1 for voxel values, if you use an isovalue of 0.5.
Any locations with a value less than the isovalue are inside of the isosurface, and any locations with a value greater than the isovalue are outside of the surface.
Any further questions?
Thank you for the answer, Yeah i got some more question =) If i m generating a height map id a 2d table values between 0 and 255 and i want water at 64 normal suface of the world can i switch heightmap values between 0 and 1 and tell that surface is 0.25?
Another thing i still don t understand why blocks inside or outside got values that are not 0 and 1.
Let s take an exemple below: it's look like that i can not send my pic =(
Anyway the exemple i take its imagine in gat a voxels pile of 5 by height and one by with can i make value of two voxel of the bottom at 0 to say that they are not render make a value of 0.39 at the third and value of 1 for the higher voxels?
The thing that i don t understand is how to generate data and what does $$anonymous$$ a value of .75f if surface is .25f
If you got a moment let me know your discord to chat with you you seam really understand this algo
If you're generating a height map, $$anonymous$$arching Cubes is not necessary.
I don't really understand the rest of your question.
$$anonymous$$y Discord handle is sjhalayka