OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-tps / addons / sky3d_extended / src / StarField.gd

85 lines · gd ref:
@tool
class_name StarField
extends MultiMeshInstance3D

@export var catalog_path: String = "res://addons/sky3d_extended/data/bright_stars.dat"
@export_range(0.0, 6.5) var limiting_magnitude: float = 6.5
@export var scintillation_strength: float = 0.3
@export var star_distance: float = 3500.0

const STAR_PSF_SHADER = preload("res://addons/sky3d_extended/shaders/star_psf.gdshader")
const PSF_TEXTURE = preload("res://addons/sky3d_extended/assets/star_psf.png")

func _ready() -> void:
	_build_star_mesh()

func _build_star_mesh() -> void:
	var file := FileAccess.open(catalog_path, FileAccess.READ)
	if not file:
		push_warning("StarField: Cannot open " + catalog_path)
		return

	var header := file.get_line()
	var stars: Array[Dictionary] = []
	while not file.eof_reached():
		var line := file.get_line().strip_edges()
		if line.is_empty():
			continue
		var parts := line.split(",")
		if parts.size() < 4:
			continue
		var mag := parts[2].to_float()
		if mag > limiting_magnitude:
			continue
		stars.append({
			"ra": parts[0].to_float(),
			"dec": parts[1].to_float(),
			"mag": mag,
			"bv": parts[3].to_float(),
		})

	var mm := MultiMesh.new()
	mm.transform_format = MultiMesh.TRANSFORM_3D
	mm.use_custom_data = true
	mm.instance_count = stars.size()

	var quad := QuadMesh.new()
	quad.size = Vector2(20, 20)
	mm.mesh = quad

	for i in stars.size():
		var s := stars[i]
		var ra_rad: float = s["ra"] * TAU / 24.0
		var dec_rad: float = deg_to_rad(s["dec"])

		var x := star_distance * cos(dec_rad) * cos(ra_rad)
		var y := star_distance * sin(dec_rad)
		var z := star_distance * cos(dec_rad) * sin(ra_rad)

		var t := Transform3D()
		t.origin = Vector3(x, y, z)
		mm.set_instance_transform(i, t)

		var seed_val := fmod(s["ra"] * 1000.0 + s["dec"] * 100.0, 1.0)
		mm.set_instance_custom_data(i, Color(s["mag"], s["bv"], seed_val, 0.0))

	multimesh = mm

	var mat := ShaderMaterial.new()
	mat.shader = STAR_PSF_SHADER
	mat.set_shader_parameter("scintillation_strength", scintillation_strength)
	mat.set_shader_parameter("psf_texture", PSF_TEXTURE)
	material_override = mat

	print("StarField: Loaded %d stars" % stars.size())

## Rotate the MultiMesh to match sidereal time for smooth per-frame star rotation.
func update_rotation(sidereal_rotation: float, tilt: float) -> void:
	var t := Basis.from_euler(Vector3(tilt, 0.0, 0.0), EULER_ORDER_XYZ)
	var r := Basis.from_euler(Vector3(0.0, sidereal_rotation, 0.0), EULER_ORDER_XYZ)
	transform = Transform3D(r * t, Vector3.ZERO)


func set_sky_brightness(brightness: float) -> void:
	visible = brightness < 0.3