pandemonium_engine/doc/engine/voxelman.md

228 lines
9.3 KiB
Markdown
Raw Normal View History

# Voxelman
A voxel engine for godot, focusing more on editor integration, gameplay-related features, and extendability (even from gdscript), without sacrificing too much speed.
This is an engine module! Which means that you will need to compile it into Godot! [See the compiling section here.](#compiling)
You can find a demonstration project (with pre-built binaries) here: https://github.com/Relintai/the_tower
## Godot Version Support
I'm currently mostly using [Terraman](https://github.com/Relintai/terraman) instead of this, so it might get temporarily a bit behind.\
If compile breaks, and I don't notice please report.
3.2 - Will likely work, probably needs changes by now. (TODO check.)\
3.3 - Will more likely work, might need smaller changes by now. (TODO check.)\
3.4 - Should work without any issues. (TODO check.)\
3.x - Works. [last tested commit](6ea58db2d849d9ca0ccee5bc6a6d2b919d404bc1)\
4.0 - Have been fixing support from time to time. Currently it won't build. Mostly done with the fix though.
## Optional Dependencies
`https://github.com/Relintai/texture_packer`: You get access to [VoxelLibraryMerger](#voxellibrarymerger) and [VoxelLibraryMergerPCM](#voxellibrarymergerpcm). \
`https://github.com/Relintai/mesh_data_resource`: You get access to a bunch of properties, and methods that can manipulate meshes.\
`https://github.com/Relintai/props`: You get access to a bunch of properties, and methods that can manipulate, and use props.\
`https://github.com/Relintai/mesh_utils`: Lets you use lod levels higher than 4 by default.
## Usage
First create a scene, and add a VoxelWorldBlocky / VoxelWorldMarchingCubes node into it. Create a VoxelLibrary, and assign it to the Library property.
Also, add a VoxelSurface into your library.
Tick the editable property, deselect, then select the world again, and click the insert button at the top toolbar, or press B to insert a
voxel at the inspector's camera's location.
Select the add button, and now you can just add voxels with the mouse, by clicking on the newly added voxel.
## VoxelLibrary
This class stores the materials, and the VoxelSurfaces.
Lod levels will automatically try to use materials of their own index.\
For example lod level 1 will try to use material index 1, lod level 2 will try to use material index 2, etc.\
If a material index is not available, they'll use the highest that is.\
For example lod level 5 will try to get material index 5, but if you only have 3 materials it will use the 3rd.
### VoxelLibrarySimple
The simplest library, just assign a material with a texture, and using the atlas_rows and atlas_culomns properties to tell the system
how the UVs should be divided.
2022-03-16 09:02:48 +01:00
This is the basic Minecraft-style lib rary. Use this if you just have one texture atlas.
### VoxelLibraryMerger
You will only have this if your godot also contains https://github.com/Relintai/texture_packer
You can assign any texture to your surfaces with this, and it will merge them together.
### VoxelLibraryMergerPCM
(PCM = Per Chunk Material)
You will only have this if your godot also contains https://github.com/Relintai/texture_packer
You can assign any texture to your surfaces with this, and it will merge them together, but it will do it for every required chunk/voxel combination.
For example if you have a chunk with voxel Grass, and voxel Stone used in it, this library will create a material with a merged texture for Stone and Grass.
If you have an anouther chunk which only has Grass and Stone in it, this material will be reused.
And if you have a third chunk which only has a Grass voxel used in it, it will get a new merged material and texture only containing Grass voxel.
## Worlds
The 2 base classes. These won't do meshing on their own:
VoxelWorld: Basic world, does not do anything until you implemnent the required virtual methods!\
VoxelWorldDefault: This adds threading, and LoD storage support to VoxelWorld. Will not create meshes for you!
### VoxelWorldBlocky
The most basic world. It is the Minecraft-style world.
### VoxelWorldMarchingCubes
A marching cubes based Voxel World. Actually it uses a modified version of the Transvoxel tables, because it is UV mapped.
### VoxelWorldCubic
This is my own meshing algorithm, it's basicly a Minecraft style mesher that can take isolevel into account.
It's kind of a pain to use, it might get removed.
### Level generation
Assign a VoxelManLevelGenerator to the `World`'s `Level Generator` property.
You can write your own algorithm by implementing the ``` void _generate_chunk(chunk: VoxelChunk) virtual ``` method.
`VoxelManLevelGeneratorFlat` is also available, it will generate a floor for you, if you use it.
## VoxelJobs
Producing just a terrain mesh for a chunk is not that hard by itself. However when you start adding layers/features
2022-03-16 09:02:48 +01:00
like lod generation, collision meshes (especially since manipulating the physics server is not threadsafe),
vertex lights, props, snapping props, props with vertex lights, etc
chunk mesh generation can quicly become a serious mess.
VoxelJobs are meant to solve the issue with less complexity.
They also provide a way to easily modularize mesh and lod generation.
### VoxelJob
Base class for jobs.
If the [thread pool](https://github.com/Relintai/thread_pool) module is present, this is inherited from `ThreadPoolJob`,
else it implements the same api as `ThreadPoolJob`, but it's not going to use threading.
A job has a reference to it's owner chunk.
If you implement your own jobs, when your job finishes call `next_job()`.
### VoxelLightJob
This is the job that will generate vertex light based ao, random ao, and will bake your `VoxelLight`s.
### VoxelTerrainJob
This will generate your terrain collider and mesh (with lods) for you, using the meshers that you add into it.
Your lod setup is easily customizable with [VoxelMesherJobSteps](https://github.com/Relintai/voxelman/blob/master/world/jobs/voxel_mesher_job_step.h). The setup happens in your selected world's `_create_chunk` method.
### VoxelPropJob
This will generate your prop meshes (with lods).
Also supports [VoxelMesherJobSteps](https://github.com/Relintai/voxelman/blob/master/world/jobs/voxel_mesher_job_step.h).
### Internal workings
#### VoxelWorld
Whenever you want to spawn a chunk your World will create it using the ``` VoxelChunk _create_chunk(x: int, y: int, z: int, chunk: VoxelChunk) virtual ``` method.
Since properly initializing a chunk usually takes quite a few steps that you probably don't want to repeat everywhere the `chunk`
parameter was added. This means you can just call the super `_create_chunk` methods, and you won't need to worry about your chunk
getting overridden. Like:
2022-03-16 09:02:48 +01:00
Note that `_create_chunk` is also responsible for initializing chunks if you have them stored inside a scene.
This is done by `setup_chunk(shunk)` in `VoxelWorld`.
2022-03-16 09:02:48 +01:00
```
func _create_chunk(x : int, y : int, z : int, chunk : VoxelChunk) -> VoxelChunk:
if !chunk:
chunk = MyChunk.new()
# We need to check whether or not we need to initialize jobs
if chunk.job_get_count() == 0:
# Setup a blocky (minecratf like) mesher job
var tj : VoxelTerrainJob = VoxelTerrainJob.new()
var s : VoxelMesherJobStep = VoxelMesherJobStep.new()
s.job_type = VoxelMesherJobStep.TYPE_NORMAL
tj.add_jobs_step(s)
tj.add_mesher(VoxelMesherBlocky.new())
tj.add_liquid_mesher(VoxelMesherLiquidBlocky.new())
chunk.job_add(tj);
#setup your chunk here
return ._create_chunk(x, y, z, chunk)
```
You can look at the world implementations for more examples: [VoxelWorldBlocky](https://github.com/Relintai/voxelman/blob/master/world/blocky/voxel_world_blocky.cpp), [VoxelWorldMarchingCubes](https://github.com/Relintai/voxelman/blob/master/world/marching_cubes/voxel_world_marching_cubes.cpp).
#### VoxelChunk
Stores terrain data, prop data. And mesh data (VoxelChunkDefault), and the mesh generation jobs.
When it starts building meshes it will start submitting jobs to thread_pool one by one.
#### VoxelMesher
If you want to implement your own meshing algorithm you can do so by overriding ``` void _add_chunk(chunk: VoxelChunk) virtual ```.
VoxelMesher works similarly to SurfaceTool, so first you need to set colors, uvs, etc and then call add_vertex.
They won't get reset, so for exaple if you want all your vertices to have a certain color, you can get away with setting it only once.
## Compiling
First make sure that you can compile godot. See the official docs: https://docs.godotengine.org/en/3.x/development/compiling/index.html
1. Clone the engine if you haven't already:
If you want Godot 3.x:
```git clone -b 3.x https://github.com/godotengine/godot.git godot```
If you want Godot 4.0:
```git clone https://github.com/godotengine/godot.git godot```
2. go into the modules folder inside the engine's directory:
```cd godot``` \
```cd modules```
3. clone this repository
```git clone https://github.com/Relintai/voxelman.git voxelman```
(the folder needs to be named voxelman!)
4. If you want the optional dependencies run these commands aswell:
```git clone https://github.com/Relintai/texture_packer.git texture_packer``` \
```git clone https://github.com/Relintai/mesh_data_resource.git mesh_data_resource```
5. Go up one folder
```cd ..```
6. Compile godot.
For example:
```scons p=x11 t=release_debug tools=yes```