+4 votes

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?

in Engine by (5,200 points)

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

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.

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

But no luck.

1 Answer

+2 votes
Best answer

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)

by (27,778 points)
selected by

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.

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))

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

Thanks for taking some time to create that demo.

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.