0.0/-90.0/0 means x = 0, y = -90, z = 0. Changing the y axis does not raise or lower the sun, it rotates it around the horizon.
func is_daytime(deg_x) -> bool:
return deg_x > 90.0 and deg_x < 270.0
It seems that because of this, you assume noon is at 180 degrees, but noon is actually at 270 degrees on the x axis (or -90). You can see in the editor than when rotation.x is at 0, the sun is actually on the horizon, pointing sideways, and points down when x is -90 or 270
This means the sunrise is at 180, and sunset is at 360, but in _sun_intensity you start ramping up light at 90 and it goes dark at 270.
Do this instead:
func is_daytime(deg_x:float) -> bool:
return deg_x > 180.0 and deg_x < 360.0
And change the offset in _sun_intensity to 180 instead of 90
func _sun_intensity(deg_x:float) -> float:
var normalized = (deg_x - 180.0) / 180.0
return sin(normalized * PI)
However, I recommend another approach entirely, since angles can be difficult to keep track of, and there is no point in reading back the rotation from the sun after setting it, since you already keep track of time inside time_of_day.
time_of_day should be the only source of truth. It should be what dictates the rotation of the sun, and it should also dictate the intensity of the light, instead of indirectly delegating that job to the rotation.
time_of_day and day_duration should hold values in seconds. Since you want your night time to last for 180 degrees of rotation, the equivalent in seconds would be half of day_duration, or day_duration * 0.5.
Do time_of_day += delta to keep track of seconds instead of dividing by day_duration.
Divide here instead sun_light.rotation_degrees.x = time_of_day * 360.0 / day_duration
Use seconds in your _sun_intensity() function too.
A bit of a nitpick but no need for a separate is_nighttime function, simply call “if not is_daytime()”, or do
if is_daytime():
else:
Here’s the full script, I took the liberty of renaming variables and functions for readability, change them back if you feel like it was unnecessary.
Also since you export a WorldEnvironment, I assume you want to change the environment based on the time of day, so I commented some pseudo-code that would fit the new structure
extends Node
@export var sun_light:DirectionalLight3D
@export var world_environment:WorldEnvironment
# Night starts at 0.0
# Day starts at day_duration * 0.5
# Noon starts at day_duration * 0.75
@export var day_duration :float = 10.0
var time :float = day_duration * 0.75
var half_day :float = day_duration * 0.5
func _ready() -> void:
sun_light.rotation_degrees.x = time * 360.0 / day_duration
func _process(delta: float) -> void:
time += delta
if time >= day_duration:
time -= day_duration
sun_light.rotation_degrees.x = time * 360.0 / day_duration
_update_environment()
func _update_environment() -> void:
# If you want the sun to turn black at night instead of emitting no light (light_energy -1.0 instead of 0.0),
# VVV then uncomment this line here outside of the if statement VVV
## sun_light.light_energy = get_sun_intensity()
# And remove the other lines setting sunlight.light_energy below
if is_daytime():
sun_light.light_energy = get_sun_intensity()
# Set world_environment for day? e.g.: _set_world_environment(is_daytime())
else:
sun_light.light_energy = 0.0
# Set world_environment for night? e.g.: _set_world_environment(is_daytime())
# func _set_world_environment(day :bool) -> void:
# if day:
# Set day environment
# elif not day:
# Set night environment
func is_daytime() -> bool:
return true if time > day_duration / 2 else false
func get_sun_intensity() -> float:
# Returns a value from 1.0 to -1.0 depending on time of day
var day_progress: float = (time - half_day) / half_day
return sin(day_progress * PI)