Skip to content

Commit

Permalink
Add OpenXR demo project showing off local reference space
Browse files Browse the repository at this point in the history
  • Loading branch information
BastiaanOlij committed Jan 27, 2024
1 parent b74261c commit d256e73
Show file tree
Hide file tree
Showing 14 changed files with 580 additions and 0 deletions.
2 changes: 2 additions & 0 deletions xr/openxr_vehicle_movement/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Normalize EOL for all files that Git considers text files.
* text=auto eol=lf
2 changes: 2 additions & 0 deletions xr/openxr_vehicle_movement/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Godot 4+ specific ignores
.godot/
Binary file added xr/openxr_vehicle_movement/assets/pattern.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
35 changes: 35 additions & 0 deletions xr/openxr_vehicle_movement/assets/pattern.png.import
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
[remap]

importer="texture"
type="CompressedTexture2D"
uid="uid://rek0t7kubpx4"
path.s3tc="res://.godot/imported/pattern.png-cf6f03dfd1cdd4bc35da3414e912103d.s3tc.ctex"
metadata={
"imported_formats": ["s3tc_bptc"],
"vram_texture": true
}

[deps]

source_file="res://assets/pattern.png"
dest_files=["res://.godot/imported/pattern.png-cf6f03dfd1cdd4bc35da3414e912103d.s3tc.ctex"]

[params]

compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0
1 change: 1 addition & 0 deletions xr/openxr_vehicle_movement/icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
37 changes: 37 additions & 0 deletions xr/openxr_vehicle_movement/icon.svg.import
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
[remap]

importer="texture"
type="CompressedTexture2D"
uid="uid://d1s6lsinmhdj5"
path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://icon.svg"
dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"]

[params]

compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false
57 changes: 57 additions & 0 deletions xr/openxr_vehicle_movement/main.tscn
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
[gd_scene load_steps=11 format=3 uid="uid://db1q04xf4urua"]

[ext_resource type="Texture2D" uid="uid://rek0t7kubpx4" path="res://assets/pattern.png" id="1_sbpla"]
[ext_resource type="PackedScene" uid="uid://dkdk37kpjui3q" path="res://vehicle.tscn" id="2_x0meh"]
[ext_resource type="Script" path="res://start_vr.gd" id="3_d042y"]
[ext_resource type="PackedScene" uid="uid://du5twm6cwhq6j" path="res://track.tscn" id="4_ddbiu"]

[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_t0uks"]
sky_horizon_color = Color(0.64625, 0.65575, 0.67075, 1)
ground_horizon_color = Color(0.64625, 0.65575, 0.67075, 1)

[sub_resource type="Sky" id="Sky_f7epq"]
sky_material = SubResource("ProceduralSkyMaterial_t0uks")

[sub_resource type="Environment" id="Environment_ctbfb"]
background_mode = 2
sky = SubResource("Sky_f7epq")
tonemap_mode = 2

[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_jptbt"]
albedo_color = Color(0.211765, 0.717647, 0.160784, 1)
albedo_texture = ExtResource("1_sbpla")
uv1_scale = Vector3(100, 100, 100)

[sub_resource type="PlaneMesh" id="PlaneMesh_judwf"]
size = Vector2(1000, 1000)
subdivide_width = 10
subdivide_depth = 10

[sub_resource type="WorldBoundaryShape3D" id="WorldBoundaryShape3D_k6vqu"]

[node name="Main" type="Node3D"]

[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
environment = SubResource("Environment_ctbfb")

[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
transform = Transform3D(-0.866023, -0.433016, 0.250001, 0, 0.499998, 0.866027, -0.500003, 0.749999, -0.43301, 0, 0, 0)

[node name="Floor" type="StaticBody3D" parent="."]

[node name="MeshInstance3D" type="MeshInstance3D" parent="Floor"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.01, 0)
material_override = SubResource("StandardMaterial3D_jptbt")
mesh = SubResource("PlaneMesh_judwf")

[node name="CollisionShape3D" type="CollisionShape3D" parent="Floor"]
shape = SubResource("WorldBoundaryShape3D_k6vqu")

[node name="Vehicle" parent="." instance=ExtResource("2_x0meh")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -4.54837, 0.2, 0)

[node name="StartVR" type="Node3D" parent="."]
script = ExtResource("3_d042y")
maximum_refresh_rate = 144

[node name="Track" parent="." instance=ExtResource("4_ddbiu")]
34 changes: 34 additions & 0 deletions xr/openxr_vehicle_movement/openxr_action_map.tres
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
[gd_resource type="OpenXRActionMap" load_steps=7 format=3 uid="uid://b6o1742qdpkht"]

[sub_resource type="OpenXRAction" id="OpenXRAction_bxnsb"]
resource_name = "default_pose"
localized_name = "Default pose"
action_type = 3
toplevel_paths = PackedStringArray("/user/hand/left", "/user/hand/right")

[sub_resource type="OpenXRAction" id="OpenXRAction_e4g8i"]
resource_name = "haptic"
localized_name = "Haptic"
action_type = 4
toplevel_paths = PackedStringArray("/user/hand/left", "/user/hand/right")

[sub_resource type="OpenXRActionSet" id="OpenXRActionSet_ucgoy"]
resource_name = "godot"
localized_name = "Godot action set"
actions = [SubResource("OpenXRAction_bxnsb"), SubResource("OpenXRAction_e4g8i")]

[sub_resource type="OpenXRIPBinding" id="OpenXRIPBinding_xbpfq"]
action = SubResource("OpenXRAction_bxnsb")
paths = PackedStringArray("/user/hand/left/input/aim/pose", "/user/hand/right/input/aim/pose")

[sub_resource type="OpenXRIPBinding" id="OpenXRIPBinding_7tlrk"]
action = SubResource("OpenXRAction_e4g8i")
paths = PackedStringArray("/user/hand/left/output/haptic", "/user/hand/right/output/haptic")

[sub_resource type="OpenXRInteractionProfile" id="OpenXRInteractionProfile_1xkvk"]
interaction_profile_path = "/interaction_profiles/khr/simple_controller"
bindings = [SubResource("OpenXRIPBinding_xbpfq"), SubResource("OpenXRIPBinding_7tlrk")]

[resource]
action_sets = [SubResource("OpenXRActionSet_ucgoy")]
interaction_profiles = [SubResource("OpenXRInteractionProfile_1xkvk")]
54 changes: 54 additions & 0 deletions xr/openxr_vehicle_movement/project.godot
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
; Engine configuration file.
; It's best edited using the editor UI and not directly,
; since the parameters that go here are not all obvious.
;
; Format:
; [section] ; section goes between []
; param=value ; assign values to parameters

config_version=5

[application]

config/name="OpenXR Vehicle Movement"
run/main_scene="res://main.tscn"
config/features=PackedStringArray("4.1", "GL Compatibility")
config/icon="res://icon.svg"

[input]

turn_left={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":65,"key_label":0,"unicode":97,"echo":false,"script":null)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":2,"axis_value":-1.0,"script":null)
]
}
turn_right={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":68,"key_label":0,"unicode":100,"echo":false,"script":null)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":2,"axis_value":1.0,"script":null)
]
}
accelerate={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":87,"key_label":0,"unicode":119,"echo":false,"script":null)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":5,"axis_value":1.0,"script":null)
]
}
brake={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":83,"key_label":0,"unicode":115,"echo":false,"script":null)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":4,"axis_value":1.0,"script":null)
]
}

[rendering]

renderer/rendering_method="gl_compatibility"
renderer/rendering_method.mobile="gl_compatibility"

[xr]

openxr/enabled=true
openxr/reference_space=0
shaders/enabled=true
104 changes: 104 additions & 0 deletions xr/openxr_vehicle_movement/start_vr.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
extends Node3D

signal focus_lost
signal focus_gained
signal pose_recentered

@export var maximum_refresh_rate : int = 90

var xr_interface : OpenXRInterface
var xr_is_focussed = false


# Called when the node enters the scene tree for the first time.
func _ready():
xr_interface = XRServer.find_interface("OpenXR")
if xr_interface and xr_interface.is_initialized():
print("OpenXR instantiated successfully.")
var vp : Viewport = get_viewport()

# Enable XR on our viewport
vp.use_xr = true

# Make sure v-sync is off, v-sync is handled by OpenXR
DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_DISABLED)

# Connect the OpenXR events
xr_interface.connect("session_begun", _on_openxr_session_begun)
xr_interface.connect("session_visible", _on_openxr_visible_state)
xr_interface.connect("session_focussed", _on_openxr_focused_state)
xr_interface.connect("session_stopping", _on_openxr_stopping)
xr_interface.connect("pose_recentered", _on_openxr_pose_recentered)
else:
# We couldn't start OpenXR.
print("OpenXR not instantiated!")
get_tree().quit()


# Handle OpenXR session ready
func _on_openxr_session_begun() -> void:
# Get the reported refresh rate
var current_refresh_rate = xr_interface.get_display_refresh_rate()
if current_refresh_rate > 0:
print("OpenXR: Refresh rate reported as ", str(current_refresh_rate))
else:
print("OpenXR: No refresh rate given by XR runtime")

# See if we have a better refresh rate available
var new_rate = current_refresh_rate
var available_rates : Array = xr_interface.get_available_display_refresh_rates()
if available_rates.size() == 0:
print("OpenXR: Target does not support refresh rate extension")
elif available_rates.size() == 1:
# Only one available, so use it
new_rate = available_rates[0]
else:
for rate in available_rates:
if rate > new_rate and rate <= maximum_refresh_rate:
new_rate = rate

# Did we find a better rate?
if current_refresh_rate != new_rate:
print("OpenXR: Setting refresh rate to ", str(new_rate))
xr_interface.set_display_refresh_rate(new_rate)
current_refresh_rate = new_rate

# Now match our physics rate
Engine.physics_ticks_per_second = current_refresh_rate


# Handle OpenXR visible state
func _on_openxr_visible_state() -> void:
# We always pass this state at startup,
# but the second time we get this it means our player took off their headset
if xr_is_focussed:
print("OpenXR lost focus")

xr_is_focussed = false

# pause our game
process_mode = Node.PROCESS_MODE_DISABLED

emit_signal("focus_lost")


# Handle OpenXR focused state
func _on_openxr_focused_state() -> void:
print("OpenXR gained focus")
xr_is_focussed = true

# unpause our game
process_mode = Node.PROCESS_MODE_INHERIT

emit_signal("focus_gained")

# Handle OpenXR stopping state
func _on_openxr_stopping() -> void:
# Our session is being stopped.
print("OpenXR is stopping")

# Handle OpenXR pose recentered signal
func _on_openxr_pose_recentered() -> void:
# User recentered view, we have to react to this by recentering the view.
# This is game implementation dependent.
emit_signal("pose_recentered")
37 changes: 37 additions & 0 deletions xr/openxr_vehicle_movement/track.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
@tool
extends Path3D

@export var tire_spacing : float = 0.5:
set(value):
tire_spacing = value
if is_inside_tree():
_update_tires()

func _update_tires():
var multimesh : MultiMesh = $Tirewall.multimesh

# Cheap and dirty approach, need to improve this!
var track_length = curve.get_baked_length()
var tires_per_side = floor(track_length / tire_spacing)
var offset = 0.0

multimesh.instance_count = tires_per_side * 2
for tire in range(tires_per_side):
var t : Transform3D = curve.sample_baked_with_rotation(offset)

var t_adj : Transform3D = t
t_adj.origin += t_adj.basis.x * 5.0
multimesh.set_instance_transform(tire, t_adj)

t_adj = t
t_adj.origin -= t_adj.basis.x * 5.0
multimesh.set_instance_transform(tires_per_side + tire, t_adj)

offset += tire_spacing

# Called when the node enters the scene tree for the first time.
func _ready():
_update_tires()

if Engine.is_editor_hint():
curve_changed.connect(_update_tires)
Loading

0 comments on commit d256e73

Please sign in to comment.