Closed SummitCollie closed 1 year ago
the docs and sample projects seem to be lacking examples of how to make a generator for SDF VoxelLodTerrain
There is indeed no copypastable example, but you can get close to this. Smooth terrain is based on signed distance fields. The doc explains what it is, and contains some snippets: https://voxel-tools.readthedocs.io/en/latest/smooth_terrain/#signed-distance-fields
And... nothing renders.
In the editor? Or did you launch the game?
Don't forget to have a VoxelViewer
in your scene, as this is necessary to tell the terrain where to stream chunks. Also you should make sure the 3D camera looks at the right angle because sometimes surfaces will show up out of your view.
Also:
if distance_to_zero > 100 && distance_to_zero < 150:
buffer.fill_f(1, channel)
else:
buffer.fill_f(0, channel)
Signed distances need to cross 0 in order to produce a surface. All your voxels here will either have distance 0 or 1, so never crossing zero. So no surface will appear. At least maybe you need to set -1
instead of 0
.
if distance_to_zero > 100 && distance_to_zero < 150:
With this logic I suppose you will obtain a very crude boxy hollow sphere, but inverted, so if your camera spawns at the origin, it will actually be below the surface and won't see it due to backface culling. And since it is inverted, there is a "ceiling" you could see 150 units away, but I suspect default view distance wont be enough to see it. I might be wrong on that one tho.
if lod != 0: return
And this pretty much prevents you to see any of it as well. Because by default LOD 0 only extends through a limited distance (I think about 50 units?) away from the camera, after which LOD 1 starts, then LOD 2 further away etc. But then your generator will return empty chunks beyond LOD 0 so nothing will show up since your shape "starts" at around 100 units away from origin. You can see how the expected VoxelBuffers look like in this LOD system here: https://voxel-tools.readthedocs.io/en/latest/smooth_terrain/#level-of-detail-lod
If you need an example:
extends VoxelGeneratorScript
const channel : int = VoxelBuffer.CHANNEL_SDF
func _get_used_channels_mask() -> int:
return 1 << channel
func _generate_block(buffer : VoxelBuffer, origin : Vector3i, lod : int) -> void:
var bs := buffer.get_size()
var sphere_radius := 50.0
# This is not required, but helps getting a smooth result,
# see https://voxel-tools.readthedocs.io/en/latest/smooth_terrain/#scaling-and-clamping
var quantization_factor := 0.01
for z in bs.z:
for x in bs.x:
for y in bs.y:
# The `a << b` operator is equivalent to `a * pow(2, b)`, but is faster than `pow`.
# Unfortunately Godot's `Vector3i` does not support this operator for some reason.
var position := Vector3(origin) + Vector3(x << lod, y << lod, z << lod)
var distance_to_zero := Vector3(position).distance_to(Vector3.ZERO)
# Makes a sphere centered at the origin. Move the camera above 50 units in order to see it,
# or invert the sign to turn it inwards.
# This is one of the simplest SDF shapes.
# More here: https://iquilezles.org/articles/distfunctions/
var sphere_signed_distance := distance_to_zero - sphere_radius
buffer.set_voxel_f(sphere_signed_distance * quantization_factor, x, y, z, channel)
If you want to fill all space with matter, you can also just do buffer.fill_f(-1, channel)
. Nothing will show up until you carve something, but that's normal because if all space is filled, there will be no surface to show, because existence of a surface implies existence of a non-filled area.
In the editor? Or did you launch the game?
Ah sorry I should've clarified since I know people frequently neglect to do that stuff: I initially used the flat generator as a sanity check and I did see its output using the same setup (both in editor & in game). The camera (with VoxelViewer child) is moveable with WASD/mouse via a script, and I always check by zooming and rotating to different angles.
I'm also aware that my generator script's output won't be visible in the editor unless I enable the "Run Stream In Editor" option on VoxelLodTerrain, which I shouldn't do unless I'm planning not to change any script files (because the editor accessing them would cause problems).
Signed distances need to cross 0 in order to produce a surface. All your voxels here will either have distance 0 or 1, so never crossing zero. So no surface will appear. At least maybe you need to set -1 instead of 0.
Ah yeah thanks, I think this is the concept I wasn't understanding, even having read over your SDF doc (perhaps not thoroughly enough).
if lod != 0: return
And this pretty much prevents you to see any of it as well.
Okay, that makes sense. I copied my script from the example I found in the scripting docs, I guess it works in that scenario because blocky voxels don't support LOD therefore always have lod == 0
? But I was curious about how anything outside the first LOD zone would get rendered with that line there... figured I should at least see some stuff near the camera though.
Thanks for all your help, and appreciate the example, I'll have to play with that after work! Closing since you've given me plenty to work with and it's my fault if I can't get it to render at this point lol.
Thanks so much for your making your work available, this module is really cool!
I'm having trouble getting my
VoxelLodTerrain
to generate any visible output. My scene looks like this:I'm using a recent Windows build of the editor (1a51cc2)
My VoxelLodTerrain is set up with the default ShaderMaterial, just added a fragment shader which sets the albedo and left the vertex shader alone for now. This is the main script on the scene root:
And
my_generator.gd
looks like:And... nothing renders. I'm pretty new to Godot and this module so it's quite possible I'm missing an important step or doing something dumb, but the docs and sample projects seem to be lacking examples of how to make a generator for SDF
VoxelLodTerrain
so I'm stuck.The script above is my attempt to just produce any visible result, but my ultimate goal is to generate a solid 3D block of voxels and carve tunnels out of it based on other logic in my game code, like distance from a Curve3D (inside the radius of the tunnel = no voxels). IDK whether this is even a sane approach but it seems like a better option than using VoxelTool to carve tunnels at runtime.
Any advice is greatly appreciated!