Rendertargets while manually drawing

Godot Version

4.2.2

Question

This is going to be quite specific, I’m using Godot here in a way that’s not necessarily the “intended” way, to achieve something i need to do.

So lets start Simply. I am using my own “_draw()” function to draw something to the screen… i.e.

func _process(_delta):
	queue_redraw()
	
func _draw():
	var col:Color = Color(0.647059, 0.164706, 0.164706, 1)
	var rect:Rect2 = Rect2(10, 10, 50, 50);
        node.draw_rect(rect, col, true)

This works. But what i really need to do is something like this (not actual code, as rendertargets like this dont exist)

func _draw():
	var col:Color = Color(0.647059, 0.164706, 0.164706, 1)
	var rect:Rect2 = Rect2(10, 10, 50, 50);
        set_render_target(rendertarget)
        node.draw_rect(rect, col, true)
        set_render_target(null)
        var tex = rendertarget.get_texture()
	node.draw_texture_rect(tex, scrRect, true)

The idea is to draw some “things” to the render target and then draw that render target to the screen.

Now I can in theory do this using SubViewports. Indeed if I set the scene up with a Subviewport, put some items in it… then draw the texture from that subviewport… it does exactly what i need - ish. The problem is, if i do that, then the other node will need to draw itself, which may be at a different time to the main node (I need all this to happen sequentially (it gets more complicated than my example).

I tried doing this:

MainNode:
->SubViewport
------>Node1

Script attached to main node… which calls this draw:

func _draw():
	var col:Color = Color(0.647059, 0.164706, 0.164706, 1)
	var rect:Rect2 = Rect2(10, 10, 50, 50);
	# draw rect to node1 (which is under it's own subviewport)
	node_1.draw_rect(rect, col, true)

	# get context of node1's subviewport and draw it to screen
	var tex = node_1.get_viewport().get_texture()
	main_node.draw_texture_rect(tex, screenRect, false)

But that doesnt work as “node_1” hasnt had the “Draw” message yet. If I call “queue_redraw” that isnt guaranteed to have happened this frame (or even next) so they’ll get out of sync.

So, my question - is there ANY way to do “Draw” calls to a rendertarget? which can be used immediately (so I can be sure everything happens on same frame). Ideally inside the same “_draw” funcion?

EDIT: Other thing I’ve tried:

I have this setup:

MainNode
->SubViewport
  ->TestingNode
->DrawNode

I’ve tried putting code in the “TestingNode->Draw” function. then Drawing the resulting RenderTargetTexture inside of “DrawNode”.

But this doesnt seem to want to work, i’m guessing the render texture is createed before the “Draw” funcion happens? If I do something like this:

MainNode
->SubViewport
  ->TestingNode
     ->TestSprite
->DrawNode

Then draw the results of THAT render target, i see the Testsprite. But again, I dont see any drawcalls i’ve made. Can I somehow tell subviewport to get the results of the “Draw” function? Maybe it updates at the start of the next frame or similar?

I’ve tried experimenting with “dont clear” and “update next frame” etc etc… but none of them do what i want (Actually I had to get the Beta version 4.3 to get the “dont clear” to work at all)

I’m sure I cant be the only person who needed this functionality - so please tell me it’s possible (Or i’ll cry :slight_smile: )

Thank you all.

If you need more clarification/etc to understand the problem, please let me know. I cant do what i need to do here using the standard “tree” system… this is for a graphical effect i’m trying to pull off.

EDIT: OR, “Draw” is only called “During idle time”, is there a way to force it to happen each frame (ideally while the render target is being drawn?)

It’s better if you explain what you want to achieve because I have no idea what you are trying to do.

Why do you need it to be sequentially?

Either way, this should work I guess:

extends Node2D


@onready var node_2d: Node2D = $SubViewport/Node2D


func _process(delta: float) -> void:
	queue_redraw()


func _draw() -> void:
	var col:Color = Color(0.647059, 0.164706, 0.164706, 1)
	var rect:Rect2 = Rect2(10, 10, 50, 50)

	# Connect to the draw signal in a ONE SHOT mode
	node_2d.draw.connect(func():
		node_2d.draw_rect(rect, col, true)
	, CONNECT_ONE_SHOT)
	# Queue redraw to the node
	node_2d.queue_redraw()

	var tex = node_2d.get_viewport().get_texture()
	draw_texture(tex, Vector2(100, 100))

The scene is:

Node2D
    SubViewport
        Node2D