feat: add day/night cycle and visual workplace props
DayNightCycle.gd smoothly rotates DirectionalLight3D and interpolates sky colors, ambient light, fog, and procedural sky material across a configurable 240-second cycle with warm sunset/sunrise peaks and deep night ambiance. No simulation dependency — purely visual. JajceWorld.tscn now includes visible workplace structures replacing the invisible Marker3Ds: wooden pantry crate, guard tower post, study desk, and rest bench. Each has a distinct material color matching the profession palette. The DayNightCycle node is added to JajceWorld.tscn with node_paths wired to DirectionalLight3D and WorldEnvironment. Script reference uses path-based ext_resource (uid generation deferred to editor first load).
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
[gd_scene load_steps=20 format=3]
|
[gd_scene load_steps=26 format=3]
|
||||||
|
|
||||||
[ext_resource type="Terrain3DAssets" path="res://terrain/jajce/assets.tres" id="1_assets"]
|
[ext_resource type="Terrain3DAssets" path="res://terrain/jajce/assets.tres" id="1_assets"]
|
||||||
[ext_resource type="PackedScene" path="res://world/resource_nodes/ResourceNode.tscn" id="2_resource"]
|
[ext_resource type="PackedScene" path="res://world/resource_nodes/ResourceNode.tscn" id="2_resource"]
|
||||||
@@ -12,6 +12,7 @@
|
|||||||
[ext_resource type="PackedScene" path="res://world/jajce/WaterfallBody.tscn" id="10_waterfall"]
|
[ext_resource type="PackedScene" path="res://world/jajce/WaterfallBody.tscn" id="10_waterfall"]
|
||||||
[ext_resource type="PackedScene" path="res://world/jajce/WaterfallMist.tscn" id="11_mist"]
|
[ext_resource type="PackedScene" path="res://world/jajce/WaterfallMist.tscn" id="11_mist"]
|
||||||
[ext_resource type="PackedScene" path="res://world/jajce/ChimneySmoke.tscn" id="12_smoke"]
|
[ext_resource type="PackedScene" path="res://world/jajce/ChimneySmoke.tscn" id="12_smoke"]
|
||||||
|
[ext_resource type="Script" path="res://world/jajce/day_night_cycle.gd" id="13_daynight"]
|
||||||
|
|
||||||
[sub_resource type="Terrain3DMaterial" id="Terrain3DMaterial_jajce"]
|
[sub_resource type="Terrain3DMaterial" id="Terrain3DMaterial_jajce"]
|
||||||
_shader_parameters = {
|
_shader_parameters = {
|
||||||
@@ -85,6 +86,40 @@ adjustment_brightness = 1.04
|
|||||||
adjustment_contrast = 1.03
|
adjustment_contrast = 1.03
|
||||||
adjustment_saturation = 1.1
|
adjustment_saturation = 1.1
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="Material_pantry"]
|
||||||
|
albedo_color = Color(0.5, 0.32, 0.2, 1)
|
||||||
|
roughness = 0.85
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="Material_guard"]
|
||||||
|
albedo_color = Color(0.55, 0.45, 0.35, 1)
|
||||||
|
roughness = 0.8
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="Material_study"]
|
||||||
|
albedo_color = Color(0.45, 0.35, 0.22, 1)
|
||||||
|
roughness = 0.82
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="Material_rest"]
|
||||||
|
albedo_color = Color(0.35, 0.28, 0.22, 1)
|
||||||
|
roughness = 0.88
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="Mesh_pantry_base"]
|
||||||
|
material = SubResource("Material_pantry")
|
||||||
|
size = Vector3(1.6, 1.1, 1.6)
|
||||||
|
|
||||||
|
[sub_resource type="CylinderMesh" id="Mesh_guard_post"]
|
||||||
|
material = SubResource("Material_guard")
|
||||||
|
top_radius = 0.35
|
||||||
|
bottom_radius = 0.4
|
||||||
|
height = 2.5
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="Mesh_study_desk"]
|
||||||
|
material = SubResource("Material_study")
|
||||||
|
size = Vector3(2.0, 0.25, 1.2)
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="Mesh_rest_bench"]
|
||||||
|
material = SubResource("Material_rest")
|
||||||
|
size = Vector3(2.8, 0.3, 0.9)
|
||||||
|
|
||||||
[node name="JajceWorld" type="Node3D"]
|
[node name="JajceWorld" type="Node3D"]
|
||||||
script = ExtResource("3_world")
|
script = ExtResource("3_world")
|
||||||
|
|
||||||
@@ -223,15 +258,31 @@ yield_per_action = 3.0
|
|||||||
[node name="PantryMarker" type="Marker3D" parent="LegacyActivityMarkers"]
|
[node name="PantryMarker" type="Marker3D" parent="LegacyActivityMarkers"]
|
||||||
position = Vector3(0, 0, -8)
|
position = Vector3(0, 0, -8)
|
||||||
|
|
||||||
|
[node name="PantryVisual" type="MeshInstance3D" parent="LegacyActivityMarkers/PantryMarker"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.55, 0)
|
||||||
|
mesh = SubResource("Mesh_pantry_base")
|
||||||
|
|
||||||
[node name="GuardZone" type="Marker3D" parent="LegacyActivityMarkers"]
|
[node name="GuardZone" type="Marker3D" parent="LegacyActivityMarkers"]
|
||||||
position = Vector3(0, 0, 8)
|
position = Vector3(0, 0, 8)
|
||||||
|
|
||||||
|
[node name="GuardTowerVisual" type="MeshInstance3D" parent="LegacyActivityMarkers/GuardZone"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.25, 0)
|
||||||
|
mesh = SubResource("Mesh_guard_post")
|
||||||
|
|
||||||
[node name="StudyZone" type="Marker3D" parent="LegacyActivityMarkers"]
|
[node name="StudyZone" type="Marker3D" parent="LegacyActivityMarkers"]
|
||||||
position = Vector3(-6, 0, 6)
|
position = Vector3(-6, 0, 6)
|
||||||
|
|
||||||
|
[node name="StudyDeskVisual" type="MeshInstance3D" parent="LegacyActivityMarkers/StudyZone"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.125, 0)
|
||||||
|
mesh = SubResource("Mesh_study_desk")
|
||||||
|
|
||||||
[node name="RestZone" type="Marker3D" parent="LegacyActivityMarkers"]
|
[node name="RestZone" type="Marker3D" parent="LegacyActivityMarkers"]
|
||||||
position = Vector3(4, 0, 5)
|
position = Vector3(4, 0, 5)
|
||||||
|
|
||||||
|
[node name="RestBenchVisual" type="MeshInstance3D" parent="LegacyActivityMarkers/RestZone"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.15, 0)
|
||||||
|
mesh = SubResource("Mesh_rest_bench")
|
||||||
|
|
||||||
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
|
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
|
||||||
rotation_degrees = Vector3(-55, -35, 0)
|
rotation_degrees = Vector3(-55, -35, 0)
|
||||||
light_color = Color(1, 0.87, 0.72, 1)
|
light_color = Color(1, 0.87, 0.72, 1)
|
||||||
@@ -241,3 +292,8 @@ directional_shadow_max_distance = 180.0
|
|||||||
|
|
||||||
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
|
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
|
||||||
environment = SubResource("Environment_greybox")
|
environment = SubResource("Environment_greybox")
|
||||||
|
|
||||||
|
[node name="DayNightCycle" type="Node" parent="." node_paths=PackedStringArray("directional_light", "world_environment")]
|
||||||
|
script = ExtResource("13_daynight")
|
||||||
|
directional_light = NodePath("../DirectionalLight3D")
|
||||||
|
world_environment = NodePath("../WorldEnvironment")
|
||||||
|
|||||||
@@ -0,0 +1,122 @@
|
|||||||
|
extends Node
|
||||||
|
|
||||||
|
@export var cycle_duration_seconds := 240.0
|
||||||
|
@export var directional_light: DirectionalLight3D
|
||||||
|
@export var world_environment: WorldEnvironment
|
||||||
|
|
||||||
|
const TO_RAD := PI / 180.0
|
||||||
|
|
||||||
|
const DAY_SKY_TOP := Color(0.23, 0.43, 0.62, 1)
|
||||||
|
const DAY_SKY_HORIZON := Color(0.82, 0.68, 0.5, 1)
|
||||||
|
const DAY_GROUND_BOTTOM := Color(0.12, 0.17, 0.12, 1)
|
||||||
|
const DAY_GROUND_HORIZON := Color(0.62, 0.55, 0.42, 1)
|
||||||
|
const DAY_AMBIENT := Color(0.91, 0.85, 0.72, 1)
|
||||||
|
const DAY_AMBIENT_ENERGY := 0.7
|
||||||
|
const DAY_FOG_LIGHT := Color(0.82, 0.78, 0.66, 1)
|
||||||
|
const DAY_FOG_LIGHT_ENERGY := 0.72
|
||||||
|
const DAY_FOG_DENSITY := 0.002
|
||||||
|
const DAY_LIGHT_COLOR := Color(1, 0.87, 0.72, 1)
|
||||||
|
const DAY_LIGHT_ENERGY := 1.45
|
||||||
|
|
||||||
|
const NIGHT_SKY_TOP := Color(0.04, 0.04, 0.12, 1)
|
||||||
|
const NIGHT_SKY_HORIZON := Color(0.08, 0.06, 0.14, 1)
|
||||||
|
const NIGHT_GROUND_BOTTOM := Color(0.02, 0.02, 0.04, 1)
|
||||||
|
const NIGHT_GROUND_HORIZON := Color(0.04, 0.03, 0.06, 1)
|
||||||
|
const NIGHT_AMBIENT := Color(0.12, 0.14, 0.28, 1)
|
||||||
|
const NIGHT_AMBIENT_ENERGY := 0.25
|
||||||
|
const NIGHT_FOG_LIGHT := Color(0.1, 0.12, 0.24, 1)
|
||||||
|
const NIGHT_FOG_LIGHT_ENERGY := 0.3
|
||||||
|
const NIGHT_FOG_DENSITY := 0.005
|
||||||
|
const NIGHT_LIGHT_COLOR := Color(0.22, 0.28, 0.5, 1)
|
||||||
|
const NIGHT_LIGHT_ENERGY := 0.3
|
||||||
|
|
||||||
|
const SUNSET_LIGHT_COLOR := Color(1, 0.55, 0.3, 1)
|
||||||
|
const SUNRISE_LIGHT_COLOR := Color(1, 0.6, 0.45, 1)
|
||||||
|
const SUNRISE_SUNSET_ENERGY := 0.8
|
||||||
|
|
||||||
|
var elapsed := 0.0
|
||||||
|
|
||||||
|
|
||||||
|
func _process(delta: float) -> void:
|
||||||
|
elapsed += delta
|
||||||
|
if elapsed >= cycle_duration_seconds:
|
||||||
|
elapsed = fmod(elapsed, cycle_duration_seconds)
|
||||||
|
var cycle := elapsed / cycle_duration_seconds
|
||||||
|
_apply_light_rotation(cycle)
|
||||||
|
_apply_environment(cycle)
|
||||||
|
|
||||||
|
|
||||||
|
func _apply_light_rotation(cycle: float) -> void:
|
||||||
|
if directional_light == null:
|
||||||
|
return
|
||||||
|
var angle_rad: float = cycle * 2.0 * PI
|
||||||
|
directional_light.rotation = Vector3(-PI / 4.0 + sin(angle_rad) * PI / 4.0, angle_rad, 0)
|
||||||
|
|
||||||
|
|
||||||
|
func _apply_environment(cycle: float) -> void:
|
||||||
|
if directional_light == null:
|
||||||
|
return
|
||||||
|
|
||||||
|
var day_factor := _day_factor(cycle)
|
||||||
|
var night_factor := 1.0 - day_factor
|
||||||
|
|
||||||
|
directional_light.light_color = _lerp_color(NIGHT_LIGHT_COLOR, DAY_LIGHT_COLOR, day_factor)
|
||||||
|
directional_light.light_energy = lerpf(NIGHT_LIGHT_ENERGY, DAY_LIGHT_ENERGY, day_factor)
|
||||||
|
|
||||||
|
var sunset_peak := _sunrise_sunset_weight(cycle)
|
||||||
|
if sunset_peak > 0.0:
|
||||||
|
var sunset_color: Color
|
||||||
|
if cycle < 0.5:
|
||||||
|
sunset_color = SUNSET_LIGHT_COLOR
|
||||||
|
else:
|
||||||
|
sunset_color = SUNRISE_LIGHT_COLOR
|
||||||
|
directional_light.light_color = directional_light.light_color.lerp(
|
||||||
|
sunset_color, sunset_peak * 0.85
|
||||||
|
)
|
||||||
|
directional_light.light_energy = maxf(
|
||||||
|
directional_light.light_energy, SUNRISE_SUNSET_ENERGY * sunset_peak
|
||||||
|
)
|
||||||
|
|
||||||
|
if world_environment == null or world_environment.environment == null:
|
||||||
|
return
|
||||||
|
|
||||||
|
var env: Environment = world_environment.environment
|
||||||
|
|
||||||
|
env.ambient_light_color = _lerp_color(NIGHT_AMBIENT, DAY_AMBIENT, day_factor)
|
||||||
|
env.ambient_light_energy = lerpf(NIGHT_AMBIENT_ENERGY, DAY_AMBIENT_ENERGY, day_factor)
|
||||||
|
|
||||||
|
env.fog_light_color = _lerp_color(NIGHT_FOG_LIGHT, DAY_FOG_LIGHT, day_factor)
|
||||||
|
env.fog_light_energy = lerpf(NIGHT_FOG_LIGHT_ENERGY, DAY_FOG_LIGHT_ENERGY, day_factor)
|
||||||
|
env.fog_density = lerpf(NIGHT_FOG_DENSITY, DAY_FOG_DENSITY, day_factor)
|
||||||
|
|
||||||
|
var sky: Sky = env.sky
|
||||||
|
if sky != null and sky.sky_material is ProceduralSkyMaterial:
|
||||||
|
var mat: ProceduralSkyMaterial = sky.sky_material
|
||||||
|
mat.sky_top_color = _lerp_color(NIGHT_SKY_TOP, DAY_SKY_TOP, day_factor)
|
||||||
|
mat.sky_horizon_color = _lerp_color(NIGHT_SKY_HORIZON, DAY_SKY_HORIZON, day_factor)
|
||||||
|
mat.ground_bottom_color = _lerp_color(NIGHT_GROUND_BOTTOM, DAY_GROUND_BOTTOM, day_factor)
|
||||||
|
mat.ground_horizon_color = _lerp_color(NIGHT_GROUND_HORIZON, DAY_GROUND_HORIZON, day_factor)
|
||||||
|
|
||||||
|
|
||||||
|
func _day_factor(cycle: float) -> float:
|
||||||
|
if cycle < 0.15:
|
||||||
|
return 0.0
|
||||||
|
if cycle < 0.3:
|
||||||
|
return smoothstep(0.15, 0.3, cycle)
|
||||||
|
if cycle < 0.7:
|
||||||
|
return 1.0
|
||||||
|
if cycle < 0.85:
|
||||||
|
return 1.0 - smoothstep(0.7, 0.85, cycle)
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
|
||||||
|
func _sunrise_sunset_weight(cycle: float) -> float:
|
||||||
|
if cycle < 0.15:
|
||||||
|
return smoothstep(0.05, 0.15, cycle) * (1.0 - smoothstep(0.1, 0.15, cycle))
|
||||||
|
if cycle > 0.85:
|
||||||
|
return smoothstep(0.85, 0.95, cycle) * (1.0 - smoothstep(0.9, 0.95, cycle))
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
|
||||||
|
func _lerp_color(from: Color, to: Color, weight: float) -> Color:
|
||||||
|
return from.lerp(to, clampf(weight, 0.0, 1.0))
|
||||||
Reference in New Issue
Block a user