HungryProton / scatter

Godot engine addon to randomly fill an area with props or other scenes
MIT License
2.06k stars 94 forks source link

How to set shader parameter on ScatterItem mesh in 4.0 version #106

Open sebastianrueckerai opened 1 year ago

sebastianrueckerai commented 1 year ago

Hi!

I am trying to pass the player position to the shader of the material used in the mesh for the Scatter Item. This is so I can have grass reacting to the player walking over it.

I have the following setup to do this: image

In the parent Node 3D I have the following script:

@tool
extends Node3D

@onready var player = get_tree().get_root().get_node("World/Player")
@onready var mm = $ProtonScatter/ScatterItem/MultiMeshInstance3D

func _process(_delta):
    mm.multimesh.mesh.surface_get_material(0).set_shader_parameter("player_position", player.global_transform.origin)

Is there a better way to access the shader parameters more directly?

Thanks! :)

sebastianrueckerai commented 1 year ago

So I can also just add an instance of the mesh used to the scene and set the shader param there. No need for the MultiMesh. Still, it seems like there should be an option to do this directly in the Scatter Node?

HungryProton commented 1 year ago

Scatter doesn't really do anything else than positioning, the issue with materials is that they can be in a lot of different places (mesh surfaces, mesh surfaces override, geometry material override, or maybe the overlay or in a next pass) so handling these are really up to the user.

For your specific case, however, I would just put the player position as a global uniform and change that instead, this way you don't have to worry about changing the shader parameter everywhere manually, you only have to do it in a single place.

sebastianrueckerai commented 1 year ago

Thanks for pointing me towards global uniform. I did not know about those! :)

This solve my immediate issue but I guess the questions remain_ I don't exactly know how scatter does what it does, but I imagine it is creating one instance of the scene it scatters? It might be helpful for other things to have access to this instance. For example: One could set different color values for the same grass in different scatter nodes. Currently to do do this I would have to create clones on the same scene that are only different in the color value of a variable. Is there any way to do this?

HungryProton commented 1 year ago

You can see what it does under the hood by clicking the Show output in tree on your scatter node, under the General tab. Even though it looks like you could edit the materials there, they may get lost when Scatter tries to regenerate these nodes, so that's not a solution.

I need to think about it, but one possible option could be to add a Material Override parameter to the ScatterItem, and force it to the multimesh (or the full copies if instancing is disabled), but then if your mesh have multiple surfaces with different materials, you lose that data.

sebastianrueckerai commented 1 year ago

Well, for now the workarounds.. work! :)

Eventually it would be cool to edit scene attributes for each node, maybe even attributes not related to the material.

HungryProton commented 1 year ago

If that helps, I've just added a material override property in the ScatterItem node. (This won't help if your mesh has multiple surfaces though). But at least it's easier to reach.