0 votes

Hi all
I want to make a 2D painting game, so I want my canvas to not update on every frame.
I have node2D and this is what I did
func _ready(): get_tree().get_root().set_render_target_update_mode(1)
but it is not working.

also I tried this
func _ready(): get_tree().get_root().set_render_target_clear_on_new_frame(false)
the drawing persist, but the screen keep flickering!

note: in godot3 the code bellow works fine, but the engine is crashing under ubuntu so I cannot use it now
func _ready(): get_tree().get_root().render_target_clear_mode = 2

in Engine by (25 points)

I made an example project for this but I don't have it right now, need to get back home first.
Basically you can use a secondary viewport and accumulate whatever drawable stuff you want in it by disabling clear

1 Answer

+2 votes
Best answer

Here is an example script in Godot 2 that lets you paint ont a Control node:

Project: http://zylannprods.fr/dl/godot/ChalkBoard.zip

extends Control

var _pen = null
var _prev_mouse_pos = Vector2()


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
    var rect = get_rect()
    viewport.set_rect(Rect2(0, 0, rect.size.x, rect.size.y))

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

    _pen = Node2D.new()
    viewport.add_child(_pen)
    _pen.connect("draw", self, "_on_draw")

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

    # Use a TextureFrame to display the result texture (because pivot is top-left)
    var rt = viewport.get_render_target_texture()
    var board = TextureFrame.new()
    board.set_texture(rt)
    add_child(board)

    set_process(true)


func _process(delta):
    _pen.update()


func _on_draw():
    var mouse_pos = get_local_mouse_pos()

    if Input.is_mouse_button_pressed(BUTTON_LEFT):
        _pen.draw_line(mouse_pos, _prev_mouse_pos, Color(1, 1, 0))

    _prev_mouse_pos = mouse_pos
by (28,835 points)
selected by

hi Zylann, your ChalkBoard demo is work well in godot 2.0 but how it works in godot 3.0?

It's almost the same, I managed to make it work in Godot 3 like this:

Project: http://zylannprods.fr/dl/godot/godot3/ChalkBoard.zip

extends Control

var _pen = null
var _prev_mouse_pos = Vector2()


func _ready():
    var viewport = Viewport.new()
    var rect = get_rect()
    viewport.size = rect.size
    viewport.usage = Viewport.USAGE_2D
    # Note: I also tried CLEAR_MODE_NEVER but it doesn't draw anything.
    # (see issue https://github.com/godotengine/godot/issues/20775)
    viewport.render_target_clear_mode = Viewport.CLEAR_MODE_ONLY_NEXT_FRAME
    viewport.render_target_v_flip = true

    _pen = Node2D.new()
    viewport.add_child(_pen)
    _pen.connect("draw", self, "_on_draw")

    add_child(viewport)

    # Use a sprite to display the result texture
    var rt = viewport.get_texture()
    var board = TextureRect.new()
    board.set_texture(rt)
    add_child(board)


func _process(delta):
    _pen.update()


func _on_draw():
    var mouse_pos = get_local_mouse_position()

    if Input.is_mouse_button_pressed(BUTTON_LEFT):
        _pen.draw_line(mouse_pos, _prev_mouse_pos, Color(1, 1, 0))

    _prev_mouse_pos = mouse_pos

thanks Zylann.
It's works well!

Hi Zylann,
I saw you tried a few different methods to change the background for your chalkboard that were all unsuccesful. Have you found out a way to do it yet? I am creating a notepad type app in godot and wanted the ability to draw in a textbox. I tried overlaying a control node with your sample script over the textbox but then the text is covered up as well. Is there a way to make the background transparent?

Hey kingpinpenguin,

Almost a year late and I'm not Zylann, but I've got a solution. Put this anywhere before adding "viewport" as a child in _ready():

viewport.set_transparent_background(true)
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 Frequently asked questions and 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.