1+ @tool
12extends Node3D
23
34@onready var mesh_instance = $ MeshInstance3D
45@onready var collision_shape_instance = $ CollisionShape3D
56
7+ @export var regenerate_in_editor : bool = false : set = _regenerate_in_editor_button
8+
9+ @export_group ("Dimensions" )
610@export var radius : float = 200000.0
7- @export var rotation_speed : float = 0.005
8- @export var gravitational_pull : float = 3e9
911@export var segments : int = 128
10-
11- # Terrain noise controls
12+ @export_group ("Terrain Noise" )
1213@export var relief_scale : float = 0.06
14+ @export_group ("Base Noise" )
1315@export var base_frequency : float = 0.08
1416@export var base_octaves : int = 4
1517@export var base_lacunarity : float = 2.0
1618@export var base_gain : float = 0.45
19+ @export_group ("Detail Noise" )
1720@export var detail_frequency : float = 2.5
1821@export var detail_octaves : int = 4
1922@export var detail_lacunarity : float = 2.2
2023@export var detail_gain : float = 0.48
24+ @export_group ("Micro Noise" )
2125@export var micro_frequency : float = 6.0
2226@export var micro_octaves : int = 3
2327@export var micro_lacunarity : float = 2.4
2428@export var micro_gain : float = 0.52
2529@export var micro_strength : float = 0.25
26-
27- # Terrain flattening controls (flatten small variations into broader flats)
30+ @export_group ("Feature Shaping" )
2831@export var flatten_deadband : float = 0.15
29-
30- # Feature shaping controls
3132@export var terrace_steps : int = 7
3233@export var terrace_strength : float = 3
3334@export var range_strength : float = 0.35
3435@export var range_frequency_main : float = 1.6
3536@export var range_anisotropy : float = 0.2
3637@export var range_rotation_deg : float = 47.0
37-
38- # Polar ice cap controls
39- @export var ice_cap_latitude_start : float = 0.95 # Latitude where the transition to ice caps begins
40- @export var ice_cap_latitude_full : float = 0.96 # Latitude where the transition to ice caps is complete
41- @export var ice_cap_height_bias : float = 0.35 # Raised height of the final ice cap, relative to relief_scale
42-
43- # Mesh smoothing/triangulation controls
38+ @export_group ("Polar Ice Caps" )
39+ @export var ice_cap_latitude_start : float = 0.82 # Latitude where the transition to ice caps begins
40+ @export var ice_cap_latitude_full : float = 0.86 # Latitude where the transition to ice caps is complete
41+ @export var ice_cap_height_bias : float = 0.25 # Raised height of the final ice cap, relative to relief_scale
42+ @export_group ("Mesh Quality" )
4443@export var smooth_iterations : int = 0
4544@export var smooth_lambda : float = 0.5
4645@export var alternate_quad_diagonals : bool = true
47-
48- # Performance controls
46+ @export_group ("Performance" )
4947@export var use_threaded_generation : bool = false
5048@export var generation_chunk_size : int = 8
51-
52- # Atmosphere controls
49+ @export_group ("Physics" )
50+ @export var rotation_speed : float = 0.005
51+ @export var gravitational_pull : float = 3e9
52+ @export_group ("Atmosphere" )
5353@export var atmosphere_height_scale : float = 0.4 # fraction of radius
5454@export var atmosphere_intensity : float = 0.5
5555@export var atmosphere_mie_intensity : float = 0.3
@@ -58,8 +58,7 @@ extends Node3D
5858@export var atmosphere_mie_color : Color = Color (1.0 , 0.95 , 0.9 )
5959@export var atmosphere_segments : int = 32
6060@export var use_mesh_atmosphere : bool = true
61-
62- # Scatter (pebbles/boulders) controls
61+ @export_group ("Scatter" )
6362@export var enable_scatter : bool = true
6463@export var scatter_radius : float = 800.0
6564@export var scatter_rebuild_move_deg : float = 2.0
@@ -76,6 +75,7 @@ extends Node3D
7675@export var scatter_color_boulder : Color = Color (0.26 , 0.18 , 0.14 )
7776@export var scatter_draw_distance : float = 8000.0
7877@export var scatter_update_interval : float = 0.25
78+ @export_group ("" ) # End groups
7979
8080var noise : FastNoiseLite = FastNoiseLite .new () # detail
8181var noise_base : FastNoiseLite = FastNoiseLite .new ()
@@ -111,29 +111,7 @@ var atmosphere_material: ShaderMaterial
111111
112112func _ready () -> void :
113113 # Configure noise
114- noise .seed = randi ()
115- noise .noise_type = FastNoiseLite .TYPE_PERLIN
116- noise .fractal_type = FastNoiseLite .FRACTAL_FBM
117- noise .frequency = detail_frequency
118- noise .fractal_octaves = detail_octaves
119- noise .fractal_lacunarity = detail_lacunarity
120- noise .fractal_gain = detail_gain
121-
122- noise_base .seed = randi () + 1337
123- noise_base .noise_type = FastNoiseLite .TYPE_PERLIN
124- noise_base .fractal_type = FastNoiseLite .FRACTAL_RIDGED
125- noise_base .frequency = base_frequency
126- noise_base .fractal_octaves = base_octaves
127- noise_base .fractal_lacunarity = base_lacunarity
128- noise_base .fractal_gain = base_gain
129-
130- noise_micro .seed = randi () + 4242
131- noise_micro .noise_type = FastNoiseLite .TYPE_SIMPLEX
132- noise_micro .fractal_type = FastNoiseLite .FRACTAL_FBM
133- noise_micro .frequency = micro_frequency
134- noise_micro .fractal_octaves = micro_octaves
135- noise_micro .fractal_lacunarity = micro_lacunarity
136- noise_micro .fractal_gain = micro_gain
114+ _configure_noise_instances ()
137115
138116 # Cache a basis to orient mountain ranges (deterministic)
139117 var axis : Vector3 = Vector3 (0.42 , 0.86 , 0.27 ).normalized ()
@@ -535,6 +513,7 @@ func create_planet_material() -> ShaderMaterial:
535513 material .set_shader_parameter ("planet_radius" , radius )
536514 material .set_shader_parameter ("detail_scale" , 24.0 )
537515 material .set_shader_parameter ("detail_strength" , 0.15 )
516+ material .set_shader_parameter ("ground_texture" , load ("res://art/images/ground.jpg" ))
538517 material .set_shader_parameter ("normal_strength" , 0.0 )
539518 material .set_shader_parameter ("detail_fade_start" , radius * 0.6 )
540519 material .set_shader_parameter ("detail_fade_end" , radius * 3.0 )
@@ -549,6 +528,17 @@ func create_planet_material() -> ShaderMaterial:
549528 material .set_shader_parameter ("atmo_mie_color" , atmosphere_mie_color )
550529 return material
551530
531+ func _process (_delta : float ):
532+ # In the editor or at runtime, the separate atmosphere mesh needs continuous updates
533+ # to correctly calculate its appearance based on camera position. This will not
534+ # reintroduce shadow artifacts as the atmosphere mesh does not cast shadows.
535+ if use_mesh_atmosphere :
536+ if not is_instance_valid (atmosphere_material ):
537+ return
538+ # Only update if the node is visible and in a viewport
539+ if is_visible_in_tree () and get_viewport ():
540+ _update_atmosphere_params ()
541+
552542func _physics_process (delta : float ) -> void :
553543 if not initialized :
554544 return
@@ -560,8 +550,11 @@ func _physics_process(delta: float) -> void:
560550 if is_instance_valid (landing_static_body ):
561551 landing_static_body .constant_angular_velocity = Vector3 (0.0 , rotation_speed , 0.0 )
562552
563- # Disable continuous atmosphere updates to prevent rolling shadows
564- # Atmosphere parameters will be set once at initialization
553+ # Atmosphere is a separate visual effect and must be updated each frame
554+ # to work correctly from different camera angles. It does not cast shadows,
555+ # so this will not reintroduce the rolling shadow artifacts on the surface.
556+ if use_mesh_atmosphere :
557+ _update_atmosphere_params ()
565558
566559 # Apply gravitational pull only to bodies that aren't too far
567560 for body in get_tree ().get_nodes_in_group ("affected_by_gravity" ):
@@ -984,3 +977,41 @@ func _generate_scatter_for_center(center_dir: Vector3) -> void:
984977 while idx_p < pebble_count :
985978 pebbles_mmi .multimesh .set_instance_transform (idx_p , Transform3D ())
986979 idx_p += 1
980+
981+ # Setter functions for live parameter updates in editor
982+ func _regenerate_in_editor_button (_value : bool ):
983+ if Engine .is_editor_hint ():
984+ print ("Regenerating planet in editor..." )
985+ _configure_noise_instances ()
986+ var axis : Vector3 = Vector3 (0.42 , 0.86 , 0.27 ).normalized ()
987+ range_basis = Basis (axis , deg_to_rad (range_rotation_deg ))
988+ generate_planet ()
989+ if use_mesh_atmosphere :
990+ _create_or_update_atmosphere ()
991+ print ("Regeneration complete." )
992+
993+ func _configure_noise_instances ():
994+ # Configure noise
995+ noise .seed = randi ()
996+ noise .noise_type = FastNoiseLite .TYPE_PERLIN
997+ noise .fractal_type = FastNoiseLite .FRACTAL_FBM
998+ noise .frequency = detail_frequency
999+ noise .fractal_octaves = detail_octaves
1000+ noise .fractal_lacunarity = detail_lacunarity
1001+ noise .fractal_gain = detail_gain
1002+
1003+ noise_base .seed = randi () + 1337
1004+ noise_base .noise_type = FastNoiseLite .TYPE_PERLIN
1005+ noise_base .fractal_type = FastNoiseLite .FRACTAL_RIDGED
1006+ noise_base .frequency = base_frequency
1007+ noise_base .fractal_octaves = base_octaves
1008+ noise_base .fractal_lacunarity = base_lacunarity
1009+ noise_base .fractal_gain = base_gain
1010+
1011+ noise_micro .seed = randi () + 4242
1012+ noise_micro .noise_type = FastNoiseLite .TYPE_SIMPLEX
1013+ noise_micro .fractal_type = FastNoiseLite .FRACTAL_FBM
1014+ noise_micro .frequency = micro_frequency
1015+ noise_micro .fractal_octaves = micro_octaves
1016+ noise_micro .fractal_lacunarity = micro_lacunarity
1017+ noise_micro .fractal_gain = micro_gain
0 commit comments