OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-tps / scenes / test / test_nubis_sky_layer.gd

95 lines · gd ref:
extends Node3D

## Test scene: single massive cloud volume covering the sky
## The Schneider density + weather map creates all cloud formations procedurally
## F12: screenshot

var _sky_mat: ShaderMaterial

func _ready() -> void:
	# Sky shader for background
	var shader := load("res://addons/nubis_clouds/shaders/cloud_sky.gdshader") as Shader
	if shader:
		_sky_mat = ShaderMaterial.new()
		_sky_mat.shader = shader
		var pw_tex = load("res://addons/nubis_clouds/textures/perlworlnoise.png")
		var worl_tex = load("res://addons/nubis_clouds/textures/worlnoise.webp")
		var weather_tex = load("res://addons/nubis_clouds/textures/weather.webp")
		if pw_tex: _sky_mat.set_shader_parameter("perlworlnoise", pw_tex)
		if worl_tex: _sky_mat.set_shader_parameter("worlnoise", worl_tex)
		if weather_tex: _sky_mat.set_shader_parameter("weather_map", weather_tex)
		_sky_mat.set_shader_parameter("cloud_coverage", 0.35)
		_sky_mat.set_shader_parameter("cloud_time_scale", 2.0)
		var sky := Sky.new()
		sky.sky_material = _sky_mat
		sky.process_mode = Sky.PROCESS_MODE_REALTIME
		var env: Environment = $WorldEnvironment.environment
		env.background_mode = Environment.BG_SKY
		env.sky = sky

	# Compositor
	var compositor := Compositor.new()
	var nubis_comp := NubisCompositor.new()
	nubis_comp.shader_file = "res://addons/nubis_clouds/experimental/cloud_compositor_sky.glsl"
	nubis_comp.enabled_setting = true
	nubis_comp.density_scale = 80.0
	nubis_comp.noise_freq = 0.002
	nubis_comp.erosion_strength = 0.6
	compositor.compositor_effects = [nubis_comp]
	$WorldEnvironment.compositor = compositor

	# ONE massive sky-layer volume
	# Schneider density + weather map will create all cloud formations within it
	var sdf := _make_sky_layer_sdf(32)
	var cloud := CloudVolume.new()
	cloud.shared_sdf = sdf
	cloud.position = Vector3(0, 350, 0)
	cloud.cloud_size = Vector3(10000, 700, 10000)  # 10km x 700m x 10km (bottom at 0m, top at 700m)
	cloud.density_scale = 80.0
	cloud.wind_speed = 0.02
	cloud.wrap_distance = 0.0  # no wrap — volume follows camera instead
	add_child(cloud)

	print("[Nubis SkyLayer] 10km cloud volume active")


func _process(_delta: float) -> void:
	# Re-center the cloud volume on camera XZ so it always covers the sky
	var cam := get_viewport().get_camera_3d()
	if cam:
		var cloud := get_child(get_child_count() - 1) as CloudVolume
		if cloud:
			cloud.position.x = cam.global_position.x
			cloud.position.z = cam.global_position.z


func _make_sky_layer_sdf(res: int) -> ImageTexture3D:
	# Flat 1.0 everywhere — ALL shaping done in shader
	# No baked height gradient = no visible banding when inside the volume
	var images: Array[Image] = []
	for z in res:
		var img := Image.create(res, res, false, Image.FORMAT_RF)
		img.fill(Color(1.0, 0, 0, 1))
		images.append(img)
	var tex := ImageTexture3D.new()
	tex.create(Image.FORMAT_RF, res, res, res, false, images)
	return tex


func _smoothstep(edge0: float, edge1: float, x: float) -> float:
	var t := clampf((x - edge0) / (edge1 - edge0), 0.0, 1.0)
	return t * t * (3.0 - 2.0 * t)


func _unhandled_input(event: InputEvent) -> void:
	if event is InputEventKey and event.pressed:
		match event.keycode:
			KEY_F12:
				var img := get_viewport().get_texture().get_image()
				var ts := Time.get_datetime_string_from_system().replace(":", "-")
				var dir := "/home/fleeky/Desktop/hyper-tps"
				DirAccess.make_dir_recursive_absolute(dir)
				var path := "%s/nubis_skylayer_%s.png" % [dir, ts]
				img.save_png(path)
				print("[Nubis SkyLayer] Screenshot: %s" % path)