From de976f34bc7b80c74dd7c11f49816781db886dfc Mon Sep 17 00:00:00 2001 From: Nitwel Date: Thu, 2 Nov 2023 01:22:48 +0100 Subject: [PATCH] support working without vr headset --- addons/xr-simulator/XRSimulator.gd | 242 ++++++++++++++++++++++ addons/xr-simulator/XRSimulator.tscn | 7 + assets/materials/sky.material | 3 + assets/materials/sky_passthrough.material | 3 + main.gd | 11 + main.tscn | 24 +-- 6 files changed, 278 insertions(+), 12 deletions(-) create mode 100644 addons/xr-simulator/XRSimulator.gd create mode 100644 addons/xr-simulator/XRSimulator.tscn create mode 100644 assets/materials/sky.material create mode 100644 assets/materials/sky_passthrough.material create mode 100644 main.gd diff --git a/addons/xr-simulator/XRSimulator.gd b/addons/xr-simulator/XRSimulator.gd new file mode 100644 index 0000000..cedeec3 --- /dev/null +++ b/addons/xr-simulator/XRSimulator.gd @@ -0,0 +1,242 @@ +extends Node + +enum ControllerSelectionMode {Hold, Toggle} + +@export var enabled: bool +@export var disable_xr_in_editor: bool = true +@export var controller_selection_mode: ControllerSelectionMode = ControllerSelectionMode.Hold +@export var device_x_sensitivity: float = 1 +@export var device_y_sensitivity: float = 1 +@export var scroll_sensitivity: float = 1 +@export var is_camera_height_limited: bool = true +@export var min_camera_height: float = 0.5 +@export var max_camera_height: float = 2.0 +@export var xr_origin: NodePath + +var origin: XROrigin3D +var camera: XRCamera3D +var left_controller: XRController3D +var right_controller: XRController3D +var left_tracker: XRPositionalTracker +var right_tracker: XRPositionalTracker + +var toggle_left_controller = false +var toggle_right_controller = false +var toggle_shift = false + +var key_map = { + KEY_1: "by_button", + KEY_2: "ax_button", + KEY_3: "by_touch", + KEY_4: "ax_touch", + KEY_5: "trigger_touch", + KEY_6: "grip_touch", + KEY_7: "secondary_click", + KEY_8: "secondary_touch", + KEY_9: "", + KEY_0: "", + KEY_MINUS: "primary_click", + KEY_EQUAL: "primary_touch", + KEY_BACKSPACE: "", + KEY_ENTER: "menu_button" +} + +@onready var viewport: Viewport = get_viewport() + +func _ready(): + if not enabled or not OS.has_feature("editor"): + enabled = false + return + + Input.mouse_mode = Input.MOUSE_MODE_CAPTURED + + origin = get_node(xr_origin) + + camera = origin.get_node("XRCamera3D") + + var left_hand = XRServer.get_tracker("left_hand") + if left_hand == null: + left_tracker = XRPositionalTracker.new() + left_tracker.type = XRServer.TRACKER_CONTROLLER + left_tracker.hand = XRPositionalTracker.TRACKER_HAND_LEFT + left_tracker.name = "left_hand" + else: + left_tracker = left_hand + + var right_hand = XRServer.get_tracker("right_hand") + if right_hand == null: + right_tracker = XRPositionalTracker.new() + right_tracker.type = XRServer.TRACKER_CONTROLLER + right_tracker.hand = XRPositionalTracker.TRACKER_HAND_RIGHT + right_tracker.name = "right_hand" + else: + right_tracker = right_hand + + for child in origin.get_children(): + if child.get("tracker"): + var pose = child.pose + if child.tracker == "left_hand": + left_controller = child + left_tracker.set_pose(pose, child.transform, Vector3.ZERO, Vector3.ZERO, XRPose.XR_TRACKING_CONFIDENCE_HIGH) + XRServer.add_tracker(left_tracker) + elif child.tracker == "right_hand": + right_controller = child + right_tracker.set_pose(pose, child.transform, Vector3.ZERO, Vector3.ZERO, XRPose.XR_TRACKING_CONFIDENCE_HIGH) + XRServer.add_tracker(right_tracker) + + +func _process(_delta): + if enabled and disable_xr_in_editor and OS.has_feature("editor") and viewport.use_xr: + viewport.use_xr = false + +func _input(event): + if not enabled or not origin.current or not OS.has_feature("editor"): + return + if Input.is_key_pressed(KEY_ESCAPE): + Input.mouse_mode = Input.MOUSE_MODE_VISIBLE + elif Input.mouse_mode != Input.MOUSE_MODE_CAPTURED and event is InputEventMouseButton: + Input.mouse_mode = Input.MOUSE_MODE_CAPTURED + + if Input.mouse_mode != Input.MOUSE_MODE_CAPTURED: + return + + simulate_joysticks() + var is_any_controller_selected = false + if event is InputEventMouseMotion: + if Input.is_physical_key_pressed(KEY_Q) or toggle_left_controller: + is_any_controller_selected = true + if Input.is_key_pressed(KEY_SHIFT): + rotate_device(event, left_controller) + else: + move_controller(event, left_controller) + if Input.is_physical_key_pressed(KEY_E) or toggle_right_controller: + is_any_controller_selected = true + if Input.is_key_pressed(KEY_SHIFT): + rotate_device(event, right_controller) + else: + move_controller(event, right_controller) + if not is_any_controller_selected: + rotate_device(event, camera) + elif event is InputEventMouseButton: + if Input.is_physical_key_pressed(KEY_Q) or toggle_left_controller: + is_any_controller_selected = true + attract_controller(event, left_controller) + simulate_trigger(event, left_controller) + simulate_grip(event, left_controller) + if Input.is_physical_key_pressed(KEY_E) or toggle_right_controller: + is_any_controller_selected = true + attract_controller(event, right_controller) + simulate_trigger(event, right_controller) + simulate_grip(event, right_controller) + if not is_any_controller_selected: + camera_height(event) + elif event is InputEventKey: + if controller_selection_mode == ControllerSelectionMode.Toggle and event.pressed: + if event.keycode == KEY_Q: + toggle_left_controller = !toggle_left_controller + elif event.keycode == KEY_E: + toggle_right_controller = !toggle_right_controller + + if Input.is_physical_key_pressed(KEY_Q) or toggle_left_controller: + simulate_buttons(event, left_controller) + if Input.is_physical_key_pressed(KEY_E) or toggle_right_controller: + simulate_buttons(event, right_controller) + +func camera_height(event: InputEventMouseButton): + var direction = -1 + + if not event.pressed: + return + + if event.button_index == MOUSE_BUTTON_WHEEL_UP: + direction = 1 + elif event.button_index != MOUSE_BUTTON_WHEEL_DOWN: + return + + var pos = camera.transform.origin + var camera_y = pos.y + (scroll_sensitivity * direction)/20 + if (camera_y >= max_camera_height or camera_y <= min_camera_height) and is_camera_height_limited: + camera_y = pos.y + camera.transform.origin = Vector3(pos.x, camera_y , pos.z) + +func simulate_joysticks(): + var vec_left = vector_key_mapping(KEY_D, KEY_A, KEY_W, KEY_S) + left_tracker.set_input("primary", vec_left) + + var vec_right = vector_key_mapping(KEY_RIGHT, KEY_LEFT, KEY_UP, KEY_DOWN) + + right_tracker.set_input("primary", vec_right) + +func simulate_trigger(event: InputEventMouseButton, controller: XRController3D): + if event.button_index == MOUSE_BUTTON_LEFT: + if controller.tracker == "left_hand": + left_tracker.set_input("trigger", float(event.pressed)) + left_tracker.set_input("trigger_click", event.pressed) + else: + right_tracker.set_input("trigger", float(event.pressed)) + right_tracker.set_input("trigger_click", event.pressed) + +func simulate_grip(event: InputEventMouseButton, controller: XRController3D): + if event.button_index == MOUSE_BUTTON_RIGHT: + if controller.tracker == "left_hand": + left_tracker.set_input("grip", float(event.pressed)) + left_tracker.set_input("grip_click", event.pressed) + else: + right_tracker.set_input("grip", float(event.pressed)) + right_tracker.set_input("grip_click", event.pressed) + +func simulate_buttons(event: InputEventKey, controller: XRController3D): + if key_map.has(event.keycode): + var button = key_map[event.keycode] + if controller.tracker == "left_hand": + left_tracker.set_input(button, event.pressed) + else: + right_tracker.set_input(button, event.pressed) + +func move_controller(event: InputEventMouseMotion, controller: XRController3D): + var movement = Vector3() + movement += camera.global_transform.basis.x * event.relative.x * device_x_sensitivity/1000 + movement += camera.global_transform.basis.y * event.relative.y * -device_y_sensitivity/1000 + controller.global_translate(movement) + +func attract_controller(event: InputEventMouseButton, controller: XRController3D): + var direction = -1 + + if not event.pressed: + return + + if event.button_index == MOUSE_BUTTON_WHEEL_UP: + direction = 1 + elif event.button_index != MOUSE_BUTTON_WHEEL_DOWN: + return + + var distance_vector = controller.global_transform.origin - camera.global_transform.origin + var forward = distance_vector.normalized() * direction + var movement = distance_vector + forward * (scroll_sensitivity/20) + if distance_vector.length() > 0.1 and movement.length() > 0.1: + controller.global_translate(forward * (scroll_sensitivity/20)) + +func rotate_device(event: InputEventMouseMotion, device: Node3D): + var motion = event.relative + device.rotate_y(motion.x * -device_x_sensitivity/1000) + device.rotate(device.transform.basis.x, motion.y * -device_y_sensitivity/1000) + +func vector_key_mapping(key_positive_x: int, key_negative_x: int, key_positive_y: int, key_negative_y: int): + var x = 0 + var y = 0 + if Input.is_physical_key_pressed (key_positive_y): + y = 1 + elif Input.is_physical_key_pressed (key_negative_y): + y = -1 + + if Input.is_physical_key_pressed (key_positive_x): + x = 1 + elif Input.is_physical_key_pressed (key_negative_x): + x = -1 + + var vec = Vector2(x, y) + + if vec: + vec = vec.normalized() + + return vec diff --git a/addons/xr-simulator/XRSimulator.tscn b/addons/xr-simulator/XRSimulator.tscn new file mode 100644 index 0000000..00befb0 --- /dev/null +++ b/addons/xr-simulator/XRSimulator.tscn @@ -0,0 +1,7 @@ +[gd_scene load_steps=2 format=3 uid="uid://ctltchlf2j2r4"] + +[ext_resource type="Script" path="res://addons/xr-simulator/XRSimulator.gd" id="1_uljju"] + +[node name="XRSimulator" type="Node"] +script = ExtResource("1_uljju") +enabled = true diff --git a/assets/materials/sky.material b/assets/materials/sky.material new file mode 100644 index 0000000..3765603 --- /dev/null +++ b/assets/materials/sky.material @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:25ef12c9534c8bbb08a816492562253c5c6fe0257f87427ce77b223231b07de5 +size 299 diff --git a/assets/materials/sky_passthrough.material b/assets/materials/sky_passthrough.material new file mode 100644 index 0000000..ccc78b5 --- /dev/null +++ b/assets/materials/sky_passthrough.material @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:eead3733b7242e93c1739fcebd649efd1ce56ad1a3934e69d850c6ef3df66b9c +size 351 diff --git a/main.gd b/main.gd new file mode 100644 index 0000000..0ca4af0 --- /dev/null +++ b/main.gd @@ -0,0 +1,11 @@ +extends Node3D + +var sky = preload("res://assets/materials/sky.material") +var sky_passthrough = preload("res://assets/materials/sky_passthrough.material") + +@export var passthrough: bool = true +@onready var environment: WorldEnvironment = $WorldEnvironment + +func _ready(): + if passthrough: + environment.environment.sky.set_material(sky_passthrough) \ No newline at end of file diff --git a/main.tscn b/main.tscn index 79ccc7c..fd5f1b5 100644 --- a/main.tscn +++ b/main.tscn @@ -1,9 +1,12 @@ -[gd_scene load_steps=10 format=3 uid="uid://eecv28y6jxk4"] +[gd_scene load_steps=12 format=3 uid="uid://eecv28y6jxk4"] [ext_resource type="PackedScene" uid="uid://clc5dre31iskm" path="res://addons/godot-xr-tools/xr/start_xr.tscn" id="1_i4c04"] [ext_resource type="Script" path="res://src/raycast.gd" id="1_tsqxc"] +[ext_resource type="Script" path="res://main.gd" id="1_uvrd4"] [ext_resource type="Script" path="res://src/model.gd" id="2_7f1x4"] [ext_resource type="PackedScene" uid="uid://c3kdssrmv84kv" path="res://scenes/menu.tscn" id="3_1tbp3"] +[ext_resource type="PackedScene" uid="uid://ctltchlf2j2r4" path="res://addons/xr-simulator/XRSimulator.tscn" id="5_3qc8g"] +[ext_resource type="Material" uid="uid://bf5ina366dwm6" path="res://assets/materials/sky.material" id="5_wgwf8"] [sub_resource type="StandardMaterial3D" id="StandardMaterial3D_m58yb"] ao_enabled = true @@ -12,17 +15,8 @@ ao_enabled = true material = SubResource("StandardMaterial3D_m58yb") size = Vector3(0.01, 0.01, 0.01) -[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_p6hri"] -sky_top_color = Color(0, 0, 0, 1) -sky_horizon_color = Color(0, 0, 0, 1) -sky_curve = 9.13367e-05 -sky_cover_modulate = Color(0, 0, 0, 1) -ground_bottom_color = Color(0, 0, 0, 1) -ground_horizon_color = Color(0, 0, 0, 1) -use_debanding = false - [sub_resource type="Sky" id="Sky_vhymk"] -sky_material = SubResource("ProceduralSkyMaterial_p6hri") +sky_material = ExtResource("5_wgwf8") [sub_resource type="Environment" id="Environment_7ghp0"] background_mode = 2 @@ -32,6 +26,9 @@ ambient_light_color = Color(1, 1, 1, 1) ambient_light_sky_contribution = 0.72 [node name="Main" type="Node3D"] +transform = Transform3D(1, -0.000296142, 0.000270963, 0.000296143, 1, -4.61078e-06, -0.000270962, 4.67014e-06, 1, 0, 0, 0) +script = ExtResource("1_uvrd4") +passthrough = false [node name="XROrigin3D" type="XROrigin3D" parent="."] @@ -50,7 +47,7 @@ mesh = SubResource("BoxMesh_ir3co") script = ExtResource("2_7f1x4") [node name="Menu" parent="XROrigin3D/XRControllerLeft" instance=ExtResource("3_1tbp3")] -transform = Transform3D(-4.37114e-08, 0, -1, -0.707107, 0.707107, 3.09086e-08, 0.707107, 0.707107, -3.09086e-08, 0.194945, 0, -0.0534939) +transform = Transform3D(-4.37114e-08, 0, -1, -0.707107, 0.707107, 3.09086e-08, 0.707107, 0.707107, -3.09086e-08, 0.183517, 0, -0.0534939) [node name="XRControllerRight" type="XRController3D" parent="XROrigin3D"] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.488349, 0.559219, -0.2988) @@ -77,3 +74,6 @@ environment = SubResource("Environment_7ghp0") [node name="DirectionalLight3D" type="DirectionalLight3D" parent="."] transform = Transform3D(0.834925, -0.386727, -0.39159, 0.550364, 0.586681, 0.594058, 0, -0.711511, 0.702675, 0, 7.21041, 2.06458) shadow_enabled = true + +[node name="XRSimulator" parent="." instance=ExtResource("5_3qc8g")] +xr_origin = NodePath("../XROrigin3D")