Quick answer: Check for a camera inside the SubViewport, a non-zero size, and render_target_update_mode set to UPDATE_ALWAYS or UPDATE_WHEN_VISIBLE. Blank ViewportTexture is almost always a missing camera or an update mode that never ticks.

Here is how to fix Godot SubViewport texture blank or black. You want a picture-in-picture minimap, a 3D model preview in a menu, or a rear-view mirror. You add a SubViewport, put a camera in it, point at the scene, and assign the ViewportTexture to a Sprite. The sprite is black. You change render modes, swap cameras, tweak sizes — still black. Godot 4’s viewport pipeline has several places where a single wrong setting produces empty output with no error message.

The Symptom

A Sprite, TextureRect, or mesh material that uses a ViewportTexture renders as a solid color — black most commonly, sometimes the scene background color. No shader error, no missing texture warning. The SubViewport node exists in the scene tree. The camera inside it exists. You can even see the SubViewport preview in the editor if you select it — which is especially confusing because the preview looks correct while the ViewportTexture does not.

What Causes This

No camera inside the SubViewport. A SubViewport needs its own camera (Camera2D for 2D scenes, Camera3D for 3D). The camera must be a descendant of the SubViewport. If you drop a Camera3D outside the SubViewport subtree, it does not affect the SubViewport’s rendering. The SubViewport has no “where to look” and renders black.

render_target_update_mode set to UPDATE_DISABLED. By default, new SubViewports are UPDATE_WHEN_VISIBLE, which is correct. But if you set it to UPDATE_DISABLED (to save performance and update manually), the texture never updates and stays black. Calling SubViewport.update() manually is needed to re-render.

Size is 0x0. A SubViewport with size Vector2i(0, 0) renders nothing. Size defaults to something reasonable when you add the node in the editor, but if you instance it from code and forget to set size, it stays 0x0. Set size = Vector2i(width, height) on creation.

Not in the scene tree. A SubViewport that is instantiated but not added to the scene tree cannot render. You have to add_child it to something that is in the tree (usually a SubViewportContainer or the root).

ViewportTexture path wrong. When you create a ViewportTexture resource, it has a Viewport Path property. If that path does not resolve to a SubViewport node at runtime (wrong path, node renamed, scene structure changed), the texture silently returns black.

Camera current not set. Multiple cameras in a SubViewport require one to be marked current = true. If none is current, the SubViewport picks one arbitrarily or renders nothing depending on Godot version.

The Fix

Step 1: Build the scene correctly. Here is a minimal working minimap setup:

- Main (Node2D)
    - Game (Node2D)           # Your main gameplay
    - MinimapContainer (SubViewportContainer)
        - SubViewport (size: 256x256, update mode: Always)
            - Camera2D (current: true, zoom: 0.1, 0.1)
            - RemoteTransform2D # follows the player

The SubViewportContainer automatically creates the texture and applies it to its own rendering. Size the container to match or scale the SubViewport output.

Step 2: Ensure the camera is inside the SubViewport. Drag the camera node into the SubViewport in the scene tree. Confirm the camera is a direct or indirect child. If you need the camera to follow something in the main scene, use a RemoteTransform2D to proxy its position rather than placing it in the main scene.

Step 3: Set render target update mode. For constant updates (minimap, mirror), set render_target_update_mode = UPDATE_ALWAYS. For performance, UPDATE_WHEN_VISIBLE is usually better — it only renders when the texture is displayed. UPDATE_DISABLED is only for cases where you manually trigger updates.

extends SubViewport

func _ready():
    render_target_update_mode = SubViewport.UPDATE_WHEN_VISIBLE
    # Or UPDATE_ALWAYS if you need constant updates

Step 4: Use SubViewportContainer for simple cases. If you just want to display the SubViewport’s output as a UI element, put it inside a SubViewportContainer — Godot handles the texture path automatically.

If you need the output on a Sprite2D or a 3D mesh, create a ViewportTexture explicitly: select the Sprite2D, click Texture, choose “New ViewportTexture,” and in the ViewportTexture Inspector, browse to your SubViewport path.

Transparent Background

For an overlay that should not cover the main scene, enable transparency:

extends SubViewport

func _ready():
    transparent_bg = true

For 3D SubViewports, the camera’s environment matters. If the camera has an Environment with a Sky background, the sky renders and defeats the transparency. Either set the environment’s background to “Clear Color” with alpha 0, or remove the environment. Also check that no WorldEnvironment node is present in the SubViewport; WorldEnvironment affects everything rendered by cameras in the same scene tree.

Performance Note

A SubViewport is essentially a second camera rendering an entire scene. If your minimap shows your whole level, it doubles your render cost. Use UPDATE_WHEN_VISIBLE to skip rendering when the minimap is hidden, reduce SubViewport resolution (a 256x256 minimap does not need 1080p), and consider lower-quality settings inside the SubViewport (no post-processing, fewer shadows).

Debugging Steps

If the viewport is still blank after all fixes:

  1. Print SubViewport.get_texture().get_image() to confirm the texture has real data. If the image is all black pixels, the viewport is not rendering. If it has content but your sprite is black, the path binding is wrong.
  2. Set the SubViewport’s background_color to bright red. If red shows up on your sprite, the viewport is rendering but your camera sees nothing.
  3. Temporarily make the SubViewport’s world visible by swapping your main scene with it briefly — if the camera shows nothing in that case, the camera is pointed wrong.

“A SubViewport is its own miniature game. Scene tree, camera, update mode, size — all the normal rules apply, inside the viewport.”

Related Issues

For navigation-specific issues, see Godot Navigation Region Not Connecting. For signal handling bugs, GDScript Await Signal Never Completing covers related async patterns.

Camera inside, size non-zero, update mode set, path correct. Four checks for a working SubViewport.