I'm trying to create a SubViewport
in combination with a ViewportTexture
programmatically in Godot 4. My minimal example looks like this:
# This node is the root of my scene tree, and the only static node in the tree.
extends Node
func _ready():
# Create the viewport, add something to it, and add it to the scene tree:
# Note that setting UPDATE_ALWAYS doesn't help.
var viewport = SubViewport.new()
viewport.render_target_update_mode = SubViewport.UPDATE_ALWAYS
add_something_to_viewport(viewport)
add_child(viewport)
# Now that the viewport has a path, we can create a texture and connect it:
var viewport_texture = ViewportTexture.new()
viewport_texture.viewport_path = viewport.get_path()
# Finally create a sprite that uses the viewport texture:
var sprite = Sprite2D.new()
sprite.centered = false
sprite.texture = viewport_texture # <== this line causes debugger errors
add_child(sprite)
func add_something_to_viewport(viewport: SubViewport):
var label = Label.new()
label.text = "Hello world"
viewport.add_child(label)
(or with syntax highlighting for better readability)
Unfortunately the content of the viewport is not visible, and instead I'm seeing debugger errors like:
get_height: Viewport Texture must be set to use it
get_width: Viewport Texture must be set to use it
Initially I was suspecting this was a bug in Godot and raised this issue. A few helpful people pointed out that I simply misunderstood the role of setting the viewport_path
of a ViewportTexture
. Apparently this functionality is just used internally by the editor, and not the way you're supposed to connect a viewport texture with a viewport programmatically.
Fortunately, the solution is much simpler and even cleaner than going via the node path.
Instead of manually constructing the ViewportTexture
, one can simply call Viewport.get_texture()
to obtain the ViewportTexture
instance directly. This works fine for me:
extends Node
func _ready():
# Create the viewport, add something to it, and add it to the scene tree:
var viewport = SubViewport.new()
add_something_to_viewport(viewport)
add_child(viewport)
# Finally create a sprite that uses the viewport texture:
var sprite = Sprite2D.new()
sprite.centered = false
sprite.texture = viewport.get_texture() # Just get the texture directly.
add_child(sprite)
func add_something_to_viewport(viewport: SubViewport):
var label = Label.new()
label.text = "Hello world"
viewport.add_child(label)