godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.16k stars 97 forks source link

Implement an algorithm for procedurally generating dots to `FastNoiseLite` #9690

Open RadiantUwU opened 6 months ago

RadiantUwU commented 6 months ago

Describe the project you are working on

World generation in 3D

Describe the problem or limitation you are having in your project

Having to randomly place details like rocks and twigs and having no deterministic way of doing it.

Describe the feature / enhancement and how it helps to overcome the problem or limitation

This would allow generating dots which would not only solve that issue, it would also solve many other issues for things like ore generation, tree generation, etc.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

It would add another algorithm to the list of supported random algorithms to FastNoiseLite, allowing the user to have yet another algorithm.

If this enhancement will not be used often, can it be worked around with a few lines of script?

Yes, here's an example in GDScript, but it is quite hard to use it when the editor preview doesnt show exactly whats gonna come after this.

var v := noise.get_noise_2dv(pos)
if v > dot_constant:
    return mapf(v,dot_constant,1.0,0.0,1.0)
return 0

Is there a reason why this should be core and not an add-on in the asset library?

It would make it more straight-forward for users to use the FastNoiseLite system for procedurally generating things.

Calinou commented 6 months ago

For placing random structures in an aesthetically pleasing manner, you may be interested in Poisson distribution.

RadiantUwU commented 6 months ago

For placing random structures in an aesthetically pleasing manner, you may be interested in Poisson distribution.

Btw how is this topic core when its one module named noise?

aXu-AP commented 6 months ago

See if this plugin suits you: https://github.com/arcaneenergy/godot-multimesh-scatter (also found in Asset Library) I think it can be used for placing props runtime in deterministic manner, altough I haven't tested for that case.

RadiantUwU commented 6 months ago

See if this plugin suits you: https://github.com/arcaneenergy/godot-multimesh-scatter (also found in Asset Library) I think it can be used for placing props runtime in deterministic manner, altough I haven't tested for that case.

I dont think it does, i want it to be deterministic and happen in the same world positions every single time. I'm making a game with infinite world sizes by the way.

Calinou commented 6 months ago

Btw how is this topic core when its one module named noise?

The topic:core label tends to be used for anything that doesn't fit in other labels, and isn't 2D/3D-specific.

aXu-AP commented 6 months ago

I'm not entirely sure what this function would do? What parameters it takes? Noise functions generally are known for their property of generating continuous gradients (taking position, outputting value), generating dots is quite different.

If, for example, you are wanting to generate bunch of random coordinates for a certain region, you could use the region's position's hash as a seed and generate random numbers for coordinates. This is closer to the way Minecraft eg. does it. You can use noise function to distribute the points in more interesting way.

On the other hand, if you want to generate noise, but want the output be 1 or 0, you can set up a simple sprite to preview the result: kuva

RadiantUwU commented 6 months ago

Hello ^ The above image does not suit my use-case. It would've required those dots to be always one pixel, which is clearly unable to be respected by simply applying a gradient to a noise.

aXu-AP commented 6 months ago

In that case you should do option A (generate coordinates from a hash) since noise generators in general isn't the tool you're looking for. Here's a small example to get you started:

@tool
extends Node2D

@export var points_in_chunk = 10:
    set(value):
        points_in_chunk = value
        queue_redraw()
@export var chunk_size = 300:
    set(value):
        chunk_size = value
        queue_redraw()

func _draw() -> void:
    # Generate 4 chunks as an example.
    generate_points(Vector2(0, 0))
    generate_points(Vector2(1, 0))
    generate_points(Vector2(0, 1))
    generate_points(Vector2(1, 1))

func generate_points(chunk_position):
    var rng = RandomNumberGenerator.new()
    rng.seed = hash(chunk_position)
    for i in points_in_chunk:
        draw_circle((chunk_position + Vector2(rng.randf(), rng.randf()) * chunk_size), 10, Color.YELLOW)

However, there's alot of ways this can be extended further, like poisson distribution as Calinou suggested, clustering, or varying density. I don't think there exists an algorithm general enough to cater most use cases, each project has its own requirements and procedural generation is a very deep rabbit hole.