Zylann / godot_voxel

Voxel module for Godot Engine
MIT License
2.68k stars 251 forks source link

VoxelGeneratorScript does not show / draw anything #626

Open Anyeos opened 6 months ago

Anyeos commented 6 months ago

Describe the bug VoxelGeneratorScript does not work at all. I tried a lot of things, from using a noise, to only calling set_voxel to calling set_voxel_f and so. There are no way to make it work. It does not take in account at all the data. I can set 1, 0, 100, 10000, 10.0, etc but it does not do anything.

To Reproduce Use VoxelGeneratorScript.

Example:

func _generate_block(out_buffer, origin_in_voxels, lod):
    out_buffer.fill_f(10.0, VoxelBuffer.CHANNEL_SDF)

func _get_used_channels_mask() -> int:
    return 1 << VoxelBuffer.CHANNEL_SDF

Expected behavior Show the voxels.

Environment

Zylann commented 6 months ago
out_buffer.fill_f(10.0, VoxelBuffer.CHANNEL_SDF)

Assuming you are using the Transvoxel mesher, this line fills all space with signed distance 10, which is outside matter, so you will see nothing. In fact, if you set the same value everywhere, you will rarely ever see anything, no matter the value or mesher. With smooth voxels, (Transvoxel) it either means all space is air when > 0, or all space is matter when < 0, so no surface will ever show up. For surfaces to show up, voxels have to vary across 0.

As shown in https://voxel-tools.readthedocs.io/en/latest/smooth_terrain/#signed-distance-fields, to write a smooth voxels generator, you need an understanding of signed distance fields.

For example, a generator producing a sphere of radius 10 centered at the origin, would look like this (untested, just wrote on the fly to illustrate my post):

func _generate_block(out_buffer, origin_in_voxels, lod):
    for rz in out_buffer.get_size().z:
        for rx in out_buffer.get_size().x:
            for ry in out_buffer.get_size().y:
                var pos_world := Vector3(origin_in_voxels) + Vector3(rx, ry, rz)
                var sd := pos_world.distance_to(Vector3(0,0,0)) - 10.0
                out_buffer.set_voxel_f(sd, rx, ry, rz, VoxelBuffer.CHANNEL_SDF)

Or a plane at altitude 5:

func _generate_block(out_buffer, origin_in_voxels, lod):
    for rz in out_buffer.get_size().z:
        for rx in out_buffer.get_size().x:
            for ry in out_buffer.get_size().y:
                var pos_world := Vector3(origin_in_voxels) + Vector3(rx, ry, rz)
                var sd := pos_world.y - 5.0
                out_buffer.set_voxel_f(sd, rx, ry, rz, VoxelBuffer.CHANNEL_SDF)

However if you intented to use blocky voxels, your code would look a bit different.

If things still don't work, there are a number of possible reasons:

Anyeos commented 6 months ago

Yes, sorry, I noted it recently. I was following the C code under the other generators and I missunderstood this. But anyway maybe there can be some notation or doc that explains how is it. Thank you for your explanation that makes me understand it better.