- Home /
Voxel-Grid rounded Marching Cube values for a sphere
Hey Guys, I'm currently trying to create a planet using the marching cubes algorithm, but I don't really understand the density value! If I set the density value for every point in the sphere to 1, I get a blocky sphere. How can I calculate the right density values to get a round sphere?
Here's my current code to fill the voxel grid:
public void generatePlanet() {
for (int x=0; x<planetDiameter; x++) {
for (int y=0; y<planetDiameter; y++) {
for (int z=0; z<planetDiameter; z++) {
Vector3 pos = new Vector3(x,y,z);
float distance = Vector3.Distance(pos, center);
if (distance <= planetRadius) {
if (distance >= planetRadius -1) {
map[x,y,z] = ??
}else {
map[x,y,z] = 1;
}
}else {
map[x,y,z] = 0;
}
}
}
}
}
Thanks in advance!
Answer by Blackup · Jul 10, 2019 at 05:36 PM
@yxyx136 Posting for future devs to find....
[This solution assumes you are using a conventional weight based voxel grid intended for generating a mesh topology using marching cubes]
With Marching cubes, you have to set "density" on each point of the grid.
In my case that values for density range from - 1 to 1.
0 is the point where things turn from empty, to solid...
in other words... if two points are at the extremes of -1 and 1, then the vertice for the mesh will appear exactly between them.
This is why, if you only assign absolute solid and empty values, your sphere will show up as "blocky" with either straight or 45 degree angles,
So... the value of density has to alternate as a decimal value, on both the positive and negative side of the sphere radius. This will slide the vertice between the points on the grid. Calculaiting those decimal weight values might seem tricky... but fortunately, doing this for a sphere is actually relatively easy. Here is how...
For each point in the grid, check the following.
If the distance to the point is less than the sphere radius then
Density = Mathf.Min(1.0f, (radius - distance) / girdBlockSize);
This applies a variance to the density based on the distance to the sphere surface. "(radius - distance) / girdBlockSize" means that within a threshold of one grid block size, the value will alternate between 0 and 1. If the distance is much smaller than the threshold then we assume it is a full density of 1.
That takes care of the value beneath the surface... but we must do the same with the values outside the surface.
(Remember that the vertices of your mesh will be placed on a point between the solid and empty weights on your voxel grid...) We need the vary the outer weights the same way (only this time it will be negative)
so... if the distance to your voxel grid point is BIGGER than the radius then
Density = Mathf.Max(-1.0f, -(distance- radius) / girdBlockSize);
As you might have guessed, we are using a threshold again for one grid block size.
Any points within that threshold will vary between -1 and 0 depending on it's distance from the surface of the sphere.
With these positive and negative variances on the voxel grid points, your mesh will interpolate correctly and create a perfect sphere.
Going forward, you and add further adjustments to the weights to create noise and turbulence.
I hope this helps new Developers that stumble across this challenge in the future.