extends SceneTree
## INTERACTIVE preview of the density field's normals, on a full-window plane.
##
## The probe shaders elsewhere are painted on a 1 m cube and a 4 m quad, so they
## sample one flat spot of a 60 km world and correctly show one flat colour.
## This maps the plane's UV across a real world span instead, and lets you move
## it, so the shading can be judged before any of it reaches a map.
##
## DISPLAY=:0 "$HYPER_TPS_GODOT" --path . --rendering-driver vulkan \
## --script res://scenes/test/density_viewer.gd
##
## W A S D pan Z / X zoom out / in
## Q / E sample Y down / up
## V view: normal-RGB / lambert / lookdev material / hypso ramp
## arrows move the sun T 1-tap analytic vs 4-tap central diffs
## R reset ESC quit
var _mat: ShaderMaterial
var _origin := Vector2(0, 0)
var _span := 60000.0
var _y := 0.0
var _view := 2
var _sun_az := 0.9
var _sun_el := 0.6
var _taps := 4
var _dirty := true
func _initialize() -> void:
var mi := MeshInstance3D.new()
var q := QuadMesh.new(); q.size = Vector2(4, 4)
mi.mesh = q
mi.extra_cull_margin = 1e5
_mat = ShaderMaterial.new()
_mat.shader = load("res://shaders/density_probe.gdshader")
mi.material_override = _mat
root.add_child(mi)
var cam := Camera3D.new(); cam.position = Vector3(0, 0, 1.9); cam.current = true
root.add_child(cam)
var w := root.get_window()
if w:
w.size = Vector2i(1280, 1280)
w.title = "density field — normals"
print("VIEWER: WASD pan · Z/X zoom · Q/E sample Y · N view · T taps · R reset · ESC quit")
func _process(dt: float) -> bool:
if Input.is_key_pressed(KEY_ESCAPE):
quit(0); return true
var pan := _span * 0.5 * dt
if Input.is_key_pressed(KEY_A): _origin.x -= pan; _dirty = true
if Input.is_key_pressed(KEY_D): _origin.x += pan; _dirty = true
if Input.is_key_pressed(KEY_W): _origin.y -= pan; _dirty = true
if Input.is_key_pressed(KEY_S): _origin.y += pan; _dirty = true
if Input.is_key_pressed(KEY_Z): _span *= 1.0 + dt; _dirty = true
if Input.is_key_pressed(KEY_X): _span /= 1.0 + dt; _dirty = true
if Input.is_key_pressed(KEY_Q): _y -= 2000.0 * dt; _dirty = true
if Input.is_key_pressed(KEY_E): _y += 2000.0 * dt; _dirty = true
_edge(KEY_V, "_view")
_edge(KEY_T, "_taps")
if Input.is_key_pressed(KEY_LEFT): _sun_az -= 1.5 * dt; _dirty = true
if Input.is_key_pressed(KEY_RIGHT): _sun_az += 1.5 * dt; _dirty = true
if Input.is_key_pressed(KEY_DOWN): _sun_el = max(0.05, _sun_el - 1.0 * dt); _dirty = true
if Input.is_key_pressed(KEY_UP): _sun_el = min(1.50, _sun_el + 1.0 * dt); _dirty = true
if Input.is_key_pressed(KEY_R):
_origin = Vector2(0, 0); _span = 60000.0; _y = 0.0
_sun_az = 0.9; _sun_el = 0.6; _dirty = true
if _dirty:
_span = clamp(_span, 200.0, 200000.0)
_mat.set_shader_parameter("probe_world_span", _span)
_mat.set_shader_parameter("probe_world_origin", _origin)
_mat.set_shader_parameter("probe_world_y", _y)
_mat.set_shader_parameter("probe_view", _view)
_mat.set_shader_parameter("probe_taps", _taps)
_mat.set_shader_parameter("probe_sun", Vector3(
cos(_sun_el) * cos(_sun_az), sin(_sun_el), cos(_sun_el) * sin(_sun_az)))
var vn := ["normal-RGB", "lambert", "lookdev material", "hypso ramp"]
print(" span %8.0f m (%5.1f m/px) origin (%7.0f,%7.0f) y %6.0f sun %4.2f/%4.2f %s %d-tap"
% [_span, _span / 1280.0, _origin.x, _origin.y, _y,
_sun_az, _sun_el, vn[_view], _taps])
_dirty = false
return false
var _held := {}
func _edge(key: int, which: String) -> void:
var down: bool = Input.is_key_pressed(key)
if down and not _held.get(key, false):
if which == "_view": _view = (_view + 1) % 4
else: _taps = 1 if _taps == 4 else 4
_dirty = true
_held[key] = down