284 lines
8.1 KiB
Markdown
284 lines
8.1 KiB
Markdown
# 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
|
|
1. Open your Godot 4.6 project
|
|
2. Wait for the editor to import all scripts (check the bottom progress bar)
|
|
3. If you see script errors, click **Project > Reload Current Project**
|
|
|
|
### Step 2: Add to Your Scene
|
|
1. Open the scene where you want the sky system
|
|
2. Drag `dynamic-sky/dynamic_sky.tscn` into your scene tree
|
|
3. 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:
|
|
|
|
1. Select the **DynamicSky** node
|
|
2. In the Inspector, under **Environment**:
|
|
- Assign your existing `WorldEnvironment` node (or leave empty to auto-create)
|
|
- Assign existing `DirectionalLight3D` for sun/moon (or leave empty)
|
|
|
|
### Step 4: Generate Cloud Textures
|
|
Clouds need textures. Use the procedural generator:
|
|
|
|
```gdscript
|
|
# 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
|
|
```gdscript
|
|
var shadow_tex = ProceduralCloudTexture.create_shadow_texture()
|
|
$DynamicSky/ShadowProxySystem.shadow_texture = shadow_tex
|
|
```
|
|
|
|
## Testing the System
|
|
|
|
### Test 1: Basic Scene Test
|
|
1. Create a new 3D scene with a `Camera3D` and a `MeshInstance3D` (e.g., plane for ground)
|
|
2. Instance `dynamic_sky.tscn`
|
|
3. Run the scene (F5)
|
|
4. You should see a gradient sky with sun light
|
|
|
|
### Test 2: Time of Day
|
|
Add this script to test time changes:
|
|
|
|
```gdscript
|
|
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
|
|
```gdscript
|
|
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
|
|
1. Add a `CanvasLayer` to your scene
|
|
2. Add a `Control` node as child
|
|
3. Attach the `sky_debug_panel.gd` script
|
|
4. In Inspector, assign the `DynamicSky` node to the `dynamic_sky` property
|
|
5. Run and use the UI controls
|
|
|
|
### Test 5: Meteor Shower
|
|
```gdscript
|
|
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
|
|
1. Add an `Area3D` to your scene
|
|
2. Attach `weather_kill_volume.gd` script
|
|
3. Configure the shape and size in Inspector
|
|
4. 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:
|
|
```gdscript
|
|
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
|
|
|
|
1. Add `dynamic_sky.tscn` to your scene
|
|
2. Reference the DynamicSky node in your scripts
|
|
3. Use the API:
|
|
|
|
```gdscript
|
|
# 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 parameters
|
|
- `SkyPreset`: Complete preset configuration
|
|
- `WeatherProfile`: Per-weather-state settings
|
|
- `CloudLayerConfig`: Per-layer cloud settings
|
|
- `PostProcessProfile`: Post-processing parameters
|
|
|
|
## Performance
|
|
|
|
- Disable unused cloud layers
|
|
- Reduce cloud texture resolution
|
|
- Lower VFX update rates
|
|
- Disable shadow blur on low-end hardware
|