Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is there any way to access the mesh of the resulting Voxel terrain? #276

Closed
Xeadriel opened this issue Jun 6, 2021 · 3 comments
Closed
Labels

Comments

@Xeadriel
Copy link

Xeadriel commented Jun 6, 2021

Hi,
Currently I set up a world editor that allows me to edit, create and save the world point by point by using voxeltool.

Later I load it in the same way I manually build the world but just automatically. Again by using voxeltool in the terrain for placing all voxels at their correct location. Now I would like to access the mesh because I want to try use them with existing pathfinding modules because regular A* just doesnt cut it even if I implement it in c++.

Can you point me towards how to access the mesh of an existing voxel terrain? Ive spent hours looking in the documentation and also into the c++ module as well. I wouldnt mind if you pointed me towards the mesh inside the module so that I can expose it myself for my project but its just so intertwined, I feel like I would need to understand your whole code just to find how to access the mesh even if it is even possible the way you implemented everything.

Thanks!

@Xeadriel Xeadriel changed the title Is there anyway to access the mesh of the resulting Voxel World? Is there any way to access the mesh of the resulting Voxel World? Jun 6, 2021
@Xeadriel Xeadriel changed the title Is there any way to access the mesh of the resulting Voxel World? Is there any way to access the mesh of the resulting Voxel terrain? Jun 6, 2021
@Zylann
Copy link
Owner

Zylann commented Jun 6, 2021

There is no exposed API to access meshes, but they are present inside this data structure:

VoxelTerrain:

VoxelMeshMap _mesh_map;

This one stores meshes in chunks. They don't necessarily are the same size of data chunks depending on your options. It uses the VoxelMeshMap class which has methods to convert coordinates. Inside chunks use the VoxelMeshBlock class, and the mesh used for rendering can be found here:
DirectMeshInstance _mesh_instance;

DirectMeshInstance, is a thin wrapper around VisualServer, and it holds a reference to the mesh inside:


VoxelLodTerrain:

VoxelMeshMap mesh_map;

This terrain types uses a similar structure, but with more twists:
Instead of a single VoxelMeshMap, it has many of them, as many as there are LODs. It stores meshes at multiple resolutions, and multiple sizes. They overlap, but at any given point in time, some will be hidden, some visible. The set of visible meshes should not overlap.
Contrary to the other terrain type, this one does have an accessor to meshes, because it was required to implement VoxelInstancer. It is however not a finalized API so I did not decide yet wether to expose it, because it could change.


Overall, one more thing to know about getting meshes this way: depending on what you do with it, it might be slower than ideal, because these meshes are for rendering. We can only hope Godot caches them in memory, so it won't have to download them back from the graphics card. They can also change anytime you edit the world, and they can get loaded or unloaded anytime as you move.

I never tested making navmeshes out of this, but it seems to me it's going to add a significant amount of work CPU-side (colliders are already a huge burden). Note, if you use blocky voxels, using meshes just because Godot happens to use navmeshes is a very bad idea, and instead could be outperformed with a simpler grid-based pathfinder.

I'm curious to see what comes out of this.

@Xeadriel
Copy link
Author

Xeadriel commented Jun 6, 2021

thanks for the detailed answer.

I'll try and give this a go...

@Zylann Zylann added the question label Jun 6, 2021
@Xeadriel
Copy link
Author

alright. so I managed to successfully extract the mesh and turn it into a working navmesh:

I assume you will not want to have these in your project but here is what I did for anyone interested(I'll skip the header files):

I added following lines to voxel_terrain.cpp:

Array VoxelTerrain::getAllMeshes() const{
	const Array array = _mesh_map.getAllMeshes();
	return array;
}

void VoxelTerrain::_bind_methods() {
	ClassDB::bind_method(D_METHOD("getAllMeshes"), &VoxelTerrain::getAllMeshes);

added these to voxel_mesh_map.cpp:

Array VoxelMeshMap::getAllMeshes() const
{
	Array meshesInstances;

	for each (VoxelMeshBlock* block in _blocks)
	{
		Ref<Mesh> mesh = block->get_mesh();
		if(mesh.is_valid()) {
			Transform transform = block->getMeshTransform();
			MeshInstance* meshInstance = memnew(MeshInstance());
			meshInstance->set_mesh(mesh);
			meshInstance->set_transform(transform);
			meshesInstances.append(meshInstance);
		}
	}

	return meshesInstances;
}

these to voxel_mesh_block.cpp:

Transform VoxelMeshBlock::getMeshTransform() {
	return _mesh_instance.get_transform();
}

and finally these to direct_mesh_instance.cpp:

void DirectMeshInstance::set_transform(Transform world_transform) {
	VOXEL_PROFILE_SCOPE();
	ERR_FAIL_COND(!_mesh_instance.is_valid());
	VisualServer &vs = *VisualServer::get_singleton();
	vs.instance_set_transform(_mesh_instance, world_transform);
	
	transform = world_transform;             <---------
}

Transform DirectMeshInstance::get_transform() {
	return transform;
}

what it does is basically get all the existing meshes (I made it so that their transform is saved when set) and use their saved location in order to set the blocks/chunks to their correct location. Simple actually. Your directions really helped. Thanks again.

after that I attached the meshes to new meshinstances because otherwise the next tool doesnt work.

then I used godot-splerger to merge the mesh into one mesh instance deleting all the small mesh instances.

then I used godotdetour to turn the mesh into a navmesh and set up some settings that can be easily read up on. I would recommend using cellsizes < 1 so that slopes work though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants