Viewports, Windows, and Worlds in Godot 4

Jonas Hundertmark
medialesson
Published in
4 min readMar 6, 2024

Today we’ll be diving a little deeper into the Viewport system in Godot and how to manipulate it to fit your needs. We need to cover a bit of ground before we get to the really juicy stuff but it’s worth it, I promise.

So what is a Viewport, anyway?

When talking about viewports, we first need to understand the Problem Viewports are trying to solve. Imagine a Game World with a Camera inside it, filming a particular part of that world. Generally speaking, we want to display that image in our display window in some form. In the easiest scenario, exactly how the camera sees it

Please enjoy my scentifically accurate depictions of game worlds and -cameras

Oftentimes, however, a simple camera image is not enough. We want to display a HUD over the camera, maybe a Minimap or a top-down view from a different camera. Sometimes we want to display Camera images inside the game world itself as textures (for instance a rear-view mirror in a racing simulation, which is just a second camera rendering its image on top of the mirror’s mesh as a texture). This is where compositing comes in, and it’s the problem Viewports are trying to solve.

How Viewports work

In Godot, a camera image is always rendered inside of a Viewport first. This Viewport itself is not an object you can display, it simply holds the current image of your camera(s). Think of it as a buffer for your camera images. You can then freely choose where that image is going to be displayed: A Window Node (which is a child of Viewport itself) will naturally display its (inherited) Viewport’s contents. Alternatively, you can create a so-called SubViewport Node, which simply holds image data for later use by a Viewport Texture and the likes.

I swear this is kind of how it works.

Since your Godot Scene Tree already starts with a Window (i.e. die Game Window), Godot’s Viewport system is totally invisible to the developer, up until the moment you need to fully leverage its features. It holds all the flexibility you might need, but it doesn’t introduce unneccesary overhead if you just need to display a simple scene.

One common pitfall for new Godot developers is that whenever you create a new Viewport, that Viewport has no coordinate system and no position in 3D space. It simply holds information. If you want to display that information somewhere, you need to create another object in 3D space (like a Sprite3D Node or a Mesh with a ViewportTexture) and assign the SubViewport as your image source.

Viewports and Worlds

Especially astute readers might have already noticed an interesting problem. If a Viewport holds no positional information itself, where are 3D transforms inside it located? Say we position a sphere with radius 0.5 at coordinates (0, 0, -5) and another sphere that is the child of a SubViewport at coordinates (2, 0, –5), will a camera positioned at origin and looking straight down Z- see one or two spheres?

Generally, the answer would be two. But it doesn’t have to be! You can treat everything going on inside the SubViewport as it’s own completely seperate World, with its own geometry, WorldEnvironment, physics space, and coordinate system.

This is especially useful when you want to simulate two different large levels at the same time without moving one of them 10.000-something units to the left, potentially running into floating point errors in the process. You can, in theory, have an unlimited number of Worlds with an arbitrary number of Viewports looking into them at runtime. References to Worlds can be passed through the world_3d and occasionally the world_2d property via scripts, although this is generally more useful for 3D Worlds.

Worlds are an additional layer of complexity that, truth be told, I’d rather see as its own Node. But I can understand why they get bundled into the Viewport Node instead.

I’ll leave you with another riddle. Let’s come back to the two spheres example we had earlier, and add another Camera3D Node, this time as a child of the SubViewport like this:

Same coordinates as the first camera. Center at origin (0, 0, 0) looking straight down the Z- axis. How many spheres does this camera see?

If you think you know the answer, try rebuilding the Scene in Godot to check! If you got it right, try displaying the Image from your Viewport alongside the first camera image. Play around with the position of the Camera Nodes and the Worlds a bit until you really understand how everything plays together.

Until next time!

--

--