Godot
Getting Started with Godot
Before jumping into VR, you should get yourself acquainted with the engine and how things work. Godot utilizes a node-based system, similar to Unity except everything is its own node.
Godot also has its own scripting language, GDScript, which is very similar to python. Most of the tutorials, guides, and resources you find online will make use of GDScript.
There is also support for C# which I recommend for both speed and consistency with the similarities with Unity. The C# community within Godot is growing fast as well.
Documentation
https://docs.godotengine.org/en/stable/index.html
Overview of Godot's key concepts
Your first 3D game
https://docs.godotengine.org/en/stable/getting_started/first_3d_game/index.html
Additional Resources
How to make a Video Game - Brackeys
Simple XR Rig
A lot has changed from the original version of this page. Below, I have linked the first article but you must follow all the chapters. These include:
- Introduction to the XR system in Godot
- Prerequisites for XR in Godot 4
- OpenXR
- Setting up the XR scene
Setting up OpenXR
https://docs.godotengine.org/en/stable/tutorials/xr/setting_up_xr.html
You may find the following two articles: Introduction to XR Tools and Basic XR Locomotion. These articles are valid but I would caution against using them and consider designing your own implementation and use these articles for reference only. If you have completed work in Unreal for things like teleportation, you will find there is a cross-over on making this work in Godot/Unity/etc. by translating the nodes into the APIs in the newer engine. I (Wes) am happy to assist.
VR Controller Input in Godot
Preface:
I use C# for coding in Godot due to the speed and resources (we need all the resources we can get when building with VR). Below is an example using C# but can be converted to GDScript as well.
For more information about C# in Godot:
https://docs.godotengine.org/en/stable/tutorials/scripting/c_sharp/c_sharp_basics.html
Getting Started
Assuming you have followed the previous tutorial and confirmed VR is working with controller visuals (even cubes) and OpenXR, you can get started.
By default, after installing OpenXR within Godot enables a default OpenXR Action Map. Typically, I leave these defaults alone. There is a good article in the documentation that reviews how to create your own custom inputs, but these work great.
The event structure on how you process this input is up to you! Below is an EXAMPLE but should be structured!
1. Create subscription events for ButtonPressed in Released.
Create a script on your XRController3D node (the VR controller) and the script should inherit from XRController3D.
Inside the script, create two override functions: _EnterTree() and _Exit Tree(). Add ButtonPressed and ButtonReleased and subscribe to a method. Here is the layout:
public override void _EnterTree()
{
ButtonPressed += OnButtonPressed;
ButtonReleased += OnButtonReleased;
}
public override void _ExitTree()
{
ButtonPressed -= OnButtonPressed;
ButtonReleased -= OnButtonReleased;
}
Now, create two functions, OnButtonPressed and OnButtonReleased:
void OnButtonPressed(string name)
{
}
void OnButtonReleased(string name)
{
}
2. Process events
You will notice on the methods created above that there is a parameter called string name. This string is what is received from your OpenXR Action Map (or anything else with a button). For me, I have added a switch statement to process these inputs and invoke methods:
void OnButtonPressed(string name)
{
switch (name)
{
case "grip_click":
OnGripPressed();
break;
case "trigger_click":
OnTriggerPressed();
break;
case "ax_button":
OnAXPressed();
break;
case "by_button":
OnBYPressed();
break;
}
}
void OnButtonReleased(string name)
{
switch (name)
{
case "grip_click":
OnGripReleased();
break;
case "trigger_click":
OnTriggerReleased();
break;
case "ax_button":
OnAXReleased();
break;
case "by_button":
OnBYReleased();
break;
}
}
I'm not including every single method, but you can see that I now have a system to process input!
3. Expand (with some Object Oriented Programming)!!
Obviously, this script would be a pain to copy for both hands and alter the names of the methods slightly. You can do this if you wish to keep it simple.
Object Oriented Programming (OOP):
For me, I created a parent script called something like XRHand.cs. Then, I created two scripts called LeftHand.cs and RightHand.cs that are children of XRHand. Using the methods above, I made them virtual so in my LeftHand.cs script for example, I can configure special implementation.
Here is the final script for XRHand.cs
using Godot;
using System;
public partial class XRHand : XRController3D
{
public override void _EnterTree()
{
ButtonPressed += OnButtonPressed;
ButtonReleased += OnButtonReleased;
InputFloatChanged += OnInputFloatChanged;
InputVector2Changed += OnInputVector2Changed;
}
public override void _ExitTree()
{
ButtonPressed -= OnButtonPressed;
ButtonReleased -= OnButtonReleased;
InputFloatChanged -= OnInputFloatChanged;
InputVector2Changed -= OnInputVector2Changed;
}
void OnButtonPressed(string name)
{
switch (name)
{
case "grip_click":
OnGripPressed();
break;
case "trigger_click":
OnTriggerPressed();
break;
case "ax_button":
OnAXPressed();
break;
case "by_button":
OnBYPressed();
break;
}
}
void OnButtonReleased(string name)
{
switch (name)
{
case "grip_click":
OnGripReleased();
break;
case "trigger_click":
OnTriggerReleased();
break;
case "ax_button":
OnAXReleased();
break;
case "by_button":
OnBYReleased();
break;
}
}
void OnInputFloatChanged(string name, double value)
{
}
void OnInputVector2Changed(string name, Vector2 value)
{
switch (name)
{
case "primary":
OnThumbstickMoved(value);
break;
}
}
// Digital Input
public virtual void OnGripPressed() { }
public virtual void OnGripReleased() { }
public virtual void OnTriggerPressed() { }
public virtual void OnTriggerReleased() { }
public virtual void OnAXPressed() { }
public virtual void OnAXReleased() { }
public virtual void OnBYPressed() { }
public virtual void OnBYReleased() { }
// Axial-1D Input
// Axial-2D Input
public virtual void OnThumbstickMoved(Vector2 value) { }
// Signals
}
And as for LeftHand.cs or RightHand.cs, I would just override a button that I would need:
using Godot;
using System;
public partial class LeftHand : XRHand
{
public override void OnGripPressed()
{
GD.Print("Right grip released!");
}
public override void OnGripReleased()
{
GD.Print("Left grip released!");
}
}
The LeftHand.cs and RightHand.cs would now go on their respective XRController3D nodes, in the scene.
Common 3D Features
This page consists of the culmination of the Brackeys video: How to make 3D Games in Godot. The video is not a tutorial, but a guide to common engine features like lighting, physics, materials, animations, and more. For convenience, video link and its times stamps are below:
How to make 3D Games in Godot (video)
3:35 3D Space
6:13 Greyboxing
9:31 Terrain
10:01 Playing the Game
11:11 Character Controller
14:15 3D Physics
16:10 Graphics
17:44 3D Assets in 1 min
18:45 Assets in Godot
22:38 StandardMaterial3D
26:53 Scene Workflows
30:53 Collision
32:57 Replace Greybox
35:43 Animated Characters
38:33 Speed up Workflow
39:24 Environment
42:00 Lighting
45:38 Tonemap
47:18 Camera
48:45 Render Quality