OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-tps / scenes / test / submarine_viewer.gd

81 lines · gd ref:
extends SceneTree
## Raymarched view of the seabed density, with nothing else in the scene.
##
##   DISPLAY=:0 "$HYPER_TPS_GODOT" --path . --rendering-driver vulkan \
##       --script res://scenes/test/submarine_viewer.gd
##
##   MOUSE look (captured) · W A S D move · Q/E down/up · SHIFT 10x · V view mode
##   [ / ] march step · P print camera · ESC quit
var _mat: ShaderMaterial
var _pos := Vector3(0.0, -1500.0, 0.0)
var _yaw := 0.0
var _pitch := -10.0
var _mode := 2
var _step := 25.0
var _held := {}
const mouse_sens := 0.12

func _initialize() -> void:
	var mi := MeshInstance3D.new()
	var q := QuadMesh.new(); q.size = Vector2(2, 2)
	mi.mesh = q
	mi.extra_cull_margin = 1e6
	_mat = ShaderMaterial.new()
	_mat.shader = load("res://shaders/submarine_probe.gdshader")
	mi.material_override = _mat
	root.add_child(mi)
	var cam := Camera3D.new(); cam.current = true
	root.add_child(cam)
	var w := root.get_window()
	if w:
		# 640x400: the marcher is ~110 density evaluations per PIXEL, so
		# resolution is a direct multiplier on frame time.
		w.size = Vector2i(640, 400)
		w.title = "seabed density — raymarched"
	# A SceneTree script never receives _input, so the look has to be POLLED.
	# get_last_mouse_velocity is in pixels/second, hence the dt.
	Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
	print("SUBVIEW: MOUSE look · WASD/QE move · SHIFT fast · V mode · [ ] quality · P print · ESC quit")
	print("  640x400, ~110 density evals per pixel — [ is finer+slower, ] coarser+faster")

func _process(dt: float) -> bool:
	if Input.is_key_pressed(KEY_ESCAPE):
		Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
		quit(0); return true
	var mv := Input.get_last_mouse_velocity()
	_yaw -= mv.x * dt * mouse_sens
	_pitch = clampf(_pitch - mv.y * dt * mouse_sens, -89.0, 89.0)
	# Arrows kept as a fallback: mouse velocity reads 0 on some setups and a
	# viewer you cannot turn is no viewer at all.
	var look := 60.0 * dt
	if Input.is_key_pressed(KEY_LEFT):  _yaw += look
	if Input.is_key_pressed(KEY_RIGHT): _yaw -= look
	if Input.is_key_pressed(KEY_UP):    _pitch = clampf(_pitch + look, -89.0, 89.0)
	if Input.is_key_pressed(KEY_DOWN):  _pitch = clampf(_pitch - look, -89.0, 89.0)
	var b := Basis.from_euler(Vector3(deg_to_rad(_pitch), deg_to_rad(_yaw), 0.0))
	var speed := (4000.0 if Input.is_key_pressed(KEY_SHIFT) else 400.0) * dt
	if Input.is_key_pressed(KEY_W): _pos -= b.z * speed
	if Input.is_key_pressed(KEY_S): _pos += b.z * speed
	if Input.is_key_pressed(KEY_A): _pos -= b.x * speed
	if Input.is_key_pressed(KEY_D): _pos += b.x * speed
	if Input.is_key_pressed(KEY_E): _pos.y += speed
	if Input.is_key_pressed(KEY_Q): _pos.y -= speed
	_edge(KEY_V, func(): _mode = (_mode + 1) % 3; print("  view mode %d" % _mode))
	_edge(KEY_BRACKETLEFT, func(): _step = maxf(2.0, _step * 0.7); print("  step %.1f m" % _step))
	_edge(KEY_BRACKETRIGHT, func(): _step = minf(400.0, _step / 0.7); print("  step %.1f m" % _step))
	_edge(KEY_P, func(): print("  cam %s  yaw %.0f pitch %.0f  step %.1f"
			% [str(_pos.round()), _yaw, _pitch, _step]))
	_mat.set_shader_parameter(&'cam_pos', _pos)
	_mat.set_shader_parameter(&'cam_fwd', -b.z)
	_mat.set_shader_parameter(&'cam_right', b.x)
	_mat.set_shader_parameter(&'cam_up', b.y)
	_mat.set_shader_parameter(&'view_mode', _mode)
	_mat.set_shader_parameter(&'march_step', _step)
	_mat.set_shader_parameter(&'march_footprint', _step)
	return false

func _edge(key: int, fn: Callable) -> void:
	var down: bool = Input.is_key_pressed(key)
	if down and not _held.get(key, false): fn.call()
	_held[key] = down