386 lines
13 KiB
GDScript
386 lines
13 KiB
GDScript
@tool
|
|
extends Node3D
|
|
|
|
@onready var perspective = $XROrigin3D/Perspective
|
|
@onready var look_recenter_timer:Timer = Timer.new()
|
|
|
|
@export var right_controller:XRController3D
|
|
|
|
const mouse_look_sensitivity: float = 0.001
|
|
const gamepad_look_sensitivity_deg: float = 90.0
|
|
const gamepad_look_deadzone: float = 0.15
|
|
|
|
var _use_prompt_1:bool = false
|
|
var _use_prompt_2:bool = false
|
|
@export var use_prompt_1:bool:
|
|
get:
|
|
return _use_prompt_1
|
|
set(val):
|
|
_use_prompt_1 = val
|
|
if (val):
|
|
$prompt_1_timer.start(prompt_1_time)
|
|
else:
|
|
$prompt_1_timer.stop()
|
|
@export var prompt_1_time:int
|
|
@export var prompt_2_time:int
|
|
@export var use_prompt_2:bool:
|
|
get:
|
|
return _use_prompt_2
|
|
set(val):
|
|
_use_prompt_2 = val
|
|
if (val and $prompt_2_timer):
|
|
$prompt_2_timer.start(prompt_2_time)
|
|
else:
|
|
$prompt_2_timer.stop()
|
|
@export var stage_music:AudioStreamMP3 = null
|
|
@onready var is_centering:bool = false
|
|
|
|
var _tunnel_1_color:Color = Color.WHITE
|
|
var _tunnel_2_color:Color = Color.WHITE
|
|
var _tunnel_3_color:Color = Color.WHITE
|
|
|
|
var _tunnel_1_spiral_color:Color = Color(0.8, 0.8, 0.8, 1)
|
|
var _tunnel_2_spiral_color:Color = Color(0.8, 0.8, 0.8, 1)
|
|
var _tunnel_3_spiral_color:Color = Color(0.8, 0.8, 0.8, 1)
|
|
|
|
var _tunnel_1_spiral_turns:float = 1.0
|
|
var _tunnel_2_spiral_turns:float = 8.0
|
|
var _tunnel_3_spiral_turns:float = 1.0
|
|
|
|
var _tunnel_1_spiral_swirl:float = 6.0
|
|
var _tunnel_2_spiral_swirl:float = 6.0
|
|
var _tunnel_3_spiral_swirl:float = 6.0
|
|
|
|
var _tunnel_1_spiral_width:float = 0.047
|
|
var _tunnel_2_spiral_width:float = 0.047
|
|
var _tunnel_3_spiral_width:float = 0.047
|
|
|
|
var _tunnel_1_spiral_strands:float = 1.0
|
|
var _tunnel_2_spiral_strands:float = 1.0
|
|
var _tunnel_3_spiral_strands:float = 1.0
|
|
|
|
@export var tunnel_1_color:Color = Color.WHITE:
|
|
get: return _tunnel_1_color
|
|
set(val):
|
|
_tunnel_1_color = val
|
|
if $MeshInstance3D:
|
|
_set_mesh_shader_parameter($MeshInstance3D, "color", val)
|
|
@export var tunnel_2_color:Color = Color.WHITE:
|
|
get: return _tunnel_2_color
|
|
set(val):
|
|
_tunnel_2_color = val
|
|
if $MeshInstance3D/MeshInstance3D2:
|
|
_set_mesh_shader_parameter($MeshInstance3D/MeshInstance3D2, "color", val)
|
|
@export var tunnel_3_color:Color = Color.WHITE:
|
|
get: return _tunnel_3_color
|
|
set(val):
|
|
_tunnel_3_color = val
|
|
if $MeshInstance3D/MeshInstance3D3:
|
|
_set_mesh_shader_parameter($MeshInstance3D/MeshInstance3D3, "color", val)
|
|
if $MeshInstance3D/Blurrycap:
|
|
_set_blurrycap_shader_parameter("tint_color", val)
|
|
|
|
@export var tunnel_1_spiral_color:Color = Color(0.8, 0.8, 0.8, 1):
|
|
get: return _tunnel_1_spiral_color
|
|
set(val):
|
|
_tunnel_1_spiral_color = val
|
|
if $MeshInstance3D:
|
|
_set_mesh_shader_parameter($MeshInstance3D, "spiral_color", val)
|
|
@export var tunnel_2_spiral_color:Color = Color(0.8, 0.8, 0.8, 1):
|
|
get: return _tunnel_2_spiral_color
|
|
set(val):
|
|
_tunnel_2_spiral_color = val
|
|
if $MeshInstance3D/MeshInstance3D2:
|
|
_set_mesh_shader_parameter($MeshInstance3D/MeshInstance3D2, "spiral_color", val)
|
|
@export var tunnel_3_spiral_color:Color = Color(0.8, 0.8, 0.8, 1):
|
|
get: return _tunnel_3_spiral_color
|
|
set(val):
|
|
_tunnel_3_spiral_color = val
|
|
if $MeshInstance3D/MeshInstance3D3:
|
|
_set_mesh_shader_parameter($MeshInstance3D/MeshInstance3D3, "spiral_color", val)
|
|
|
|
@export_range(1.0, 48.0) var tunnel_1_spiral_turns:float = 1.0:
|
|
get: return _tunnel_1_spiral_turns
|
|
set(val):
|
|
_tunnel_1_spiral_turns = val
|
|
if $MeshInstance3D:
|
|
_set_mesh_shader_parameter($MeshInstance3D, "spiral_turns", val)
|
|
@export_range(1.0, 48.0) var tunnel_2_spiral_turns:float = 8.0:
|
|
get: return _tunnel_2_spiral_turns
|
|
set(val):
|
|
_tunnel_2_spiral_turns = val
|
|
if $MeshInstance3D/MeshInstance3D2:
|
|
_set_mesh_shader_parameter($MeshInstance3D/MeshInstance3D2, "spiral_turns", val)
|
|
@export_range(1.0, 48.0) var tunnel_3_spiral_turns:float = 1.0:
|
|
get: return _tunnel_3_spiral_turns
|
|
set(val):
|
|
_tunnel_3_spiral_turns = val
|
|
if $MeshInstance3D/MeshInstance3D3:
|
|
_set_mesh_shader_parameter($MeshInstance3D/MeshInstance3D3, "spiral_turns", val)
|
|
|
|
@export_range(6.0, 360.0) var tunnel_1_spiral_swirl:float = 6.0:
|
|
get: return _tunnel_1_spiral_swirl
|
|
set(val):
|
|
_tunnel_1_spiral_swirl = val
|
|
if $MeshInstance3D:
|
|
_set_mesh_shader_parameter($MeshInstance3D, "spiral_swirl", val)
|
|
@export_range(6.0, 360.0) var tunnel_2_spiral_swirl:float = 6.0:
|
|
get: return _tunnel_2_spiral_swirl
|
|
set(val):
|
|
_tunnel_2_spiral_swirl = val
|
|
if $MeshInstance3D/MeshInstance3D2:
|
|
_set_mesh_shader_parameter($MeshInstance3D/MeshInstance3D2, "spiral_swirl", val)
|
|
@export_range(6.0, 360.0) var tunnel_3_spiral_swirl:float = 6.0:
|
|
get: return _tunnel_3_spiral_swirl
|
|
set(val):
|
|
_tunnel_3_spiral_swirl = val
|
|
if $MeshInstance3D/MeshInstance3D3:
|
|
_set_mesh_shader_parameter($MeshInstance3D/MeshInstance3D3, "spiral_swirl", val)
|
|
|
|
@export_range(0.02, 0.5) var tunnel_1_spiral_width:float = 0.047:
|
|
get: return _tunnel_1_spiral_width
|
|
set(val):
|
|
_tunnel_1_spiral_width = val
|
|
if $MeshInstance3D:
|
|
_set_mesh_shader_parameter($MeshInstance3D, "spiral_width", val)
|
|
@export_range(0.02, 0.5) var tunnel_2_spiral_width:float = 0.047:
|
|
get: return _tunnel_2_spiral_width
|
|
set(val):
|
|
_tunnel_2_spiral_width = val
|
|
if $MeshInstance3D/MeshInstance3D2:
|
|
_set_mesh_shader_parameter($MeshInstance3D/MeshInstance3D2, "spiral_width", val)
|
|
@export_range(0.02, 0.5) var tunnel_3_spiral_width:float = 0.047:
|
|
get: return _tunnel_3_spiral_width
|
|
set(val):
|
|
_tunnel_3_spiral_width = val
|
|
if $MeshInstance3D/MeshInstance3D3:
|
|
_set_mesh_shader_parameter($MeshInstance3D/MeshInstance3D3, "spiral_width", val)
|
|
|
|
@export_range(1.0, 2.0) var tunnel_1_spiral_strands:float = 1.0:
|
|
get: return _tunnel_1_spiral_strands
|
|
set(val):
|
|
_tunnel_1_spiral_strands = val
|
|
if $MeshInstance3D:
|
|
_set_mesh_shader_parameter($MeshInstance3D, "spiral_strands", val)
|
|
@export_range(1.0, 2.0) var tunnel_2_spiral_strands:float = 1.0:
|
|
get: return _tunnel_2_spiral_strands
|
|
set(val):
|
|
_tunnel_2_spiral_strands = val
|
|
if $MeshInstance3D/MeshInstance3D2:
|
|
_set_mesh_shader_parameter($MeshInstance3D/MeshInstance3D2, "spiral_strands", val)
|
|
@export_range(1.0, 2.0) var tunnel_3_spiral_strands:float = 1.0:
|
|
get: return _tunnel_3_spiral_strands
|
|
set(val):
|
|
_tunnel_3_spiral_strands = val
|
|
if $MeshInstance3D/MeshInstance3D3:
|
|
_set_mesh_shader_parameter($MeshInstance3D/MeshInstance3D3, "spiral_strands", val)
|
|
|
|
func _enter_tree() -> void:
|
|
if Engine.is_editor_hint():
|
|
set_process(true)
|
|
call_deferred("_apply_tunnel_shader_properties")
|
|
|
|
# Called when the node enters the scene tree for the first time.
|
|
func _ready() -> void:
|
|
_apply_tunnel_shader_properties()
|
|
|
|
# Keep editor behavior limited to visual parameter syncing.
|
|
if Engine.is_editor_hint():
|
|
return
|
|
|
|
# Re-trigger setters now that the scene tree is ready.
|
|
|
|
add_child(look_recenter_timer)
|
|
look_recenter_timer.connect("timeout",_look_recenter_timer_timeout)
|
|
look_recenter_timer.one_shot = true
|
|
look_recenter_timer.autostart = false
|
|
look_recenter_timer.stop()
|
|
# As a PC game, we want to eat the mouse cursor like an FPS.
|
|
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
|
|
# _ensure_gamepad_look_actions()
|
|
|
|
if use_prompt_1:
|
|
$prompt_2_timer.start(169)
|
|
if use_prompt_2:
|
|
$prompt_1_timer.start(69)
|
|
|
|
# Initialize VR
|
|
_init_vr()
|
|
|
|
# Wait one frame for XR to be fully set up, then center the headset
|
|
await get_tree().process_frame
|
|
|
|
if get_viewport().use_xr:
|
|
XRServer.center_on_hmd(XRServer.DONT_RESET_ROTATION, false)
|
|
else:
|
|
# go fullscreen - this is a computer.
|
|
DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN)
|
|
|
|
# Begin the portal
|
|
_prepare_music()
|
|
_begin_portal()
|
|
$XROrigin3D/AudioStreamPlayer.play()
|
|
|
|
func _apply_tunnel_shader_properties() -> void:
|
|
var mesh_1 := get_node_or_null("MeshInstance3D") as MeshInstance3D
|
|
var mesh_2 := get_node_or_null("MeshInstance3D/MeshInstance3D2") as MeshInstance3D
|
|
var mesh_3 := get_node_or_null("MeshInstance3D/MeshInstance3D3") as MeshInstance3D
|
|
|
|
if mesh_1:
|
|
_set_mesh_shader_parameter(mesh_1, "color", _tunnel_1_color)
|
|
_set_mesh_shader_parameter(mesh_1, "spiral_color", _tunnel_1_spiral_color)
|
|
_set_mesh_shader_parameter(mesh_1, "spiral_turns", _tunnel_1_spiral_turns)
|
|
_set_mesh_shader_parameter(mesh_1, "spiral_swirl", _tunnel_1_spiral_swirl)
|
|
_set_mesh_shader_parameter(mesh_1, "spiral_width", _tunnel_1_spiral_width)
|
|
_set_mesh_shader_parameter(mesh_1, "spiral_strands", _tunnel_1_spiral_strands)
|
|
|
|
if mesh_2:
|
|
_set_mesh_shader_parameter(mesh_2, "color", _tunnel_2_color)
|
|
_set_mesh_shader_parameter(mesh_2, "spiral_color", _tunnel_2_spiral_color)
|
|
_set_mesh_shader_parameter(mesh_2, "spiral_turns", _tunnel_2_spiral_turns)
|
|
_set_mesh_shader_parameter(mesh_2, "spiral_swirl", _tunnel_2_spiral_swirl)
|
|
_set_mesh_shader_parameter(mesh_2, "spiral_width", _tunnel_2_spiral_width)
|
|
_set_mesh_shader_parameter(mesh_2, "spiral_strands", _tunnel_2_spiral_strands)
|
|
|
|
if mesh_3:
|
|
_set_mesh_shader_parameter(mesh_3, "color", _tunnel_3_color)
|
|
_set_mesh_shader_parameter(mesh_3, "spiral_color", _tunnel_3_spiral_color)
|
|
_set_mesh_shader_parameter(mesh_3, "spiral_turns", _tunnel_3_spiral_turns)
|
|
_set_mesh_shader_parameter(mesh_3, "spiral_swirl", _tunnel_3_spiral_swirl)
|
|
_set_mesh_shader_parameter(mesh_3, "spiral_width", _tunnel_3_spiral_width)
|
|
_set_mesh_shader_parameter(mesh_3, "spiral_strands", _tunnel_3_spiral_strands)
|
|
|
|
_set_blurrycap_shader_parameter("tint_color", _tunnel_3_color)
|
|
|
|
func _prepare_music()->void:
|
|
$XROrigin3D/AudioStreamPlayer.stream=stage_music
|
|
|
|
func _cycle_presentation_format() -> void:
|
|
var emitter := $MeshInstance3D/EmissionPoint
|
|
if not emitter.is_node_ready():
|
|
return
|
|
emitter.cycle_format()
|
|
|
|
func _set_mesh_shader_parameter(
|
|
mesh_instance: MeshInstance3D,
|
|
parameter: StringName,
|
|
val: Variant
|
|
) -> void:
|
|
var mesh := mesh_instance.mesh as CylinderMesh
|
|
if not mesh:
|
|
return
|
|
var shader_material := mesh.material as ShaderMaterial
|
|
if shader_material:
|
|
shader_material.set_shader_parameter(parameter, val)
|
|
|
|
func _set_blurrycap_shader_parameter(parameter: StringName, val: Variant) -> void:
|
|
var blurrycap := get_node_or_null("MeshInstance3D/Blurrycap") as MeshInstance3D
|
|
if not blurrycap:
|
|
return
|
|
var shader_material := blurrycap.get_surface_override_material(0) as ShaderMaterial
|
|
if shader_material:
|
|
shader_material.set_shader_parameter(parameter, val)
|
|
|
|
func _begin_portal() -> void:
|
|
var emitter := $MeshInstance3D/EmissionPoint
|
|
emitter.set_viewer_camera(perspective)
|
|
await emitter.initialize_video_pool()
|
|
|
|
func _init_vr():
|
|
if (XRServer.get_interface_count() > 0):
|
|
var xr_interface = XRServer.find_interface("OpenXR")
|
|
if xr_interface and xr_interface.is_initialized():
|
|
print("OpenXR initialized successfully")
|
|
|
|
# Turn off v-sync!
|
|
DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_DISABLED)
|
|
|
|
# Change our main viewport to output to the HMD
|
|
get_viewport().use_xr = true
|
|
else:
|
|
print("OpenXR not initialized, please check if your headset is connected")
|
|
|
|
func _input(event:InputEvent) ->void:
|
|
if Engine.is_editor_hint():
|
|
return
|
|
|
|
if event.is_action_pressed("Quit"):
|
|
get_tree().quit(0)
|
|
elif event.is_action_pressed("Fullscreen"):
|
|
if DisplayServer.window_get_mode() != DisplayServer.WINDOW_MODE_FULLSCREEN:
|
|
DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN)
|
|
else:
|
|
DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED)
|
|
if event.is_action_pressed("CycleFormat"):
|
|
_cycle_presentation_format()
|
|
|
|
func _process(delta: float) -> void:
|
|
if Engine.is_editor_hint():
|
|
_apply_tunnel_shader_properties()
|
|
return
|
|
|
|
# Desktop gamepad look is disabled while XR output is active.
|
|
_do_gamepad_movement(gamepad_look_sensitivity_deg, delta)
|
|
|
|
if $XROrigin3D/XRController3D.get_float("trigger") > 0:
|
|
_cycle_presentation_format()
|
|
|
|
_do_autocentering(delta)
|
|
|
|
func _do_autocentering(delta:float)->void:
|
|
if is_centering:
|
|
var target_rotation = Vector3.ZERO
|
|
var recenter_speed = 0.05 # radians per second
|
|
var rotation_delta = target_rotation - perspective.rotation
|
|
rotation_delta.x = angle_difference(perspective.rotation.x, target_rotation.x)
|
|
rotation_delta.y = angle_difference(perspective.rotation.y, target_rotation.y)
|
|
|
|
perspective.rotation += rotation_delta.normalized() * recenter_speed * delta
|
|
|
|
if rotation_delta.length() < 0.01:
|
|
is_centering = false
|
|
perspective.rotation = Vector3(0, perspective.rotation.z, 0)
|
|
|
|
func _unhandled_input(event: InputEvent) -> void:
|
|
if Engine.is_editor_hint():
|
|
return
|
|
|
|
if (event is InputEventMouseMotion and Input.mouse_mode == Input.MOUSE_MODE_CAPTURED) :
|
|
var e = event as InputEventMouseMotion
|
|
_apply_look_delta(
|
|
mouse_look_sensitivity * -e.relative.x,
|
|
mouse_look_sensitivity * -e.relative.y
|
|
)
|
|
look_recenter_timer.start(1)
|
|
|
|
|
|
func _apply_look_delta(yaw_delta: float, pitch_delta: float) -> void:
|
|
perspective.rotate_y(yaw_delta)
|
|
perspective.rotate_x(pitch_delta)
|
|
perspective.rotation.x = clampf(perspective.rotation.x, -deg_to_rad(50), deg_to_rad(50))
|
|
perspective.rotation.y = clampf(perspective.rotation.y, -deg_to_rad(35), deg_to_rad(35))
|
|
perspective.rotation.z = 0
|
|
|
|
func _do_gamepad_movement(gamepad_look_sensitivity_deg:float, delta:float)->void:
|
|
if get_viewport().use_xr:
|
|
return
|
|
|
|
var look_input := Vector2(
|
|
Input.get_axis("look_left", "look_right"),
|
|
Input.get_axis("look_up", "look_down")
|
|
)
|
|
if look_input.length_squared() < gamepad_look_deadzone * gamepad_look_deadzone:
|
|
return
|
|
|
|
_apply_look_delta(
|
|
deg_to_rad(-look_input.x * gamepad_look_sensitivity_deg * delta),
|
|
deg_to_rad(-look_input.y * gamepad_look_sensitivity_deg * delta)
|
|
)
|
|
|
|
if look_input!=Vector2.ZERO:
|
|
# You moved!
|
|
look_recenter_timer.start(1.5) # seconds of no motion until auto recenter.
|
|
|
|
func _look_recenter_timer_timeout():
|
|
is_centering = true
|