Voxelers / 3d

3D in Voxelers
Apache License 2.0
9 stars 1 forks source link

Analyze how the terrain is created and create it in its simplest way #16

Closed acs closed 4 years ago

acs commented 4 years ago

After our successful experience playing with simple voxels using the VoxelMesherCubes in #11 it is time to play with the real thing: the terrain. It has physics included so it is our main goal to understand how physics works with voxels.

Now it is important to read all the doc in https://github.com/Zylann/godot_voxel/blob/master/doc/01_get-started.md

Let's start playing with VoxelTerrain and with its tutorial. Review the video and all its comments with interesting info about this terrain feature.

Our goal is to create a plain world of a variable size. The thick of the world should be configurable. With it we will start to play with physics trying to implement overhangs, tunnels, and user creation/destruction.

acs commented 4 years ago

Our first VoxTerrain

A VoxTerrain is a SpatialNode with some properties:

Screenshot from 2020-09-30 06-47-11

Stream

The stream defines from where to get the voxels that will define the world.

VoxTerrainStreams

We can create our own VoxelGenerator from GDScript.

The simplest one is just to use VoxelGeneratorFlat which will create a flat terrain covering "all" the world

Screenshot from 2020-09-30 06-55-33

And we can define the height of the flat world.

Screenshot from 2020-09-30 07-33-16

By default the dimensions are:

Screenshot from 2020-09-30 07-02-00

But we can define them using the Bounds! Not sure what the size of the grid indicates. It is a grid reference which VoxelTerrain adds.

Screenshot from 2020-09-30 06-56-45

By default the collision are enable so let's check what happens if we let a mesh drops in the terrain

acs commented 4 years ago

Bounds

Playing with the bounds I get the message:

ERROR: push_call: Message queue out of memory. Try increasing 'memory/limits/message_queue/max_size_kb' in project settings. godot-memory-queue

In my first try Bounds are not very intuitive ... let's try to understand how they work playing with them. My goal is to have a small terrain first.

For example, playing with x I can set that it must start at "-10" and if the width is 20 it must be a region from -10 to 10. And it is how it works. But is seems to be a big buggy when showing in real time these changes. You need to press the "Re-generate" button!

Screenshot from 2020-09-30 07-22-07

Also the precision is not right ... there is 16 grid boxes at both sides. Maybe the grid size is not 1?

Screenshot from 2020-09-30 07-25-04

The automatic refresh and the re-generate results are not always the same.

Ok, it seems that if you don't modify the bounds for the height, it is mostly working, but with the low precision between grids and units in the bounds.

acs commented 4 years ago

Ok, material can be defined easily as expected:

Screenshot from 2020-09-30 22-21-51

and with the view distance we can define how far the world is rendered.

Screenshot from 2020-09-30 22-26-14

Ok, just pending to understand the properties for the Voxel Library, and important topic:

Screenshot from 2020-09-30 22-27-25

and all the details related to a voxel:

Screenshot from 2020-09-30 22-28-57

Guau, it is pretty interesting!

acs commented 4 years ago

The first try has not worked. The terrain is not shown in the rendering of the scene:

Screenshot from 2020-09-30 23-19-24 Screenshot from 2020-09-30 23-20-00

acs commented 4 years ago

In the terrain there are two voxels, one that is called air and the other one that is called solid. Not sure if here is the problem.

But inside the 3D editor then terrain is shown. And also using the camera view. So, why not when doing the final rendering?

acs commented 4 years ago

Voxel Library

I am not sure if the VoxelLibrary is used in this example. According to the doc it is: «A collection of voxel types, which is used for blocky only, similar to Minecraft or GridMap.»

And inside it we have two voxel types defined. But not sure if one of them is used by the VoxelTerrain.

acs commented 4 years ago

VoxelGeneratorWave

The same experience than with the flat generator. In the render view, the terrain does no appear. It should be related to a config issue.

acs commented 4 years ago

The problem that the VoxelTerrain is not generated is related to current status of master. In the 3.2.3 branch it works correctly.

Screenshot from 2020-10-01 00-17-08 Screenshot from 2020-10-01 00-13-55

and probably it is related with the desapparition of the ViewerPath option.

acs commented 4 years ago

Ok, the problem is that in the new version the VoxelViewer node must be added. It is the evolution of the ViewerPath. Pointed out at: https://github.com/Zylann/godot_voxel/issues/198#issuecomment-701667305

acs commented 4 years ago

Ok, so the next step is to track in the code how the VoxelTerrain is created. And for that, the best approach is to create the VoxelTerrain from code, so it is easier to follow all in the code later.

acs commented 4 years ago

Nice results ... let's continue playing:

Screenshot from 2020-10-01 07-06-55

acs commented 4 years ago

Ok, next step is to create a minima VoxelTerrain from GDScript code and track its execution in GDScript and in the voxel module C++ code. Let's do it!

acs commented 4 years ago

https://github.com/Zylann/godot_voxel/blob/master/doc/03_create-terrain.md#create-a-terrain-with-code

All this tutorials work with the 3.2.3 branch of godot_voxel. So it is better to play with it. I have tried to add a VoxelViewer but the terrain nos not rendered in master branch version of godot_voxel.

acs commented 4 years ago

Really cool. To create a flat terrain the code needed is:

extends Spatial

var terrain = VoxelTerrain.new()

func _ready():
    terrain.stream = VoxelGeneratorFlat.new()
    add_child(terrain)

and for physics probably we must add:

        terrain.generate_collisions = true

Just add it to a Spatial Node, add a Camera and that's all.

Screenshot from 2020-10-01 23-15-56

So the key is to understand how godot call the rendering of VoxelTerrain, The other two lines are just creating the two objects and configuring the stream property. But let's debug the full process.

acs commented 4 years ago

Ok, the main method in which the VoxelTerrain is created is in ... "_process". Godot engine send a notification (NOTIFICATION_PROCESS) to the Node to process the node. It is a pretty long implementation this _process method.

The implementation goes from line 756:

void VoxelTerrain::_process() {

until line

1085:

_stats.time_process_update_responses = profiling_clock.restart();

and the basic logic is to get blocks from the voxel generator and render them using a mesher. The meshed used depends in the channel configured (blocky:0, sdf:1).

acs commented 4 years ago

Changing from blocky to smooth terrain is as easy as changing the Channel from the Generator.

Screenshot from 2020-10-01 23-55-46

acs commented 4 years ago

So probably the next goal is to understand how the blocks are rendered. Because the render process is based on blocks.

It seems that this work is done by the VoxelMeshUpdater. And it has to meshers:

    Ref<VoxelMesherBlocky> blocky_mesher;
    Ref<VoxelMesherTransvoxel> smooth_mesher;

and the main logic for doing the meshing is the same that we already saw:

        if (blocky_mesher.is_valid()) {
            blocky_mesher->build(output.blocky_surfaces, input);
        }
        if (smooth_mesher.is_valid()) {
            smooth_mesher->build(output.smooth_surfaces, input);
        } 

So the physics must be inside this meshers probably.

acs commented 4 years ago

Ok, as a summary, the process of rendering a VoxelTerrain is mostly described. As with the meshers, the low level stuff I have not studied in all its glory details, but I will dot it. There are threads inside the "_process" method that we must understand.

But we can close this ticket and focus now in physics in VoxelTerrains.

acs commented 4 years ago

VoxelTerrain Edition

In order to edit a VoxelTerrain there is the class VoxelTool which provides some methods for editing:

    // The following methods represent one edit each. Pick the correct one for the job.
    // For example, using `do_box` will be more efficient than calling `do_point` many times.
    virtual void set_voxel(Vector3i pos, uint64_t v);
    virtual void set_voxel_f(Vector3i pos, float v);
    virtual void do_point(Vector3i pos);
    virtual void do_line(Vector3i begin, Vector3i end);
    virtual void do_circle(Vector3i pos, int radius, Vector3i direction);
    virtual void do_sphere(Vector3 center, float radius);
    virtual void do_box(Vector3i begin, Vector3i end);

    virtual void paste(Vector3i pos, Ref<VoxelBuffer> p_voxels, uint64_t mask_value);

    virtual Ref<VoxelRaycastResult> raycast(Vector3 pos, Vector3 dir, float max_distance, uint32_t collision_mask);

The edition is done at voxel level. For example:

               box.for_each_cell([this, center, radius](Vector3i pos) {
            float d = pos.to_vec3().distance_to(center) - radius;
            _set_voxel_f(pos, sdf_blend(d, get_voxel_f(pos), _mode));
        });
acs commented 4 years ago

VoxelTerrain loading data

Once the stream is set in the VoxelTerrain a thread is started to load its data with: start_streamer()

void VoxelTerrain::start_streamer() {
    ERR_FAIL_COND(_stream_thread != nullptr);
    ERR_FAIL_COND(_stream.is_null());

    _stream_thread = memnew(VoxelDataLoader(1, _stream, get_block_size_pow2()));
}

So the loading of data logic is easy to track.