Dynamic Sky System for Godot 4.6
A stylized dynamic sky system with day/night cycles, weather, clouds, and VFX.
Setup Instructions
Step 1: Open Project in Godot
- Open your Godot 4.6 project
- Wait for the editor to import all scripts (check the bottom progress bar)
- If you see script errors, click Project > Reload Current Project
Step 2: Add to Your Scene
- Open the scene where you want the sky system
- Drag
dynamic-sky/dynamic_sky.tscninto your scene tree - Or right-click in the scene tree → Instance Child Scene → select
dynamic_sky.tscn
Step 3: Configure the Environment
The DynamicSky node auto-creates required children. To link an existing environment:
- Select the DynamicSky node
- In the Inspector, under Environment:
- Assign your existing
WorldEnvironmentnode (or leave empty to auto-create) - Assign existing
DirectionalLight3Dfor sun/moon (or leave empty)
- Assign your existing
Step 4: Generate Cloud Textures
Clouds need textures. Use the procedural generator:
# In a tool script or _ready():
var cloud_tex = ProceduralCloudTexture.create_default_cloud_texture(1)
$DynamicSky/CloudSystem.layer_configs[0].texture = cloud_tex
Or assign existing cloud textures to each CloudLayerConfig in the Inspector.
Step 5: Configure Shadow Texture
var shadow_tex = ProceduralCloudTexture.create_shadow_texture()
$DynamicSky/ShadowProxySystem.shadow_texture = shadow_tex
Testing the System
Test 1: Basic Scene Test
- Create a new 3D scene with a
Camera3Dand aMeshInstance3D(e.g., plane for ground) - Instance
dynamic_sky.tscn - Run the scene (F5)
- You should see a gradient sky with sun light
Test 2: Time of Day
Add this script to test time changes:
extends Node
@onready var sky = $DynamicSky
func _ready():
# Start at morning
sky.set_time_of_day(0.25)
func _process(delta):
# Press keys to change time
if Input.is_action_just_pressed("ui_right"):
sky.set_time_of_day(sky.get_time_of_day() + 0.05)
if Input.is_action_just_pressed("ui_left"):
sky.set_time_of_day(sky.get_time_of_day() - 0.05)
# Print current time
if Input.is_action_just_pressed("ui_accept"):
print("Time: ", sky.get_time_of_day())
Test 3: Weather System
func _input(event):
if event.is_action_pressed("ui_up"):
$DynamicSky.set_weather(WeatherProfile.WeatherState.RAIN)
if event.is_action_pressed("ui_down"):
$DynamicSky.set_weather(WeatherProfile.WeatherState.CLEAR)
Test 4: Debug Panel
- Add a
CanvasLayerto your scene - Add a
Controlnode as child - Attach the
sky_debug_panel.gdscript - In Inspector, assign the
DynamicSkynode to thedynamic_skyproperty - Run and use the UI controls
Test 5: Meteor Shower
func _ready():
# Ensure it's night for visibility
$DynamicSky.set_time_of_day(0.0)
# Wait a moment then trigger
await get_tree().create_timer(1.0).timeout
$DynamicSky.trigger_meteor_shower(30.0)
Test 6: Kill Volumes
- Add an
Area3Dto your scene - Attach
weather_kill_volume.gdscript - Configure the shape and size in Inspector
- Precipitation will be blocked inside this volume
Complete Test Scene Example
Create a new scene with this structure:
TestScene (Node3D)
├── DynamicSky (instance of dynamic_sky.tscn)
├── Camera3D
├── Ground (MeshInstance3D with PlaneMesh)
├── CanvasLayer
│ └── DebugPanel (Control with sky_debug_panel.gd)
└── TestScript (Node with test script below)
Test script:
extends Node
@onready var sky = $"../DynamicSky"
func _ready():
# Generate cloud textures
_setup_clouds()
# Start at mid-morning
sky.set_time_of_day(0.35)
print("Dynamic Sky Test Ready!")
print("Arrow keys: Change time")
print("1-6: Change weather")
print("M: Meteor shower")
print("P: Pause/Resume time")
func _setup_clouds():
var cloud_system = sky.cloud_system
if cloud_system:
for i in cloud_system.layer_configs.size():
var tex = ProceduralCloudTexture.create_default_cloud_texture(i)
cloud_system.layer_configs[i].texture = tex
cloud_system.rebuild_layers()
var shadow_system = sky.shadow_proxy_system
if shadow_system:
shadow_system.shadow_texture = ProceduralCloudTexture.create_shadow_texture()
func _input(event):
if event is InputEventKey and event.pressed:
match event.keycode:
KEY_RIGHT:
sky.set_time_of_day(wrapf(sky.get_time_of_day() + 0.02, 0, 1))
KEY_LEFT:
sky.set_time_of_day(wrapf(sky.get_time_of_day() - 0.02, 0, 1))
KEY_1:
sky.set_weather(WeatherProfile.WeatherState.CLEAR)
KEY_2:
sky.set_weather(WeatherProfile.WeatherState.CLOUDY)
KEY_3:
sky.set_weather(WeatherProfile.WeatherState.OVERCAST)
KEY_4:
sky.set_weather(WeatherProfile.WeatherState.RAIN)
KEY_5:
sky.set_weather(WeatherProfile.WeatherState.STORM)
KEY_6:
sky.set_weather(WeatherProfile.WeatherState.SNOW)
KEY_M:
sky.trigger_meteor_shower(30.0)
KEY_P:
if sky.day_night_controller.paused:
sky.resume_time()
else:
sky.pause_time()
Troubleshooting
| Issue | Solution |
|---|---|
| Script errors on load | Reload project: Project → Reload Current Project |
| No sky visible | Ensure camera is looking up; check WorldEnvironment exists |
| Clouds not visible | Assign textures to CloudLayerConfig or generate procedurally |
| Shadows not visible | Assign shadow_texture to ShadowProxySystem |
| Stars not visible | Set time to night (0.0 or 0.9+); check stars_visibility curve |
| Time not advancing | Check paused is false on DayNightController |
| Weather not changing | Check WeatherController has profiles; look at transition progress |
Features
Preset Skybox Nodes
- 6 presets: Clear Day, Sunset, Night, Overcast, Storm, Dawn
- Runtime preset switching with smooth transitions
- Non-destructive overrides
Day/Night Cycle
- Configurable day length (1-1440 minutes)
- Sun/moon arc movement
- Color/intensity curves for sun, moon, ambient, fog
- Star visibility at night
- Time events (sunrise, sunset, noon)
Weather System
- States: Clear, Cloudy, Overcast, Rain, Storm, Snow
- Smooth transitions between states
- Per-state cloud, wind, and VFX settings
- Random or scripted weather timelines
2D Cloudscapes
- 4 independent layers (low, mid, high, wisps)
- Per-layer texture, tiling, opacity, color
- Flow animation with wind influence
- Evolution/morphing over time
- Reactive to sun/moon lighting
Post-Processing
- Sky gradient shading
- Height and distance fog
- Sun glow halo
- Dawn/dusk enhancement
- Procedural stars
VFX
- Shooting stars (randomized)
- Meteor showers (event-triggered)
- Configurable appearance
Cloud Shadows
- Projected shadow overlay
- Syncs with cloud movement
- Blur and opacity controls
Kill Volumes
- Block precipitation in indoor areas
- Box, sphere, cylinder shapes
- Fade-out margins
Quick Start
- Add
dynamic_sky.tscnto your scene - Reference the DynamicSky node in your scripts
- Use the API:
# Get reference
@onready var sky = $DynamicSky
# Set time (0.0-1.0, where 0.5 = noon)
sky.set_time_of_day(0.5)
# Change weather
sky.set_weather(WeatherProfile.WeatherState.RAIN)
# Apply preset
sky.apply_preset("Sunset")
# Trigger meteor shower
sky.trigger_meteor_shower(60.0)
Debug Panel
Add SkyDebugPanel to your UI and assign the DynamicSky reference to see:
- Current time and weather
- Cloud coverage
- Controls for testing
Resources
SkyConfig: Global sky parametersSkyPreset: Complete preset configurationWeatherProfile: Per-weather-state settingsCloudLayerConfig: Per-layer cloud settingsPostProcessProfile: Post-processing parameters
Performance
- Disable unused cloud layers
- Reduce cloud texture resolution
- Lower VFX update rates
- Disable shadow blur on low-end hardware