Viewport in Godot – Complete Guide

Viewports are gateways to creativity in game development, offering an innovative way to render various parts of a game either to separate windows or within textures. They’re a cornerstone of visual presentation, enabling developers to think outside the proverbial two-dimensional box and leap into dynamic rendering techniques. From creating minimaps to intricate multi-camera setups, viewports empower you to architect your game’s visual output with finesse and precision.

What is a Viewport in Godot?

In Godot 4, a Viewport is a powerful node type that controls how portions of the game world are rendered and displayed. It’s effectively a canvas where your game’s content, whether 2D or 3D, comes to life before being presented to the player.

  • Custom Rendering: By default, anything drawn within a Viewport’s boundaries can appear in the game window or another pre-defined area, allowing for a wide range of visual effects.
  • Worlds Within Worlds: Whether you wish to render a star-studded skybox or a bustling NPC crowd in a sideline game, Viewports can encapsulate these details, maintaining their own render canvas and environment settings independently of the main game scene.

Why Use Viewports?

The use of Viewports in game development extends beyond mere rendering niches; it’s a versatile tool designed to enhance interaction and player immersion.

  • Decoupled Rendering: By enabling separate render worlds, you can display different scenes or control visual elements without the need to overhaul your main scene structure.
  • Performance Flexibility: Viewports let you control rendering costs by confining high-detail assets to small portions of the screen or optimizing separate render passes differently.

How Will This Benefit Your Game Development Skills?

Mastering Viewports is akin to unlocking a new dimension in your game development skill set. Learning to use them effectively means providing yourself with the capability to construct complex games that handle diverse scenarios gracefully and engagingly. Every creative choice, from the strategic placement of UI elements to the creation of distinctive gameplay mechanics, becomes more accessible and more potent when you’re adept at leveraging the functionality of the Godot Viewport class.

CTA Small Image
FREE COURSES AT ZENVA
LEARN GAME DEVELOPMENT, PYTHON AND MORE
ACCESS FOR FREE
AVAILABLE FOR A LIMITED TIME ONLY

Creating and Configuring a Viewport

To start utilizing viewports in your Godot project, the first step is to create and configure them. Let’s begin by adding a viewport to our scene tree.

var my_viewport = Viewport.new()
add_child(my_viewport)

With the Viewport added, we now need to set its size. This determines the resolution at which the content within the Viewport will be rendered:

my_viewport.size = Vector2(1024, 768)

Next, for rendering 3D content, you need to attach a Camera to the Viewport. Here’s how you do it:

var camera = Camera.new()
my_viewport.add_child(camera)
my_viewport.camera = camera

Note that for 2D content, this step is not necessary as the Viewport will render all 2D nodes by default.

Using a Viewport as a Render Texture

A common use of Viewports is as a render texture; for example, you might render a scene to a texture that you later use for an in-game monitor or a mini-map. To do this, you need to set ‘render_target’ to ‘true’ on your Viewport:

my_viewport.render_target = true

Once the Viewport is set up as a render target, you can access the resulting image with ‘get_texture()’:

var texture = my_viewport.get_texture()

You can now use the texture on any node that uses textures, like a Sprite or TextureRect:

var sprite = Sprite.new()
sprite.texture = texture
add_child(sprite)

This setup is excellent for dynamic textures that update in real-time, such as a player character’s view on an in-game screen.

Managing Multiple Views

In many games, especially strategy and simulation games, you may want to display multiple views of the game world at once. Here’s an example of how to set this up with two side-by-side Viewports:

var left_viewport = Viewport.new()
var right_viewport = Viewport.new()

left_viewport.size = Vector2(512, 768)
right_viewport.size = Vector2(512, 768)

left_viewport.rect_position = Vector2(0, 0)
right_viewport.rect_position = Vector2(512, 0)

add_child(left_viewport)
add_child(right_viewport)

With these two Viewports side by side, you could render different scenes, or the same scene from different angles, providing a unique visual experience for the player.

Handling Input in Multiple Viewports

When using multiple Viewports, you may want to handle inputs separately for each. This can be done by setting ‘input_pass_on’ to ‘false’ on the Viewport:

my_viewport.input_pass_on = false

Now, you’ll need to manually handle the input for this Viewport by connecting to the ‘gui_input’ signal or overriding the ‘_input’ function:

my_viewport.connect("gui_input", self, "_on_viewport_input")
# OR
func _unhandled_input(event):
    if my_viewport.get_rect().has_point(event.position):
        # Handle the input event

This setup ensures that each Viewport can react independently to user inputs, which is particularly crucial when dealing with UIs or interactive elements within multiple Viewports.

Through these examples, you’ve seen how essential features of Viewports in Godot work. You’re now well on your way to implementing sophisticated rendering solutions for your games, leveraging the full power of Godot’s Viewport capabilities.

In the next part of our tutorial, we’ll delve deeper into advanced Viewport concepts such as ViewportContainers, layering, and using Viewports for post-processing effects.

Expanding our knowledge further on viewports, we’ll look at some advanced concepts such as embedding viewports within our UI using ViewportContainers, setting up layers, and using viewports to create post-processing effects.

Firstly, let’s integrate a Viewport into our UI, which can be particularly useful for creating rendered previews or interactive elements that are part of the UI:

var viewport_container = ViewportContainer.new()
var my_viewport = Viewport.new()

my_viewport.size = Vector2(256, 256)
viewport_container.add_child(my_viewport)
add_child(viewport_container)

viewport_container.rect_min_size = my_viewport.size

This code snippet demonstrates the steps for embedding a Viewport within a GUI. The ViewportContainer node will automatically resize to the dimensions of the contained Viewport, allowing for seamless integration within the UI.

Next, let’s consider layer management within a Viewport. Godot provides functionality to render different elements on separate layers. This can be useful to control the rendering order or to isolate certain elements from post-processing effects:

var sprite = Sprite.new()
var background = Sprite.new()

sprite.z_index = 1
background.z_index = 0

my_viewport.add_child(background)
my_viewport.add_child(sprite)

In this example, the sprite will render above the background due to its higher ‘z_index’. Layering is a simple yet powerful concept, enabling developers to create complex visual hierarchies.

Now, let’s discuss how to use a Viewport for post-processing effects. By drawing the Viewport’s content onto a full-screen quad and applying a shader, we can add effects such as blur or color grading:

var screen_texture = my_viewport.get_texture()
var screen_quad = QuadMesh.new()
var shader_material = ShaderMaterial.new()
var viewport_quad = MeshInstance2D.new()

shader_material.shader = preload("res://my_shader.shader")
shader_material.set_shader_param("screen_texture", screen_texture)

viewport_quad.mesh = screen_quad
viewport_quad.material = shader_material

add_child(viewport_quad)

Here we preload a custom shader that will process ‘screen_texture’. We then create a MeshInstance2D with a QuadMesh and apply our ShaderMaterial to it. When added to the scene, the quad will be drawn using our custom shader, effectively applying the post-processing effect.

Understanding the use of multiple viewports can also facilitate the creation of separate render pipelines, for example, setting up a view for reflections:

var reflection_viewport = Viewport.new()
var reflection_scene_instance = preload("res://reflection_scene.tscn").instance()

reflection_viewport.size = Vector2(512, 256)
reflection_viewport.environment = preload("res://reflection_env.tres")
reflection_viewport.add_child(reflection_scene_instance)

var reflection_texture = reflection_viewport.get_texture()

# You can now use reflection_texture as a dynamic reflection map

In this snippet, we create a new Viewport for rendering our reflection scene at a reduced resolution to optimize performance. We assign it a specific environment to simulate reflective lighting conditions, and we retrieve its texture to be used elsewhere, possibly as a dynamic texture on a water surface in our main scene.

Lastly, let’s talk about handling multiple screens for local multiplayer games. Viewports can render different player perspectives, providing a seamless local co-op or competitive experience:

for i in range(number_of_players):
    var player_viewport = Viewport.new()
    var player_camera = Camera.new()
    
    player_viewport.size = get_viewport_rect().size / 2
    player_viewport.position = Vector2((i % 2) * player_viewport.size.x, (i / 2) * player_viewport.size.y)
    
    player_camera.current = true
    player_viewport.add_child(player_camera)
    
    add_child(player_viewport)

    var player_scene = preload("res://player_scene.tscn").instance()
    player_scene.set_owner(player_viewport)
    player_camera.add_child(player_scene)

This example sets up viewports for a two-player game, each with its own camera and rendered scene. It positions the viewports side by side (or top and bottom), depending on the number of players, to split the screen accordingly.

Armed with the powerful features of Godot’s Viewport node, your creativity can truly flourish. Implementing these practices can add depth and polish to your projects, enhancing the gaming experience while affording you greater control over the visual aspects of your game.

With these examples, you’re well-equipped to create complex and visually appealing systems in Godot. Keep experimenting with viewports to find innovative solutions for your game development challenges!

With a grasp of viewports and their basic use cases, we can step further into the realm of multi-camera setups, screen-to-world transformations, and viewport signals which can elevate the interactivity and flexibility in your Godot games.

Creating multi-camera setups can be essential for real-time strategy games or simulations that require an overview and a detailed view simultaneously. Here’s a quick rundown on setting up a secondary camera with Godot:

var main_viewport = get_viewport()
var overview_camera = Camera.new()

main_viewport.add_child(overview_camera)
overview_camera.current = true

This assigns a new camera as the current camera for the main viewport. To switch between cameras, simply change the ‘current’ property:

func _on_switch_camera_button_pressed():
    overview_camera.current = !overview_camera.current

Another powerful feature is transforming screen coordinates to world coordinates, a common requirement for gameplay mechanics like object placement or touch interactions:

func _input(event):
    if event is InputEventMouse:
        var mouse_event = event as InputEventMouse
        var mouse_position = mouse_event.position
        var world_position = my_viewport.get_camera().unproject_position(mouse_position)
        # Now world_position will hold the 3D coordinate of the location under the cursor

Viewport signals are also essential to manage interactivity within your game. Godot’s viewports emit signals like ‘size_changed’, letting you react to changes in viewport dimensions:

func _ready():
    my_viewport.connect("size_changed", self, "_on_viewport_size_changed")

func _on_viewport_size_changed():
    print("The viewport size has changed")

Lastly, while Viewport nodes are powerful, they do have limitations. If a developer needs to create layers of UI elements that overlay 3D or 2D game worlds, the UI should be handled by a CanvasLayer. This ensures that the UI always draws over the game world and can respond to user inputs correctly. Here’s how to instantiate a CanvasLayer programmatically:

var my_canvas_layer = CanvasLayer.new()
my_canvas_layer.layer = 1
add_child(my_canvas_layer)

var my_ui = preload("res://my_ui_scene.tscn").instance()
my_canvas_layer.add_child(my_ui)

This code snippet adds a new CanvasLayer on top of everything else (‘layer = 1’) and then attaches the UI scene to it.

Rendering 3D objects onto a 2D plane in your game can create unique visuals or interfaces, like a 3D character that appears on a flat GUI panel. The snippet below demonstrates how to render a 3D model within a 2D environment:

var my_3d_viewport = Viewport.new()
my_3d_viewport.size = Vector2(128, 128)
var my_3d_scene = preload("res://my_3d_model.tscn").instance()
my_3d_viewport.add_child(my_3d_scene)
my_3d_viewport.render_target = true

var my_texture_rect = TextureRect.new()
my_texture_rect.texture = my_3d_viewport.get_texture()

add_child(my_texture_rect)

These operations provide a foundation to innovatively play with rendering and interaction possibilities in Godot. With this versatile toolset, your game can feature complex UI systems, interactive game worlds, and multitasking visuals that complement your gameplay mechanics.

By getting comfortable with viewports and responding to the various needs of your game’s architecture, you solidify your ability to be a flexible and problem-solving game developer. Dive into Godot’s documentation, experiment with different setups, and see how viewports can inspire new ideas for your game development projects!

Embark on Your Game Development Journey

As you master the intricacies of viewports in Godot, your journey in game development is only beginning. The ability to control the camera, render, and interact with game environments opens endless possibilities. To continue refining your skills and learn how to build your own 2D and 3D games, explore our Godot Game Development Mini-Degree. It’s an in-depth curriculum designed to take you from the basics to crafting your custom gameplay experiences with Godot, all at your own pace and accessible on any device.

When you’re ready to delve into a broader spectrum of topics and projects, our comprehensive collection of Godot courses awaits. These lessons will bolster your skill set, whether you’re a beginner aiming to become a professional or an experienced developer seeking to deepen your expertise.

At Zenva, we believe in equipping aspiring developers with the tools they need to thrive in this exciting and growing field. Join us, and take your first step towards cementing your place in the vibrant world of game development.

Conclusion

Diving deep into viewports is just the tip of the iceberg in the expansive universe of game development with Godot. From intricately layered worlds to highly interactive gameplay elements, the skills you acquire here can be the cornerstone of your future creations. As you continue to build, refine, and innovate, remember that every game developer’s path is a collection of small achievements leading to grand triumphs.

We at Zenva are excited to be part of your journey, offering guidance, knowledge, and inspiration every step of the way. Unlock your full potential by continuing your learning adventure with our Godot Game Development Mini-Degree. Shape your dreams into reality, one line of code, one node, and one viewport at a time. The world of game development awaits, and we can’t wait to see what you’ll create!

FREE COURSES
Python Blog Image

FINAL DAYS: Unlock coding courses in Unity, Godot, Unreal, Python and more.