Rendering a lot of different objects using a shader only renders using the last iteration uniform value

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By RotcivOcnarb

Ok, so i have a scenario where one node is responsible for rendering a lot of other nodes (2DColliders) using a specific material shader.

The shader has an Uniform which store the object color (a Vec4), and while iterating through all the 2DColliders i need to render, every time i just set the uniform to the object Modulate:

func _draw():
#
    for m in meta_group.get_children():

	var sz = Vector2(m.get_node("CollisionShape2D").shape.radius * 2, m.get_node("CollisionShape2D").shape.radius * 2)
	get_material().set_shader_param("modulate", m.modulate)
	draw_set_transform(m.position, 0, Vector2(1, 1))
	draw_texture_rect(texture, Rect2(-sz.x, -sz.y, sz.x*2, sz.y*2), false, modulate)

But when playing the game, instead of each node has its specific color, all of them are rendered with only one color (which i assume is the last modulate iterated)

This is the code that spawns the 2D Colliders to be rendered:

func spawn_paint():
var m = meta.instance()
m.position = get_node("Brush/Node2D").get_global_transform().get_origin()
		
var vel = (get_node("Brush/Node2D").get_global_transform().get_origin() - get_node("Brush").get_global_transform().get_origin()).normalized()
m.linear_velocity = vel * 300
m.modulate = Color().from_hsv(colorTimer - int(colorTimer), 1, 1, 1)
m.linear_velocity = m.linear_velocity.rotated(rand_range(-0.1, 0.1))
m.get_node("CollisionShape2D").set_shape(CircleShape2D.new())
m.get_node("CollisionShape2D").shape.radius = rand_range(3,6)
		
get_tree().get_root().get_node("Root/MetaGroup").add_child(m)

I use a timer to shift a HUE value to make the colliders interpolate to al HUE values.

But when i run the game, this is what is rendered: (when i shoot a ball, ALL the balls are set with the same color)

Result

Is there any rendering 2D Pipeline that could be doing this behaviour?

What i have imagined is that probably, when i call “draw_texture_rect”, it doesnt draw imediately, and insteady adds to a “batcher”, and at the end of the “_draw()” function, it then renders all of them at once using only the last shader param setted.

If this is the case, is there any way to “force” a batch flush so it can be rendered each one with an specific uniform value?

Seems to be that all material uses the same material instance. So the shader uniform is shared by all material(s).

Try to assign an individual copy of the material to each instance of your texturerect (or whatever you use it in.) You can use the method “.duplicate()” to make a copy of any resource (including shader materials).

I hope it works.

wombatstampede | 2019-04-14 10:09

Thanks for the help, but i don’t think that is the case.

The thing is that the 2DColliders do not have a Material object, the modulate property is a separeted property from the material, within te CanvasItem object:

enter image description here

I do have made a test by assigning a different Material instance to each Collider, but that didn’t make any effect

RotcivOcnarb | 2019-04-14 11:29