Is there method to use canvas drawing on top of the buffer of the previous?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By avencherus
:warning: Old Version Published before Godot 3 was released.

I’d like to call some draw commands, but at some later time overlay some others on top. However, the _draw() method gets called through update(), and this seems to clear the buffer.

Is there a way to retain a canvas drawing and continue to draw on top of it without clearing it?

Like drawing on a viewport and creating a texture from it?

Look if it have what you need or something close to it:
http://docs.godotengine.org/en/latest/tutorials/engine/viewports.html

eons | 2016-10-19 20:19

I suppose that’s a possibility, but I was hoping to just not clear the canvas when I need to use a draw function.

Maybe it’s not possible though.

avencherus | 2016-10-19 20:21

Look at the render modes
Viewport — Godot Engine (latest) documentation in English

eons | 2016-10-19 22:17

I tried this get_viewport().set_render_target_update_mode(Viewport.RENDER_TARGET_UPDATE_DISABLED)

But no luck.

avencherus | 2016-10-19 22:24

:bust_in_silhouette: Reply From: Zylann

If you need to physically accumulate the drawings, I would see two options:

  1. memorize drawings in a list of draw commands, so you can re-draw everything when the node needs to be updated

  2. Use a RenderTexture to accumulate the drawings. However I have no idea how it would work in the 2D engine, I suppose you can have a secondary Viewport with a RenderTexture as target, disable frame clearing, then you would use that texture in the main viewport to display it. (and of course, as I am trying that right now, it lamentably fails… EDIT I found it, getting there. I’ll maybe show an example if I get it to work :D)

Quite right.

I got something running with method 2, but I had to hook a viewport sprite into it to see the results, since my node was put as a child of the viewport and it doesn’t quite show what’s going on.

I’d still like to see what you come up with.

I’m wondering now the best way to set it up though.

avencherus | 2016-10-19 22:18

I came up with this test script.
It’s only a demo, you may want to adapt it to be easier to re-use.

extends Node

var _chalk = null


func _ready():
	# Create the viewport
	var viewport = Viewport.new()
	# Make it so it renders on a texture
	viewport.set_as_render_target(true)
	# Set the size of it
	viewport.set_rect(Rect2(0,0,256,256))
	
	# I tried to set the background color, but none of this worked...
#	var world = World.new()
#	var env = Environment.new()
#	env.set_background(Environment.BG_COLOR)
#	env.set_background_param(Environment.BG_PARAM_COLOR, Color(0,0,0))
#	world.set_environment(env)
#	viewport.set_world(world)
#	viewport.set_use_own_world(true)

	# Don't clear the frame when it gets updated so it will accumulate drawings
	viewport.set_render_target_clear_on_new_frame(false)
	
	add_child(viewport)

	# Create a sprite to serve as a "drawer"
	_chalk = Sprite.new()
	_chalk.set_texture(preload("icon.png"))
	_chalk.set_pos(viewport.get_rect().size/2.0)
	viewport.add_child(_chalk)
	
	# Use a sprite to display the result texture
	var rt = viewport.get_render_target_texture()
	var board = Sprite.new()
	board.set_texture(rt)
	board.set_pos(Vector2(100,100))
	add_child(board)
	
	set_process(true)


func _process(delta):
	_chalk.rotate(delta)
	var s = sin(OS.get_ticks_msec()/1000.0)+1.2
	_chalk.set_scale(Vector2(s,s))

Zylann | 2016-10-19 23:51

Very nice, exactly the kind of effects I’m looking into recreating in Godot.

Thanks for taking some time to create that demo.

avencherus | 2016-10-20 00:40