Skip to content

Commit 7cd6a13

Browse files
committed
Initialize WebXR.
Following the guide in the WebXRInterface documentation. Initializes, but fails in Chrome because of missing support for 'layers'.
1 parent 484bf79 commit 7cd6a13

2 files changed

Lines changed: 113 additions & 1 deletion

File tree

scenes/main.gd

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,16 @@ const FADE_TIME : float = 0.2
4242
var music_fade_tween : Tween
4343

4444
var xr_interface : XRInterface
45+
## If WebXR, this is equal to [member xr_interface], but cast to a more specific
46+
## type. If not, null.
47+
var webxr_interface : WebXRInterface
48+
var vr_supported : bool = false
4549

4650
@onready var left_hand : XRController3D = $XROrigin/LeftHand
4751
@onready var right_hand : XRController3D = $XROrigin/RightHand
4852

53+
@onready var web_xr_setup_ui : CanvasLayer = $WebXRSetupUI
54+
4955
func _ready() -> void:
5056
Globals.init_settings(music_volume, sound_effects_volume)
5157
Globals.main = self
@@ -62,7 +68,23 @@ func _ready() -> void:
6268
# Change our main viewport to output to the HMD
6369
get_viewport().use_xr = true
6470
else:
65-
print("OpenXR not initialized; assuming regular mode")
71+
webxr_interface = XRServer.find_interface("WebXR") as WebXRInterface
72+
if webxr_interface:
73+
xr_interface = webxr_interface
74+
# Set up WebXR callbacks.
75+
webxr_interface.session_supported.connect(self._webxr_session_supported)
76+
webxr_interface.session_started.connect(self._webxr_session_started)
77+
webxr_interface.session_ended.connect(self._webxr_session_ended)
78+
webxr_interface.session_failed.connect(self._webxr_session_failed)
79+
80+
# This returns immediately; the result is delivered to the
81+
# _webxr_session_supported callback.
82+
webxr_interface.is_session_supported("immersive-vr")
83+
84+
# Show the button to enter WebXR.
85+
web_xr_setup_ui.visible = true
86+
else:
87+
print("OpenXR/WebXR not initialized; assuming regular mode")
6688

6789
if override_startup_scene != '':
6890
# This will be set if another scene was loaded by the editor.
@@ -198,3 +220,61 @@ func _on_audio_volume_changed(type: AudioManager.AudioType, volume: float) -> vo
198220
# Check before assigning, to avoid restarting already-playing music.
199221
if music_player.playing != (volume > 0):
200222
music_player.playing = volume > 0
223+
224+
# --- WebXR stuff --- #
225+
# TODO: Move all VR setup to a separate file.
226+
227+
func _webxr_session_supported(session_mode: String, supported: bool) -> void:
228+
if session_mode == 'immersive-vr':
229+
vr_supported = supported
230+
231+
func _on_btn_enter_web_xr_pressed() -> void:
232+
if not vr_supported:
233+
OS.alert("Your browser doesn't support VR")
234+
return
235+
236+
# We want an immersive VR session.
237+
webxr_interface.session_mode = 'immersive-vr'
238+
# 'bounded-floor' is room scale, 'local-floor' is a standing or sitting
239+
# experience (it puts you 1.6m above the ground if you have 3DoF headset),
240+
# whereas as 'local' puts you down at the XROrigin.
241+
# This list means it'll first try to request 'bounded-floor', then
242+
# fallback on 'local-floor' and ultimately 'local', if nothing else is
243+
# supported.
244+
webxr_interface.requested_reference_space_types = 'bounded-floor, local-floor, local'
245+
# In order to use 'local-floor' or 'bounded-floor' we must also
246+
# mark the features as required or optional. By including 'hand-tracking'
247+
# as an optional feature, it will be enabled if supported.
248+
webxr_interface.required_features = 'local-floor'
249+
webxr_interface.optional_features = 'bounded-floor, hand-tracking'
250+
# TODO: I probably don't want hand tracking. I do want to validate that
251+
# the device actually has two controllers though.
252+
253+
# This will return false if we're unable to even request the session,
254+
# however, it can still fail asynchronously later in the process, so we
255+
# only know if it's really succeeded or failed when our
256+
# _webxr_session_started() or _webxr_session_failed() methods are called.
257+
if not webxr_interface.initialize():
258+
OS.alert("Failed to initialize WebXR")
259+
return
260+
261+
func _webxr_session_started() -> void:
262+
web_xr_setup_ui.visible = false
263+
# This tells Godot to start rendering to the headset.
264+
get_viewport().use_xr = true
265+
# This will be the reference space type you ultimately got, out of the
266+
# types that you requested above. This is useful if you want the game to
267+
# work a little differently in 'bounded-floor' versus 'local-floor'.
268+
print("Reference space type: ", webxr_interface.reference_space_type)
269+
# This will be the list of features that were successfully enabled
270+
# (except on browsers that don't support this property).
271+
print("Enabled features: ", webxr_interface.enabled_features)
272+
273+
func _webxr_session_ended() -> void:
274+
web_xr_setup_ui.visible = true
275+
# If the user exits immersive mode, then we tell Godot to render to the web
276+
# page again.
277+
get_viewport().use_xr = false
278+
279+
func _webxr_session_failed(message: String) -> void:
280+
OS.alert("Failed to initialize WebXR: " + message)

scenes/main.tscn

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,36 @@ layout_mode = 2
9090
size_flags_vertical = 0
9191
theme_override_font_sizes/font_size = 10
9292

93+
[node name="WebXRSetupUI" type="CanvasLayer" parent="."]
94+
layer = 102
95+
visible = false
96+
97+
[node name="Scrim" type="ColorRect" parent="WebXRSetupUI"]
98+
anchors_preset = 15
99+
anchor_right = 1.0
100+
anchor_bottom = 1.0
101+
grow_horizontal = 2
102+
grow_vertical = 2
103+
mouse_filter = 2
104+
color = Color(0, 0, 0, 0.5019608)
105+
106+
[node name="BtnEnterWebXR" type="Button" parent="WebXRSetupUI"]
107+
z_index = 1
108+
anchors_preset = 8
109+
anchor_left = 0.5
110+
anchor_top = 0.5
111+
anchor_right = 0.5
112+
anchor_bottom = 0.5
113+
offset_left = -61.5
114+
offset_top = -15.5
115+
offset_right = 61.5
116+
offset_bottom = 15.5
117+
grow_horizontal = 2
118+
grow_vertical = 2
119+
size_flags_horizontal = 4
120+
size_flags_vertical = 4
121+
text = "Enter WebXR"
122+
93123
[node name="XROrigin" type="XROrigin3D" parent="."]
94124

95125
[node name="XRCamera" type="XRCamera3D" parent="XROrigin"]
@@ -105,3 +135,5 @@ show_when_tracked = true
105135
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.5, 1, -0.5)
106136
tracker = &"right_hand"
107137
show_when_tracked = true
138+
139+
[connection signal="pressed" from="WebXRSetupUI/BtnEnterWebXR" to="." method="_on_btn_enter_web_xr_pressed"]

0 commit comments

Comments
 (0)