+1 vote

I'm trying to dynamically create a Viewport, render to it, fetch its contents (as a texture), and discard it again. As a basic test I'm using this script attached to a plain Node2D root node (nothing else in the scene tree):

extends Node2D

func _ready():
    # Create viewport
    var viewport = Viewport.new()
    viewport.size = Vector2(200, 200)

    # Create some test content
    var rect = ColorRect.new()
    rect.color = Color(1, 0, 0)
    rect.rect_size = Vector2(100, 100)

    # Add to scene
    viewport.add_child(rect)
    add_child(viewport)

    # Wait for content
    yield(get_tree(), "idle_frame")
    yield(get_tree(), "idle_frame")

    # Fetch viewport content
    var texture = viewport.get_texture()
    var image = texture.get_data()
    image.save_png("test.png") # just as a debugging check

This works in the sense that the I do get a "test.png" output file. However, the file is just black -- it looks like nothing has been rendered to the viewport. If I add the test content (the rect) directly as a child it renders fine.

What am I missing that I'm not getting any output from the viewport?

asked Dec 14, 2019 in Engine by bluenote (24 points)

maybe you could try

#Add to scene
viewport.add_child(rect)
rect.show()
add_child(viewport)

@Klagsam Thanks for the suggestion. Unfortunately that doesn't seem to make a difference for me. Does it work for you?

I did not try it. I just had a similar problem which i could solve by adding that line.

1 Answer

+1 vote
Best answer

you need to add one of the following lines after creating your viewport variable

viewport.render_target_update_mode =Viewport.UPDATE_ONCE

or

viewport.render_target_update_mode =Viewport.UPDATE_ALWAYS

(before edit)
I believe you need to add a Camera2D as well beneath your Viewport

as each viewport renders from the child camera beneath it (am not 100% sure tho)

answered Dec 14, 2019 by Xtremezero (288 points)
selected Dec 15, 2019 by bluenote

I tried that as well, but it doesn't make a difference. Also, I've seen many (working) examples of viewports without explicit sub-cameras. My understanding is that they come with an implicit camera (much like the root viewport), but if there is an explicit camera that one is preferred.

omg I was so idiot :/ you need to change the update_mode

viewport.rendertargetupdatemode =Viewport.UPDATEONCE
or
viewport.rendertargetupdatemode =Viewport.UPDATEALWAYS

extends Node2D

func _ready():
     # Create viewport
    var viewport = Viewport.new()
    viewport.size = Vector2(200, 200)
    viewport.render_target_update_mode =Viewport.UPDATE_ALWAYS
    #var cam = Camera2D.new()
    #viewport.add_child(cam) 

    # Create some test content
    var rect = ColorRect.new()
    rect.color = Color(1, 0, 0)
    rect.rect_size = Vector2(100, 100)

    # Add to scene
    viewport.add_child(rect)
    add_child(viewport)

    # Wait for content
    yield(get_tree(), "idle_frame")
    yield(get_tree(), "idle_frame")

    # Fetch viewport content
    var texture = viewport.get_texture()
    var image = texture.get_data()
    image.save_png("test.png") # just as a debugging check

That's it, indeed the default of UPDATE_WHEN_VISIBLE implies that the viewport is simply not active. Thanks a lot!

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.