extends Node3D var webxr_interface: XRInterface var vr_supported: bool = false func _ready() -> void: $CanvasLayer/EnterVRButton.pressed.connect(_on_enter_vr_button_pressed) webxr_interface = XRServer.find_interface("WebXR") if webxr_interface: # WebXR uses a lot of asynchronous callbacks, so we connect to various # signals in order to receive them. webxr_interface.session_supported.connect(_webxr_session_supported) webxr_interface.session_started.connect(_webxr_session_started) webxr_interface.session_ended.connect(_webxr_session_ended) webxr_interface.session_failed.connect(_webxr_session_failed) webxr_interface.select.connect(_webxr_on_select) webxr_interface.selectstart.connect(_webxr_on_select_start) webxr_interface.selectend.connect(_webxr_on_select_end) webxr_interface.squeeze.connect(_webxr_on_squeeze) webxr_interface.squeezestart.connect(_webxr_on_squeeze_start) webxr_interface.squeezeend.connect(_webxr_on_squeeze_end) # This returns immediately - our _webxr_session_supported() method # (which we connected to the "session_supported" signal above) will # be called sometime later to let us know if it's supported or not. webxr_interface.is_session_supported("immersive-vr") $XROrigin3D/LeftController.button_pressed.connect(_on_left_controller_button_pressed) $XROrigin3D/LeftController.button_released.connect(_on_left_controller_button_released) func _webxr_session_supported(session_mode: String, supported: bool) -> void: if session_mode == 'immersive-vr': vr_supported = supported func _on_enter_vr_button_pressed() -> void: if not vr_supported: OS.alert("Your browser doesn't support VR") return # We want an immersive VR session, as opposed to AR ('immersive-ar') or a # simple 3DoF viewer ('viewer'). webxr_interface.session_mode = 'immersive-vr' # 'bounded-floor' is room scale, 'local-floor' is a standing or sitting # experience (it puts you 1.6m above the ground if you have 3DoF headset), # whereas as 'local' puts you down at the XROrigin3D. # This list means it'll first try to request 'bounded-floor', then # fallback on 'local-floor' and ultimately 'local', if nothing else is # supported. webxr_interface.requested_reference_space_types = 'bounded-floor, local-floor, local' # In order to use 'local-floor' or 'bounded-floor' we must also # mark the features as required or optional. webxr_interface.required_features = 'local-floor' webxr_interface.optional_features = 'bounded-floor' # This will return false if we're unable to even request the session, # however, it can still fail asynchronously later in the process, so we # only know if it's really succeeded or failed when our # _webxr_session_started() or _webxr_session_failed() methods are called. if not webxr_interface.initialize(): OS.alert("Failed to initialize WebXR") return func _webxr_session_started() -> void: $CanvasLayer.visible = false # This tells Godot to start rendering to the headset. get_viewport().use_xr = true # This will be the reference space type you ultimately got, out of the # types that you requested above. This is useful if you want the game to # work a little differently in 'bounded-floor' versus 'local-floor'. print("Reference space type: " + webxr_interface.reference_space_type) # This will be the list of features that were successfully enabled # (except on browsers that don't support this property). print("Enabled features: ", webxr_interface.enabled_features) func _webxr_session_ended() -> void: $CanvasLayer.visible = true # If the user exits immersive mode, then we tell Godot to render to the web # page again. get_viewport().use_xr = false func _webxr_session_failed(message: String) -> void: OS.alert("Failed to initialize: " + message) func _on_left_controller_button_pressed(button: String) -> void: print("Button pressed: " + button) func _on_left_controller_button_released(button: String) -> void: print("Button release: " + button) func _process(_delta: float) -> void: var thumbstick_vector: Vector2 = $XROrigin3D/LeftController.get_vector2("thumbstick") if thumbstick_vector != Vector2.ZERO: print("Left thumbstick position: " + str(thumbstick_vector)) func _webxr_on_select(input_source_id: int) -> void: print("Select: " + str(input_source_id)) var tracker: XRPositionalTracker = webxr_interface.get_input_source_tracker(input_source_id) var xform = tracker.get_pose('default').transform print(xform.origin) func _webxr_on_select_start(input_source_id: int) -> void: print("Select Start: " + str(input_source_id)) func _webxr_on_select_end(input_source_id: int) -> void: print("Select End: " + str(input_source_id)) func _webxr_on_squeeze(input_source_id: int) -> void: print("Squeeze: " + str(input_source_id)) func _webxr_on_squeeze_start(input_source_id: int) -> void: print("Squeeze Start: " + str(input_source_id)) func _webxr_on_squeeze_end(input_source_id: int) -> void: print("Squeeze End: " + str(input_source_id))