Open Anders333 opened 4 years ago
Try set_voxel_f
Thx! Now i see some vertical little offset.
Looks like need a lot of work on correct voxel position for smooth terrain, coz default height from image is not enough.
To obtain smooth terrain you need a distance field value to put in set_voxel_f
, which should vary slow enough to be sampled properly, which is why it is often scaled to adjust it (if it varies too fast the value will clip to -1 or 1 and rarely in between, causing blocky result).
Is there still something you need help on about that subject or is the issue about set_voxel
solved?
To obtain smooth terrain you need a distance field value to put in
set_voxel_f
, which should vary slow enough to be sampled properly, which is why it is often scaled to adjust it (if it varies too fast the value will clip to -1 or 1 and rarely in between, causing blocky result).Is there still something you need help on about that subject or is the issue about
set_voxel
solved? Thx, as i understand, set float to zero makes level of voxes as we see in data? In case set just int at height 1 we receive height on 0.5.But when i set float 0.0 on the top of previos voxel, i have result height of terrain on 1.0. But I have a little problem. I set float value to voxel, and they show me unexpected result:So what i see, -1.0 give me expected result : +0.5 in height , but 0.5 looks like +0.34(not +0.25), and 0.25 like +0.16 (not +0.125)
Ok, this ended up as a long one but here is the explanation:
The SDF value to store in the grid is not an actual distance directly corresponding to what you see in the world. It is a normalized value between -1 and 1. However, by ratio, it should correspond to the degree of "filling" of a cell.
Also, smooth voxels use interpolation to be smooth. Because of this, if you set a single voxel of matter in the middle of the air at (x,y,z), it will appear as a diamond centered on that position, rather than the center of a cube that would go from (x,y,z) to (x+1, y+1, z+1).
So a value of
-1.0
means the voxel will indeed be of size 1, but centered. So 0.5 on each side, and here as a diamond because all neighbors are air (1.0).
Here with different SDF values:
Here a patch of 2x3 voxels with value 1.0:
And value 0.5:
Now if I measure it using a plane, at a height where the voxel would be if its growth was linear:
There is indeed a small divergence, which seems to follow a curve like this:
It can also be reproduced with the old smooth mesher (which was basically marching cubes from Ogre's dual marching cubes). Both were written from scratch and don't have any code in common.
Here is how Transvoxel interpolates two samples to determine a vertex position:
// p0 and p1 are integer positions of the two corners of the cube we are in
// sample0 and sample1 are -128..127 integer representations of the SDF at the corners
int ti0 = (sample1 << 8) / (sample1 - sample0);
int ti1 = 0x100 - ti0;
Vector3i primary = p0 * ti0 + p1 * ti1;
Vector3 primaryf = primary.to_vec3() * FIXED_FACTOR;
There you go, here is the curve ti1
follows, which controls how much of p1
the vertex will have:
Now, a practical explanation of this, is a direct consequence of what an isosurface actually is: The visible surface is the place where interpolated SDF values cross zero. If you chart this in 2D, that's how it looks like:
Now, take voxel 0
value, and increase it linearly... and you will notice the point where the line crosses 0 does not move linearly.
In fact, it will only move linearly if you increase both voxels up.
But, since voxels are sampled in normalized values, it's not possible to store values higher than 1, or lower than -1. In fact, having such values so close to the surface means they are clipping, and that can cause blockyness. This problem can be attenuated by multiplying your SDF by a small factor like 0.1, to exploit the sampling precision better, keeping the curve within -1..1. It will provide more headroom, while not changing the intersection point.
This is what improved heightmap generators a lot recently. They used to clip too early due to generating actual distances into voxel values, now they generate 1/10e of that https://github.com/Zylann/godot_voxel/issues/73#issuecomment-578526202
In general, don't try to set specific values with set_voxel_f
. Always use something akin to a distance, unless you aim for a specific look.
I ended up listing far more things than I intented, but I hope this helps.
Thanks for wide answer, now i see it is not simple. I planned to make editable terrain that can support flat regions with angles< 45 degrees. Looks like need to calculate some constant multiplier for that. But after terrain will generated, i need store data in another stream, like voxel_stream_file, coz i need to store caves and another modification of voxel terrain. Thx for that awesome tool!
I need create large terraind so i decided to create own voxel stream. But looks like out_buffer.set_voxel() does not care about first parameter as float. So when i put 0.5 or 1.0 as first parameter, height of voxel always the same. We can see that on screenshot below:
I didnt find way to set iso(sdf) parameter. Can i do smooth terrain with my own voxel stream logic?