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

Generate biomes for smooth sdf VoxelLodTerrain #633

Closed
Cyberphinx opened this issue May 5, 2024 · 12 comments
Closed

Generate biomes for smooth sdf VoxelLodTerrain #633

Cyberphinx opened this issue May 5, 2024 · 12 comments
Labels

Comments

@Cyberphinx
Copy link

My current setup:

  • Terrain type: VoxelLodTerrain
  • Mesher: VoxelMesherTransvoxel
  • Generator: VoxelGeneratorNoise2D with FastNoiseLite, channel sdf, height start -200, height range 200
  • Stream: none
  • Scene structure: node3d/VoxelLodTerrain for a fps game
  • Plugin version (or where you got it): Godot Engine v4.3.dev.custom_build.4bca2d8bc (2024-04-24 16:55:30 UTC)
  • Godot version: Godot Engine v4.3.dev.custom_build.4bca2d8bc (2024-04-24 16:55:30 UTC)
  • OS: Fedora

What is the correct approach when it comes to generating different biomes with temperature, humidity, etc. with the VoxelLodTerrain using channel sdf? I believe it cannot be done in the same way as the blocky terrain, since it doesn't use channel type. Could you please provide a simple example/workflow description of how to do this with smooth terrain? Should it be done in the shader instead of the generator?

@Zylann
Copy link
Owner

Zylann commented May 5, 2024

You can't do all of this with a basic generator such as VoxelGeneratorNoise2D. Biomes require to compose multiple sources in arbitrarily complex ways that depend on your choices. You will have to either use VoxelGeneratorGraph, write your own with VoxelGeneratorScript, or mix both.
This is also unrelated to channels. Biomes can be done in similar ways with blocky or SDF, the difference is what kind of data you are blending and outputting. Some of it can also be done in shader if it's purely visual and deterministic (meaning shaders wouldn't have to depend on voxel data thanks to random seed).

@Zylann Zylann added the question label May 5, 2024
@Cyberphinx
Copy link
Author

Thanks for the reply. I'm trying to test a simple VoxelGeneratorScript just to render a flat plane to make sure that the script is attached to the VoxelLodTerrain correctly, but nothing shows up:
Screenshot from 2024-05-06 14-43-42

class_name TestGenerator
extends VoxelGeneratorScript

const channel : int = VoxelBuffer.CHANNEL_SDF

func _get_used_channels_mask() -> int:
	return 1 << channel

func _generate_block(out_buffer, origin_in_voxels, lod):
	print('Out buffer: ', out_buffer.get_size())
	for z in range(out_buffer.get_size().z):
		for y in range(out_buffer.get_size().y):
			for x in range(out_buffer.get_size().x):
				if y + origin_in_voxels.y == 0:
					out_buffer.set_voxel(1, x, y, z, VoxelBuffer.CHANNEL_SDF)

and then in the parent node of the VoxelLodTerrain:

@onready var terrain : VoxelLodTerrain = $LandscapeLod
func _ready():
    var generator = preload("res://src/world_generator/simple_generator.gd").new()
    terrain.generator = generator

Try running this, the print function returns a log like these:

Out buffer: (19, 19, 19)
Out buffer: (19, 19, 19)
Out buffer: (19, 19, 19)
Out buffer: (19, 19, 19)
Out buffer: (19, 19, 19)
Out buffer: (19, 19, 19)
Out buffer: (19, 19, 19)
Out buffer: (19, 19, 19)
Out buffer: (19, 19, 19)
...

Nothing is rendered on screen.
Are there some settings that I'm missing? Is there a tutorial of how to use VoxelGeneratorScript with VoxelLodTerrain?

Screenshot from 2024-05-06 14-42-40
Screenshot from 2024-05-06 14-42-33

@Zylann
Copy link
Owner

Zylann commented May 6, 2024

Thanks for the reply. I'm trying to test a simple VoxelGeneratorScript just to render a flat plane to make sure that the script is attached to the VoxelLodTerrain correctly, but nothing shows up:

There is another recent issue asking the same question, also doing the same mistakes (and that gets asked a lot because people don't read the docs / don't realize how Godot works) so to avoid repeating myself I'll link to it: #626 (comment)

@Cyberphinx
Copy link
Author

Cyberphinx commented May 6, 2024

Thank you for the quick reply and the links, they are really helpful! Sorry I'm quite new to godot.

For the biomes materials, it is correct to set buffer.set_voxel(material_index, x, y, z, VoxelBuffer.CHANNEL_INDICES) together with buffer.set_voxel_f(sdf, x, y, z, VoxelBuffer.CHANNEL_SDF) for the same buffer? And how to override the material for the buffer (eg. sand.tres, grass.tres, etc.), as there seem to be only one material slot in the editor of the VoxelLodTerrain?

@Zylann
Copy link
Owner

Zylann commented May 7, 2024

For the biomes materials, it is correct to set buffer.set_voxel(material_index, x, y, z, VoxelBuffer.CHANNEL_INDICES) together with buffer.set_voxel_f(sdf, x, y, z, VoxelBuffer.CHANNEL_SDF) for the same buffer?

Yes

And how to override the material for the buffer (eg. sand.tres, grass.tres, etc.), as there seem to be only one material slot in the editor of the VoxelLodTerrain?

Like for many terrains, using standalone materials is not possible because blending between different textures wouldn't work (and Godot doesn't come with something to handle it). So typically you have to do this in a single shader material, mixing procedural approaches (such as using normals to decide which texture to blend) and voxel data (for cases where the actual voxels tell what texture to use). This comes with a whole bunch of caveats and compromises, compared to heightmaps or regular models. See https://voxel-tools.readthedocs.io/en/latest/smooth_terrain/#texturing

@Cyberphinx
Copy link
Author

I have another question regarding LOD, do you know the causes for the distant meshes to appear floating / inverted until the player navigates to it/ becoming LOD0? (It is generated with a simple VoxelGeneratorScript with a noise)

Screenshot from 2024-05-07 00-35-27

@Zylann
Copy link
Owner

Zylann commented May 7, 2024

My suspicion is that your generator is not outputting LODs correctly. Note that with LOD1, world positions you sample on noise must be spaced twice as much, and so on by powers of two for each higher LOD index.

@Cyberphinx
Copy link
Author

Cyberphinx commented May 11, 2024

I was experimenting with the shader code in the docs with the custom VoxelGeneratorScript with 4 simple textures:

func _ready():
        var img_red = Image.create(16, 16, true, Image.FORMAT_RGBA8)
	img_red.fill(Color.RED)
	var img_green = Image.create(16, 16, true, Image.FORMAT_RGBA8)
	img_green.fill(Color.GREEN)
	var img_blue = Image.create(16, 16, true, Image.FORMAT_RGBA8)
	img_blue.fill(Color.BLUE)
	var img_yellow = Image.create(16, 16, true, Image.FORMAT_RGBA8)
	img_yellow.fill(Color.YELLOW)

	var texture_2d_array = Texture2DArray.new()
	texture_2d_array.create_from_images([img_red, img_green, img_blue, img_yellow])

	var material = terrain.material as ShaderMaterial
	material.set_shader_parameter("u_texture_array", texture_2d_array)

However, it generated some black areas. Do you know what could be the problem area that caused the black zone to appear and how to fix it?

(p.s. The hills are generated with a cellular noise in the VoxelGeneratorScript.)

image

image

@Zylann
Copy link
Owner

Zylann commented May 11, 2024

I can't tell, sorry. The problem is somewhere else that you havent posted. Probably your generator

@Cyberphinx
Copy link
Author

Cyberphinx commented May 11, 2024

In the example shader code, does the v_indices and v_weights correspond directly to the voxel buffer's CHANNEL_INDICES and CHANNEL_WEIGHTS values?

void vertex() {
    // Indices are integer values so we can decode them as-is
    v_indices = decode_8bit_vec4(CUSTOM1.x);

    // Weights must be in [0..1] so we divide them
    v_weights = decode_8bit_vec4(CUSTOM1.y) / 255.0;

In my generator, it is set using buffer.set_voxel(material_index, x, y, z, VoxelBuffer.CHANNEL_INDICES) with the material_index being, 1, 2, 3, 4, depending on biome_value of the buffer.

biome values are generated using a noise noise_biome.set_noise_type(FastNoiseLite.NoiseType.TYPE_CELLULAR) and mapped to each buffer var biome_value = noise_biome.get_noise_2d(pos_world.x, pos_world.z)

I've tried to change the values of the heights and the material indices in relation to the biome noise values, but some voxels still appear black.

@Zylann
Copy link
Owner

Zylann commented May 12, 2024

In the example shader code, does the v_indices and v_weights correspond directly to the voxel buffer's CHANNEL_INDICES and CHANNEL_WEIGHTS values?

Yes, though with a slightly different encoding.

In my generator, it is set using buffer.set_voxel(material_index, x, y, z, VoxelBuffer.CHANNEL_INDICES) with the material_index being, 1, 2, 3, 4, depending on biome_value of the buffer.

That's wrong. You are setting only one index per voxel, but the engine expects 4 at once. Values you set in here must be encoded as shown here: https://voxel-tools.readthedocs.io/en/latest/smooth_terrain/#voxel-data
Things are similar for weights.

Check these functions for encoding:

@Cyberphinx
Copy link
Author

It works now. Thank you for your support.

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