Added the leveling up apply to agility

This commit is contained in:
Nathan Chapman 2025-05-18 12:36:32 -06:00
parent 108ac002ef
commit 76068312a2
219 changed files with 14279 additions and 45 deletions

26
addons/sky_3d/LICENSE.txt Normal file
View File

@ -0,0 +1,26 @@
MIT License
Copyright (c) 2023-2025 Cory Petkovsek and Contributors
Copyright (c) 2021 J. Cuéllar
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
----
Third party assets have their own licenses found under assets/thirdparty.

3
addons/sky_3d/README.md Normal file
View File

@ -0,0 +1,3 @@
# Sky3D
See the README in the code repository at https://github.com/TokisanGames/Sky3D.

View File

@ -0,0 +1,8 @@
## Attribution for Third Party Assets
`Milkyway.jpg` "[The Milky Way panorama](https://www.eso.org/public/images/eso0932a/)" by ESO/S. Brunier, licensed under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/
).
[Read more](/addons/sky_3d/assets/thirdparty/textures/milkyway/LICENSE.md)
`MoonMap.png` Copyright (c) 2019 GPoSM, MIT License
[Read more](/addons/sky_3d/assets/thirdparty/textures/moon/LICENSE.md)

View File

@ -0,0 +1,33 @@
[gd_scene load_steps=5 format=3 uid="uid://hyy7u72h77"]
[ext_resource type="Shader" path="res://addons/sky_3d/shaders/SimpleMoon.gdshader" id="1_h4nhh"]
[ext_resource type="Texture2D" uid="uid://2r8ylu6rg5dp" path="res://addons/sky_3d/assets/thirdparty/textures/moon/MoonMap.png" id="2_fnh72"]
[sub_resource type="ShaderMaterial" id="ShaderMaterial_5qbl8"]
render_priority = 0
shader = ExtResource("1_h4nhh")
shader_parameter/_sun_direction = Vector3(-0.976421, -0.0982674, -0.192214)
shader_parameter/_texture = ExtResource("2_fnh72")
[sub_resource type="SphereMesh" id="2"]
[node name="MoonRender" type="SubViewport"]
own_world_3d = true
transparent_bg = true
msaa_3d = 3
render_target_update_mode = 4
[node name="MoonTransform" type="Node3D" parent="."]
[node name="Camera3D" type="Camera3D" parent="MoonTransform"]
transform = Transform3D(-1, 0, 3.25841e-07, 0, 1, 0, -3.25841e-07, 0, -1, 0, 0, 0)
projection = 1
size = 2.59
[node name="Mesh" type="MeshInstance3D" parent="MoonTransform/Camera3D"]
transform = Transform3D(8.74228e-08, -2, -7.78829e-07, -2, -8.74228e-08, 6.77626e-20, -3.40438e-14, 7.78829e-07, -2, -4.00785e-07, 0, -1.23)
material_override = SubResource("ShaderMaterial_5qbl8")
cast_shadow = 0
mesh = SubResource("2")

View File

@ -0,0 +1,7 @@
[gd_resource type="NoiseTexture2D" load_steps=2 format=3 uid="uid://cfqk60lpl5ljv"]
[sub_resource type="FastNoiseLite" id="1"]
[resource]
seamless = true
noise = SubResource("1")

View File

@ -0,0 +1,5 @@
[gd_resource type="Curve" format=3 uid="uid://70482fhm3qg7"]
[resource]
_data = [Vector2(0, 0), 0.0, 0.0, 0, 0, Vector2(0.617886, 0), 0.0, 0.0467088, 1, 0, Vector2(0.699187, 1), 0.0, 0.0, 0, 0, Vector2(1, 1), 0.0, 0.0, 0, 0]
point_count = 4

BIN
addons/sky_3d/assets/textures/SkyIcon.png (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bwooawylkf7f2"
path="res://.godot/imported/SkyIcon.png-7b3cbfa68354965cdbfdba8b95dacf67.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/sky_3d/assets/textures/SkyIcon.png"
dest_files=["res://.godot/imported/SkyIcon.png-7b3cbfa68354965cdbfdba8b95dacf67.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

View File

@ -0,0 +1,35 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://djpfuyxkryegn"
path.s3tc="res://.godot/imported/noise.jpg-b47d5d36d9abfdaec2a09c140a78ba24.s3tc.ctex"
metadata={
"imported_formats": ["s3tc_bptc"],
"vram_texture": true
}
[deps]
source_file="res://addons/sky_3d/assets/textures/noise.jpg"
dest_files=["res://.godot/imported/noise.jpg-b47d5d36d9abfdaec2a09c140a78ba24.s3tc.ctex"]
[params]
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

BIN
addons/sky_3d/assets/textures/noise2.png (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -0,0 +1,35 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bd7u40ws8s57f"
path.s3tc="res://.godot/imported/noise2.png-37a5cbd5451b4b9c2c18ab32099e6965.s3tc.ctex"
metadata={
"imported_formats": ["s3tc_bptc"],
"vram_texture": true
}
[deps]
source_file="res://addons/sky_3d/assets/textures/noise2.png"
dest_files=["res://.godot/imported/noise2.png-37a5cbd5451b4b9c2c18ab32099e6965.s3tc.ctex"]
[params]
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

BIN
addons/sky_3d/assets/textures/noiseClouds.png (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -0,0 +1,35 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cecwdqjol0ckd"
path.s3tc="res://.godot/imported/noiseClouds.png-07511094ef8b72a49cc860b35c60d0fd.s3tc.ctex"
metadata={
"imported_formats": ["s3tc_bptc"],
"vram_texture": true
}
[deps]
source_file="res://addons/sky_3d/assets/textures/noiseClouds.png"
dest_files=["res://.godot/imported/noiseClouds.png-07511094ef8b72a49cc860b35c60d0fd.s3tc.ctex"]
[params]
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

View File

@ -0,0 +1,40 @@
# Attribution
`Milkyway.jpg` "[The Milky Way panorama](https://www.eso.org/public/images/eso0932a/)" by ESO/S. Brunier, licensed under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/
).
`StarField.jpg` is the same image modified to hide all but the brightest stars.
Your game credits should include attribution similar to the above with a link to the license where reasonable.
e.g. `The Milky Way panorama by ESO/S. Brunier, licensed under CC BY 4.0 and used in original and modified forms.`
Higher resolutions and more information are available at: https://www.eso.org/public/images/eso0932a/
Licensing questions answered here: https://www.eso.org/public/copyright/
## License
[Creative Commons Attribution 4.0 International License](https://creativecommons.org/licenses/by/4.0/)
## Relevant FAQs
[From ESO](https://www.eso.org/public/copyright/)
```
Q: I am making an electronic game. Where should I place the credit?
A: As long as the credit is clearly visible to all users and reproduced in full, for instance in a splashscreen, all is fine.
```
[From CC](https://wiki.creativecommons.org/wiki/Recommended_practices_for_attribution#This_is_a_great_attribution)
```
This is a great attribution
"Creative Commons 10th Birthday Celebration San Francisco"(source link) by Timothy Vollmer is licensed under CC BY 4.0 (license link)
Lets go through TASL:
Title? "Creative Commons 10th Birthday Celebration San Francisco"
Author? "Timothy Vollmer" - linked to his profile page
Source? "Creative Commons 10th Birthday Celebration San Francisco" - linked to original Flickr page
License? "CC BY 4.0" - linked to license deed
Most importantly, this attribution reasonably includes all the relevant information provided by the author.
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 MiB

View File

@ -0,0 +1,35 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://c1vwcdcdvb74a"
path.s3tc="res://.godot/imported/Milkyway.jpg-a06044e407cf6953ab6e46a2f0f17f3a.s3tc.ctex"
metadata={
"imported_formats": ["s3tc_bptc"],
"vram_texture": true
}
[deps]
source_file="res://addons/sky_3d/assets/thirdparty/textures/milkyway/Milkyway.jpg"
dest_files=["res://.godot/imported/Milkyway.jpg-a06044e407cf6953ab6e46a2f0f17f3a.s3tc.ctex"]
[params]
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

View File

@ -0,0 +1,35 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bm7dot7t7u1q4"
path.s3tc="res://.godot/imported/StarField.jpg-9d224e20fcbe8fdc7ff5028dae269839.s3tc.ctex"
metadata={
"imported_formats": ["s3tc_bptc"],
"vram_texture": true
}
[deps]
source_file="res://addons/sky_3d/assets/thirdparty/textures/milkyway/StarField.jpg"
dest_files=["res://.godot/imported/StarField.jpg-9d224e20fcbe8fdc7ff5028dae269839.s3tc.ctex"]
[params]
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

View File

@ -0,0 +1,23 @@
MIT License
Copyright (c) 2019 GPoSM
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Source: https://www.highend3d.com/downloads/3d-textures/c/16k-earth-w-4k-moon-free#dialog_license

BIN
addons/sky_3d/assets/thirdparty/textures/moon/MoonMap.png (Stored with Git LFS) vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,35 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://2r8ylu6rg5dp"
path.s3tc="res://.godot/imported/MoonMap.png-81d542c3fafff4e5b235a177af6f3221.s3tc.ctex"
metadata={
"imported_formats": ["s3tc_bptc"],
"vram_texture": true
}
[deps]
source_file="res://addons/sky_3d/assets/thirdparty/textures/moon/MoonMap.png"
dest_files=["res://.godot/imported/MoonMap.png-81d542c3fafff4e5b235a177af6f3221.s3tc.ctex"]
[params]
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

7
addons/sky_3d/plugin.cfg Normal file
View File

@ -0,0 +1,7 @@
[plugin]
name="Sky3D"
description="Atmospheric Day/Night Cycle"
author="J. Cuéllar, Cory Petkovsek, Contributors"
version="2.0"
script="src/Plugin.gd"

View File

@ -0,0 +1,212 @@
// Copyright (c) 2023-2025 Cory Petkovsek and Contributors
// Copyright (c) 2021 J. Cuellar
shader_type spatial;
render_mode blend_mix, cull_disabled, unshaded;
uniform vec2 _color_correction_params;
uniform float _fog_density = .0001;
uniform float _fog_rayleigh_depth = .115;
uniform float _fog_mie_depth = 0.;
uniform float _fog_falloff = 3.;
uniform float _fog_start = 0.;
uniform float _fog_end = 1000.;
uniform vec3 _sun_direction = vec3(.25, -.25, .25);
uniform vec3 _moon_direction = vec3(.45, -.25, .45);
uniform float _atm_darkness = .5;
uniform float _atm_sun_intensity = 30.;
uniform vec4 _atm_day_tint: source_color = vec4(.78, .85, .98, 1.);
uniform vec4 _atm_horizon_light_tint: source_color = vec4(.98, .73, .49, 1.);
uniform vec4 _atm_night_tint: source_color = vec4(.16, .2, .25, 1.);
uniform vec3 _atm_level_params = vec3(1., 0., 0.);
uniform float _atm_thickness = .7;
uniform vec3 _atm_beta_ray;
uniform vec3 _atm_beta_mie;
uniform vec3 _atm_sun_partial_mie_phase;
uniform vec4 _atm_sun_mie_tint: source_color = vec4(1.);
uniform float _atm_sun_mie_intensity = 1.;
uniform vec3 _atm_moon_partial_mie_phase;
uniform vec4 _atm_moon_mie_tint: source_color = vec4(.13, .18, .29, 1.);
uniform float _atm_moon_mie_intensity = .7;
uniform sampler2D DEPTH_TEXTURE : hint_depth_texture, filter_linear_mipmap;
uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, filter_linear_mipmap;
// Inc
//------------------------------------------------------------------------------
const float kPI = 3.1415927f;
const float kINV_PI = 0.3183098f;
const float kHALF_PI = 1.5707963f;
const float kINV_HALF_PI = 0.6366198f;
const float kQRT_PI = 0.7853982f;
const float kINV_QRT_PI = 1.2732395f;
const float kPI4 = 12.5663706f;
const float kINV_PI4 = 0.0795775f;
const float k3PI16 = 0.1193662f;
const float kTAU = 6.2831853f;
const float kINV_TAU = 0.1591549f;
const float kE = 2.7182818f;
float saturate(float value){
return clamp(value, 0.0, 1.0);
}
vec3 saturateRGB(vec3 value){
return clamp(value.rgb, 0.0, 1.0);
}
// pow3
vec3 contrastLevel(vec3 vec, float level){
return mix(vec, vec * vec * vec, level);
}
vec3 tonemapPhoto(vec3 color, float exposure, float level){
color.rgb *= exposure;
return mix(color.rgb, 1.0 - exp(-color.rgb), level);
}
vec2 equirectUV(vec3 norm){
vec2 ret;
ret.x = (atan(norm.x, norm.z) + kPI) * kINV_TAU;
ret.y = acos(norm.y) * kINV_PI;
return ret;
}
// Atmosphere Inc
//------------------------------------------------------------------------------
const float RAYLEIGH_ZENITH_LENGTH = 8.4e3;
const float MIE_ZENITH_LENGTH = 1.25e3;
float rayleighPhase(float mu){
return k3PI16 * (1.0 + mu * mu);
}
float miePhase(float mu, vec3 partial){
return kPI4 * (partial.x) * (pow(partial.y - partial.z * mu, -1.5));
}
// Simplifield for more performance
void simpleOpticalDepth(float y, out float sr, out float sm){
y = max(0.03, y + 0.03) + _atm_level_params.y;
y = 1.0 / (y * _atm_level_params.x);
sr = y * RAYLEIGH_ZENITH_LENGTH;
sm = y * MIE_ZENITH_LENGTH;
}
// Paper based
void opticalDepth(float y, out float sr, out float sm){
y = max(0.0, y);
y = saturate(y * _atm_level_params.x);
float zenith = acos(y);
zenith = cos(zenith) + 0.15 * pow(93.885 - ((zenith * 180.0) / kPI), -1.253);
zenith = 1.0 / (zenith + _atm_level_params.y);
sr = zenith * RAYLEIGH_ZENITH_LENGTH;
sm = zenith * MIE_ZENITH_LENGTH;
}
vec3 atmosphericScattering(float sr, float sm, vec2 mu, vec3 mult, float depth){
vec3 betaMie = _atm_beta_mie;
vec3 betaRay = _atm_beta_ray * _atm_thickness;
vec3 extcFactor = saturateRGB(exp(-(betaRay * sr + betaMie * sm)));
float extcFF = mix(saturate(_atm_thickness * 0.5), 1.0, mult.x);
vec3 finalExtcFactor = mix(1.0 - extcFactor, (1.0 - extcFactor) * extcFactor, extcFF);
float rayleighPhase = rayleighPhase(mu.x);
vec3 BRT = betaRay * rayleighPhase * saturate(depth * _fog_rayleigh_depth);
vec3 BMT = betaMie * miePhase(mu.x, _atm_sun_partial_mie_phase);
BMT *= _atm_sun_mie_intensity * _atm_sun_mie_tint.rgb * saturate(depth * _fog_mie_depth);
vec3 BRMT = (BRT + BMT) / (betaRay + betaMie);
vec3 scatter = _atm_sun_intensity * (BRMT * finalExtcFactor) * _atm_day_tint.rgb * mult.y;
scatter = mix(scatter, scatter * (1.0 - extcFactor), _atm_darkness);
vec3 lcol = mix(_atm_day_tint.rgb, _atm_horizon_light_tint.rgb, mult.x);
vec3 nscatter = (1.0 - extcFactor) * _atm_night_tint.rgb * saturate(depth * _fog_rayleigh_depth);
nscatter += miePhase(mu.y, _atm_moon_partial_mie_phase) *
_atm_moon_mie_tint.rgb * _atm_moon_mie_intensity * 0.005 * saturate(depth * _fog_mie_depth);
return (scatter * lcol) + nscatter;
}
// Fog
//------------------------------------------------------------------------------
float fogExp(float depth, float density){
return 1.0 - saturate(exp2(-depth * density));
}
float fogFalloff(float y, float zeroLevel, float falloff){
return saturate(exp(-(y + zeroLevel) * falloff));
}
float fogDistance(float depth){
float d = depth;
d = (_fog_end - d) / (_fog_end - _fog_start);
return saturate(1.0 - d);
}
void computeCoords(vec2 uv, float depth, mat4 camMat, mat4 invProjMat,
out vec3 viewDir, out vec3 worldPos){
vec3 ndc = vec3(uv * 2.0 - 1.0, depth);
// ViewDir
vec4 view = invProjMat * vec4(ndc, 1.0);
viewDir = view.xyz / view.w;
// worldPos
view = camMat * view;
view.xyz /= view.w;
view.xyz -= (camMat * vec4(0.0, 0.0, 0.0, 1.0)).xyz;
worldPos = view.xyz;
}
// Varyings
//------------------------------------------------------------------------------
varying mat4 camera_matrix;
varying vec4 angle_mult;
varying flat int angle;
void vertex(){
POSITION = vec4(VERTEX.xy, 1.0, 1.0);
angle = 0; //ignore; without this the line below errors in 4.3-stable
angle_mult.x = saturate(1.0 - _sun_direction.y);
angle_mult.y = saturate(_sun_direction.y + 0.45);
angle_mult.z = saturate(-_sun_direction.y + 0.30);
angle_mult.w = saturate(-_sun_direction.y + 0.60);
camera_matrix = INV_VIEW_MATRIX;
}
void fragment(){
float depthRaw = texture(DEPTH_TEXTURE, SCREEN_UV).r;
vec3 view; vec3 worldPos;
computeCoords(SCREEN_UV, depthRaw, camera_matrix, INV_PROJECTION_MATRIX, view, worldPos);
worldPos = normalize(worldPos);
float linearDepth = -view.z;
float fogFactor = fogExp(linearDepth, _fog_density);
fogFactor *= fogFalloff(worldPos.y, 0.0, _fog_falloff);
fogFactor *= fogDistance(linearDepth);
vec2 mu = vec2(dot(_sun_direction, worldPos), dot(_moon_direction, worldPos));
float sr; float sm; simpleOpticalDepth(worldPos.y + _atm_level_params.z, sr, sm);
vec3 scatter = atmosphericScattering(sr, sm, mu.xy, angle_mult.xyz, linearDepth);
vec3 tint = scatter;
vec4 fogColor = vec4(tint.rgb, fogFactor);
fogColor = vec4((fogColor.rgb), saturate(fogColor.a));
fogColor.rgb = tonemapPhoto(fogColor.rgb, _color_correction_params.y, _color_correction_params.x);
ALBEDO = fogColor.rgb;
ALPHA = fogColor.a;
//ALPHA = (depthRaw) < 0.999999999999 ? fogColor.a: 0.0; // Exclude sky.
}

View File

@ -0,0 +1 @@
uid://bn8sv775a1kvs

View File

@ -0,0 +1,198 @@
// Copyright (c) 2023-2025 Cory Petkovsek and Contributors
// Copyright (c) 2021 J. Cuellar
// This shader is based on DanilS clouds shader with MIT License
// See https://github.com/danilw/godot-utils-and-other/tree/master/Dynamic%20sky%20and%20reflection
shader_type spatial;
render_mode unshaded, blend_mix, depth_draw_never, cull_front, skip_vertex_transform;
uniform vec3 _sun_direction;
uniform vec3 _moon_direction;
uniform float _clouds_coverage;
uniform float _clouds_thickness;
uniform float _clouds_absorption;
uniform float _clouds_noise_freq;
uniform float _clouds_sky_tint_fade;
uniform float _clouds_intensity;
uniform float _clouds_size;
uniform float _clouds_speed;
uniform vec3 _clouds_direction;
uniform sampler2D _clouds_texture;
uniform vec4 _clouds_day_color: source_color;
uniform vec4 _clouds_horizon_light_color: source_color;
uniform vec4 _clouds_night_color: source_color;
const int kCLOUDS_STEP = 10;
uniform vec3 _clouds_partial_mie_phase;
uniform float _clouds_mie_intensity;
uniform vec4 _atm_sun_mie_tint;
uniform vec4 _atm_moon_mie_tint: source_color;
const float kPI = 3.1415927f;
const float kINV_PI = 0.3183098f;
const float kHALF_PI = 1.5707963f;
const float kINV_HALF_PI = 0.6366198f;
const float kQRT_PI = 0.7853982f;
const float kINV_QRT_PI = 1.2732395f;
const float kPI4 = 12.5663706f;
const float kINV_PI4 = 0.0795775f;
const float k3PI16 = 0.1193662f;
const float kTAU = 6.2831853f;
const float kINV_TAU = 0.1591549f;
const float kE = 2.7182818f;
float saturate(float value){
return clamp(value, 0.0, 1.0);
}
vec3 saturateRGB(vec3 value){
return clamp(value.rgb, 0.0, 1.0);
}
float pow3(float real){
return real * real * real;
}
float noiseClouds(vec3 p){
vec3 pos = vec3(p * 0.01);
pos.z *= 256.0;
vec2 offset = vec2(0.317, 0.123);
vec4 uv= vec4(0.0);
uv.xy = pos.xy + offset * floor(pos.z);
uv.zw = uv.xy + offset;
float x1 = textureLod(_clouds_texture, uv.xy, 0.0).r;
float x2 = textureLod(_clouds_texture, uv.zw, 0.0).r;
return mix(x1, x2, fract(pos.z));
}
float cloudsFBM(vec3 p, float l){
float ret;
ret = 0.51749673 * noiseClouds(p);
p *= l;
ret += 0.25584929 * noiseClouds(p);
p *= l;
ret += 0.12527603 * noiseClouds(p);
p *= l;
ret += 0.06255931 * noiseClouds(p);
return ret;
}
float noiseCloudsFBM(vec3 p, float freq){
return cloudsFBM(p, freq);
}
float remap(float value, float fromMin, float fromMax, float toMin, float toMax){
return toMin + (value - fromMin) * (toMax - toMin) / (fromMax - fromMin);
}
float cloudsDensity(vec3 p, vec3 offset, float t){
vec3 pos = p * 0.0212242 - offset;
float dens = noiseCloudsFBM(pos, _clouds_noise_freq);
dens += dens;
float cov = 1.0-_clouds_coverage;
cov = smoothstep(0.00, (cov * 3.5) + t, dens);
dens *= cov;
dens = remap(dens, 1.0-cov, 1.0, 0.0, 1.0);
return saturate(dens);
}
bool IntersectSphere(float r, vec3 origin, vec3 dir, out float t, out vec3 nrm)
{
origin += vec3(0.0, 450.0, 0.0);
float a = dot(dir, dir);
float b = 2.0 * dot(origin, dir);
float c = dot(origin, origin) - r * r;
float d = b * b - 4.0 * a * c;
if(d < 0.0) return false;
d = sqrt(d);
a *= 2.0;
float t1 = 0.5 * (-b + d);
float t2 = 0.5 * (-b - d);
if(t1<0.0) t1 = t2;
if(t2 < 0.0) t2 = t1;
t1 = min(t1, t2);
if(t1 < 0.0) return false;
nrm = origin + t1 * dir;
t = t1;
return true;
}
float miePhase(float mu, vec3 partial){
return kPI4 * (partial.x) * (pow(partial.y - partial.z * mu, -1.5));
}
vec4 renderClouds2(vec3 ro, vec3 rd, float tm, float am){
vec4 ret = vec4(0, 0, 0, 0);
vec3 wind = _clouds_direction * (tm * _clouds_speed);
float a = 0.0;
// n and tt doesnt need to be initialized since it would be set by IntersectSphere
vec3 n; float tt;
if(IntersectSphere(500, ro, rd, tt, n))
{
float marchStep = float(kCLOUDS_STEP) * _clouds_thickness;
vec3 dirStep = rd / rd.y * marchStep;
vec3 pos = n * _clouds_size;
vec2 mu = vec2(dot(_sun_direction, rd), dot(_moon_direction, rd));
vec3 mph = ((miePhase(mu.x, _clouds_partial_mie_phase) * _atm_sun_mie_tint.rgb) +
miePhase(mu.y, _clouds_partial_mie_phase) * am);
vec4 t = vec4(1.0);
t.rgb += (mph.rgb * _clouds_mie_intensity);
for(int i = 0; i < kCLOUDS_STEP; i++)
{
float h = float(i) * 0.1; // / float(kCLOUDS_STEP);
float density = cloudsDensity(pos, wind, h);
float sh = saturate(exp(-_clouds_absorption * density * marchStep));
t *= sh;
ret += (t * (exp(h) * 0.571428571) * density * marchStep);
a += (1.0 - sh) * (1.0 - a);
pos += dirStep;
}
return vec4(ret.rgb * _clouds_intensity, a);
}
return vec4(ret.rgb * _clouds_intensity, a);
}
varying vec4 world_pos;
varying vec4 moon_coords;
varying vec3 deep_space_coords;
varying vec4 angle_mult;
void vertex(){
vec4 vert = vec4(VERTEX, 0.0);
POSITION = PROJECTION_MATRIX * MODELVIEW_MATRIX * vert;
POSITION.z = 0.0000001;
world_pos = (MODEL_MATRIX * vert);
angle_mult.x = saturate(1.0 - _sun_direction.y);
angle_mult.y = saturate(_sun_direction.y + 0.45);
angle_mult.z = saturate(-_sun_direction.y + 0.30);
angle_mult.w = saturate(-_sun_direction.y + 0.60);
}
void fragment(){
vec3 ray = normalize(world_pos).xyz;
float horizonBlend = saturate((ray.y+0.01) * 50.0);
vec4 clouds = renderClouds2(vec3(0.0, 0.0, 0.0), ray, TIME, angle_mult.z);
clouds.a = saturate(clouds.a);
clouds.rgb *= mix(mix(_clouds_day_color.rgb, _clouds_horizon_light_color.rgb, angle_mult.x),
_clouds_night_color.rgb, angle_mult.w);
clouds.a = mix(0.0, clouds.a, horizonBlend);
ALBEDO = clouds.rgb;
ALPHA = pow3(clouds.a);
}

View File

@ -0,0 +1 @@
uid://brbic4veeaixo

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 J. Cuéllar
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,299 @@
// Copyright (c) 2023-2025 Cory Petkovsek and Contributors
// Copyright (c) 2021 J. Cuellar
shader_type spatial;
render_mode unshaded, depth_draw_never, cull_front, skip_vertex_transform;
// Color correction
uniform vec2 _color_correction_params;
uniform vec4 _ground_color: source_color;
uniform float _horizon_level;
// uniforms
uniform vec3 _sun_direction;
uniform vec3 _moon_direction;
uniform float _moon_size;
uniform mat3 _moon_matrix;
uniform mat3 _deep_space_matrix;
// Atmospheric Scattering
uniform float _atm_darkness;
uniform float _atm_sun_intensity;
uniform vec4 _atm_day_tint: source_color;
uniform vec4 _atm_horizon_light_tint: source_color;
uniform vec4 _atm_night_tint: source_color;
uniform vec3 _atm_level_params;
uniform float _atm_thickness;
// Sun mie phase
uniform vec4 _atm_sun_mie_tint: source_color;
uniform float _atm_sun_mie_intensity;
uniform vec4 _atm_moon_mie_tint: source_color;
uniform float _atm_moon_mie_intensity;
uniform vec3 _atm_beta_ray;
uniform vec3 _atm_beta_mie;
uniform vec3 _atm_sun_partial_mie_phase;
uniform vec3 _atm_moon_partial_mie_phase;
// Sun disk
uniform vec4 _sun_disk_color: source_color;
uniform float _sun_disk_intensity;
uniform float _sun_disk_size;
uniform vec4 _moon_color: source_color;
uniform sampler2D _moon_texture: source_color, repeat_disable;
// Background
uniform sampler2D _background_texture: source_color;
uniform vec4 _background_color: source_color;
// Stars Field
uniform vec4 _stars_field_color: source_color;
uniform sampler2D _stars_field_texture: source_color;
uniform float _stars_scintillation;
uniform float _stars_scintillation_speed;
uniform sampler2D _noise_tex: source_color;
// Clouds
uniform float _clouds_coverage;
uniform float _clouds_thickness;
uniform float _clouds_absorption;
uniform float _clouds_sky_tint_fade;
uniform float _clouds_intensity;
uniform float _clouds_size;
uniform vec2 _clouds_uv;
uniform float _clouds_speed;
uniform vec2 _clouds_direction;
uniform vec4 _clouds_day_color: source_color;
uniform vec4 _clouds_horizon_light_color: source_color;
uniform vec4 _clouds_night_color: source_color;
uniform sampler2D _clouds_texture;
// Inc
//------------------------------------------------------------------------------
const float kPI = 3.1415927f;
const float kINV_PI = 0.3183098f;
const float kHALF_PI = 1.5707963f;
const float kINV_HALF_PI = 0.6366198f;
const float kQRT_PI = 0.7853982f;
const float kINV_QRT_PI = 1.2732395f;
const float kPI4 = 12.5663706f;
const float kINV_PI4 = 0.0795775f;
const float k3PI16 = 0.1193662f;
const float kTAU = 6.2831853f;
const float kINV_TAU = 0.1591549f;
const float kE = 2.7182818f;
float saturate(float value){
return clamp(value, 0.0, 1.0);
}
vec3 saturateRGB(vec3 value){
return clamp(value.rgb, 0.0, 1.0);
}
// pow3
vec3 contrastLevel(vec3 vec, float level){
return mix(vec, vec * vec * vec, level);
}
vec3 tonemapPhoto(vec3 color, float exposure, float level){
color.rgb *= exposure;
return mix(color.rgb, 1.0 - exp(-color.rgb), level);
}
vec2 equirectUV(vec3 norm){
vec2 ret;
ret.x = (atan(norm.x, norm.z) + kPI) * kINV_TAU;
ret.y = acos(norm.y) * kINV_PI;
return ret;
}
/*
float random(vec2 uv){
float ret = dot(uv, vec2(12.9898, 78.233));
return fract(43758.5453 * sin(ret));
}
*/
float disk(vec3 norm, vec3 coords, lowp float size){
float dist = length(norm - coords);
return 1.0 - step(size, dist);
}
// Atmosphere Inc
//------------------------------------------------------------------------------
const float RAYLEIGH_ZENITH_LENGTH = 8.4e3;
const float MIE_ZENITH_LENGTH = 1.25e3;
float rayleighPhase(float mu){
return k3PI16 * (1.0 + mu * mu);
}
float miePhase(float mu, vec3 partial){
return kPI4 * (partial.x) * (pow(partial.y - partial.z * mu, -1.5));
}
// Simplifield for more performance
void simpleOpticalDepth(float y, out float sr, out float sm){
y = max(0.03, y + 0.03) + _atm_level_params.y;
y = 1.0 / (y * _atm_level_params.x);
sr = y * RAYLEIGH_ZENITH_LENGTH;
sm = y * MIE_ZENITH_LENGTH;
}
// Paper based
void opticalDepth(float y, out float sr, out float sm){
y = max(0.0, y);
y = saturate(y * _atm_level_params.x);
float zenith = acos(y);
zenith = cos(zenith) + 0.15 * pow(93.885 - ((zenith * 180.0) / kPI), -1.253);
zenith = 1.0 / (zenith + _atm_level_params.y);
sr = zenith * RAYLEIGH_ZENITH_LENGTH;
sm = zenith * MIE_ZENITH_LENGTH;
}
vec3 atmosphericScattering(float sr, float sm, vec2 mu, vec3 mult){
vec3 betaMie = _atm_beta_mie;
vec3 betaRay = _atm_beta_ray * _atm_thickness;
vec3 extcFactor = saturateRGB(exp(-(betaRay * sr + betaMie * sm)));
float extcFF = mix(saturate(_atm_thickness * 0.5), 1.0, mult.x);
vec3 finalExtcFactor = mix(1.0 - extcFactor, (1.0 - extcFactor) * extcFactor, extcFF);
float rayleighPhase = rayleighPhase(mu.x);
vec3 BRT = betaRay * rayleighPhase;
vec3 BMT = betaMie * miePhase(mu.x, _atm_sun_partial_mie_phase);
BMT *= _atm_sun_mie_intensity * _atm_sun_mie_tint.rgb;
vec3 BRMT = (BRT + BMT) / (betaRay + betaMie);
vec3 scatter = _atm_sun_intensity * (BRMT * finalExtcFactor) * _atm_day_tint.rgb * mult.y;
scatter = mix(scatter, scatter * (1.0 - extcFactor), _atm_darkness);
vec3 lcol = mix(_atm_day_tint.rgb, _atm_horizon_light_tint.rgb, mult.x);
vec3 nscatter = (1.0 - extcFactor) * _atm_night_tint.rgb;
nscatter += miePhase(mu.y, _atm_moon_partial_mie_phase) *
_atm_moon_mie_tint.rgb * _atm_moon_mie_intensity * 0.005;
return (scatter * lcol) + nscatter;
}
// Clouds
//------------------------------------------------------------------------------
float noiseClouds(vec2 coords, vec2 offset){
float speed = TIME * _clouds_speed * .5; // .5 matches cumulus clouds
vec2 wind = offset * speed;
vec2 wind2 = (offset + offset) * speed;
float a = textureLod(_clouds_texture, coords.xy * _clouds_uv - wind, 0.0).r;
float b = textureLod(_clouds_texture, coords.xy * _clouds_uv - wind2, 0.0).r;
return ((a + b) * 0.5);
}
float cloudsDensity(vec2 p, vec2 offset){
float d = noiseClouds(p, offset);
float c = 1.0 - _clouds_coverage;
d = d - c;
return saturate(d);
}
vec4 renderClouds(vec3 pos){
pos.xy = pos.xz / pos.y;
pos *= _clouds_size;
float density = cloudsDensity(pos.xy, _clouds_direction);
float sh = saturate(exp(-_clouds_absorption * density));
float a = saturate(density * _clouds_thickness);
return vec4(vec3(density*sh) * _clouds_intensity, a);
}
// Varyings
//------------------------------------------------------------------------------
varying vec4 world_pos;
varying vec4 moon_coords;
varying vec3 deep_space_coords;
varying vec4 angle_mult;
varying vec3 scatter;
void vertex(){
vec4 vert = vec4(VERTEX, 0.0);
POSITION = PROJECTION_MATRIX * MODELVIEW_MATRIX * vert;
POSITION.z = 0.00000001;
world_pos = MODEL_MATRIX * vert;
moon_coords.xyz = (_moon_matrix * VERTEX) / _moon_size + 0.5;
moon_coords.w = dot(world_pos.xyz, _moon_direction.xyz);
deep_space_coords.xyz = (_deep_space_matrix * VERTEX).xyz;
angle_mult.x = saturate(1.0 - _sun_direction.y);
angle_mult.y = saturate(_sun_direction.y + 0.45);
angle_mult.z = saturate(-_sun_direction.y + 0.30);
angle_mult.w = saturate(-_sun_direction.y + 0.60);
// Atmosphere
vec3 worldPos = normalize(world_pos).xyz;
vec2 mu = vec2(dot(_sun_direction, worldPos), dot(_moon_direction, worldPos));
float sr, sm;
simpleOpticalDepth(worldPos.y + _atm_level_params.z + _horizon_level, sr, sm);
scatter = atmosphericScattering(sr, sm, mu.xy, angle_mult.xyz);
}
void fragment(){
vec3 col = vec3(0.0);
vec3 worldPos = normalize(world_pos).xyz;
vec3 cloudsPos = worldPos;
worldPos.y += _horizon_level;
float horizonBlend = saturate((worldPos.y - 0.03) * 3.0);
col.rgb += scatter.rgb;
// Near Space
vec3 nearSpace = vec3(0.0);
vec3 sunDisk = disk(worldPos, _sun_direction, _sun_disk_size) *
_sun_disk_color.rgb * scatter.rgb;
sunDisk *= _sun_disk_intensity;
// Moon
vec4 moon = texture(_moon_texture, vec2(-moon_coords.x+1.0, moon_coords.y));
moon.rgb = contrastLevel(moon.rgb * _moon_color.rgb, _moon_color.a);
moon *= saturate(moon_coords.w);
float moonMask = saturate(1.0 - moon.a);
nearSpace = moon.rgb + (sunDisk.rgb * moonMask);
col.rgb += nearSpace;
vec3 deepSpace = vec3(0.0);
vec2 deepSpaceUV = equirectUV(normalize(deep_space_coords));
// Background
vec3 deepSpaceBackground = textureLod(_background_texture, deepSpaceUV, 0.0).rgb;
deepSpaceBackground *= _background_color.rgb;
deepSpaceBackground = contrastLevel(deepSpaceBackground, _background_color.a);
deepSpace.rgb += deepSpaceBackground.rgb * moonMask;
// Stars Field
float starsScintillation = textureLod(_noise_tex, UV + (TIME * _stars_scintillation_speed), 0.0).r;
starsScintillation = mix(1.0, starsScintillation * 1.5, _stars_scintillation);
vec3 starsField = textureLod(_stars_field_texture, deepSpaceUV, 0.0).rgb * _stars_field_color.rgb;
starsField = saturateRGB(mix(starsField.rgb, starsField.rgb * starsScintillation, _stars_scintillation));
//deepSpace.rgb -= saturate(starsField.r*10.0);
deepSpace.rgb += starsField.rgb * moonMask;
deepSpace.rgb *= angle_mult.z;
col.rgb += deepSpace.rgb * horizonBlend;
// Clouds
vec4 clouds = renderClouds(cloudsPos);
clouds.a = saturate(clouds.a);
clouds.rgb *= mix(mix(_clouds_day_color.rgb, _clouds_horizon_light_color.rgb, angle_mult.x),
_clouds_night_color.rgb, angle_mult.w);
clouds.a = mix(0.0, clouds.a, horizonBlend);
col.rgb = mix(col.rgb, clouds.rgb + mix(vec3(0.0), scatter, _clouds_sky_tint_fade), clouds.a);
col.rgb = mix(col.rgb, _ground_color.rgb * scatter, saturate((-worldPos.y - _atm_level_params.z)*100.0));
col.rgb = tonemapPhoto(col.rgb, _color_correction_params.y, _color_correction_params.x);
ALBEDO = col.rgb;
}

View File

@ -0,0 +1 @@
uid://esppe8gjxn2o

View File

@ -0,0 +1,22 @@
// Copyright (c) 2023-2025 Cory Petkovsek and Contributors
// Copyright (c) 2021 J. Cuellar
shader_type spatial;
render_mode unshaded;
uniform sampler2D _texture;
uniform vec3 _sun_direction;
float saturate(float v){
return clamp(v, 0.0, 1.0);
}
varying vec3 normal;
void vertex(){
normal = (MODEL_MATRIX * vec4(VERTEX, 0.0)).xyz;
}
void fragment(){
float l = saturate(max(0.0, dot(_sun_direction, normal)) * 2.0);
ALBEDO = texture(_texture, UV).rgb * l;
}

View File

@ -0,0 +1 @@
uid://b32kr6wc23uit

View File

@ -0,0 +1,299 @@
// Copyright (c) 2023-2025 Cory Petkovsek and Contributors
// Copyright (c) 2021 J. Cuellar
shader_type spatial;
render_mode unshaded, depth_draw_never, cull_front, skip_vertex_transform;
// Color correction
uniform vec2 _color_correction_params;
uniform vec4 _ground_color: source_color;
uniform float _horizon_level;
// uniforms
uniform vec3 _sun_direction;
uniform vec3 _moon_direction;
uniform float _moon_size;
uniform mat3 _moon_matrix;
uniform mat3 _deep_space_matrix;
// Atmospheric Scattering
uniform float _atm_darkness;
uniform float _atm_sun_intensity;
uniform vec4 _atm_day_tint: source_color;
uniform vec4 _atm_horizon_light_tint: source_color;
uniform vec4 _atm_night_tint: source_color;
uniform vec3 _atm_level_params;
uniform float _atm_thickness;
// Sun mie phase
uniform vec4 _atm_sun_mie_tint: source_color;
uniform float _atm_sun_mie_intensity;
uniform vec4 _atm_moon_mie_tint: source_color;
uniform float _atm_moon_mie_intensity;
uniform vec3 _atm_beta_ray;
uniform vec3 _atm_beta_mie;
uniform vec3 _atm_sun_partial_mie_phase;
uniform vec3 _atm_moon_partial_mie_phase;
// Sun disk
uniform vec4 _sun_disk_color: source_color;
uniform float _sun_disk_intensity;
uniform float _sun_disk_size;
uniform vec4 _moon_color: source_color;
uniform sampler2D _moon_texture: source_color, repeat_disable;
// Background
uniform sampler2D _background_texture: source_color;
uniform vec4 _background_color: source_color;
// Stars Field
uniform vec4 _stars_field_color: source_color;
uniform sampler2D _stars_field_texture: source_color;
uniform float _stars_scintillation;
uniform float _stars_scintillation_speed;
uniform sampler2D _noise_tex: source_color;
// Clouds
uniform float _clouds_coverage;
uniform float _clouds_thickness;
uniform float _clouds_absorption;
uniform float _clouds_sky_tint_fade;
uniform float _clouds_intensity;
uniform float _clouds_size;
uniform vec2 _clouds_uv;
uniform float _clouds_speed;
uniform vec2 _clouds_direction;
uniform vec4 _clouds_day_color: source_color;
uniform vec4 _clouds_horizon_light_color: source_color;
uniform vec4 _clouds_night_color: source_color;
uniform sampler2D _clouds_texture;
// Inc
//------------------------------------------------------------------------------
const float kPI = 3.1415927f;
const float kINV_PI = 0.3183098f;
const float kHALF_PI = 1.5707963f;
const float kINV_HALF_PI = 0.6366198f;
const float kQRT_PI = 0.7853982f;
const float kINV_QRT_PI = 1.2732395f;
const float kPI4 = 12.5663706f;
const float kINV_PI4 = 0.0795775f;
const float k3PI16 = 0.1193662f;
const float kTAU = 6.2831853f;
const float kINV_TAU = 0.1591549f;
const float kE = 2.7182818f;
float saturate(float value){
return clamp(value, 0.0, 1.0);
}
vec3 saturateRGB(vec3 value){
return clamp(value.rgb, 0.0, 1.0);
}
// pow3
vec3 contrastLevel(vec3 vec, float level){
return mix(vec, vec * vec * vec, level);
}
vec3 tonemapPhoto(vec3 color, float exposure, float level){
color.rgb *= exposure;
return mix(color.rgb, 1.0 - exp(-color.rgb), level);
}
vec2 equirectUV(vec3 norm){
vec2 ret;
ret.x = (atan(norm.x, norm.z) + kPI) * kINV_TAU;
ret.y = acos(norm.y) * kINV_PI;
return ret;
}
/*
float random(vec2 uv){
float ret = dot(uv, vec2(12.9898, 78.233));
return fract(43758.5453 * sin(ret));
}
*/
float disk(vec3 norm, vec3 coords, lowp float size){
float dist = length(norm - coords);
return 1.0 - step(size, dist);
}
// Atmosphere Inc
//------------------------------------------------------------------------------
const float RAYLEIGH_ZENITH_LENGTH = 8.4e3;
const float MIE_ZENITH_LENGTH = 1.25e3;
float rayleighPhase(float mu){
return k3PI16 * (1.0 + mu * mu);
}
float miePhase(float mu, vec3 partial){
return kPI4 * (partial.x) * (pow(partial.y - partial.z * mu, -1.5));
}
// Simplifield for more performance
void simpleOpticalDepth(float y, out float sr, out float sm){
y = max(0.03, y + 0.03) + _atm_level_params.y;
y = 1.0 / (y * _atm_level_params.x);
sr = y * RAYLEIGH_ZENITH_LENGTH;
sm = y * MIE_ZENITH_LENGTH;
}
// Paper based
void opticalDepth(float y, out float sr, out float sm){
y = max(0.0, y);
y = saturate(y * _atm_level_params.x);
float zenith = acos(y);
zenith = cos(zenith) + 0.15 * pow(93.885 - ((zenith * 180.0) / kPI), -1.253);
zenith = 1.0 / (zenith + _atm_level_params.y);
sr = zenith * RAYLEIGH_ZENITH_LENGTH;
sm = zenith * MIE_ZENITH_LENGTH;
}
vec3 atmosphericScattering(float sr, float sm, vec2 mu, vec3 mult){
vec3 betaMie = _atm_beta_mie;
vec3 betaRay = _atm_beta_ray * _atm_thickness;
vec3 extcFactor = saturateRGB(exp(-(betaRay * sr + betaMie * sm)));
float extcFF = mix(saturate(_atm_thickness * 0.5), 1.0, mult.x);
vec3 finalExtcFactor = mix(1.0 - extcFactor, (1.0 - extcFactor) * extcFactor, extcFF);
float rayleighPhase = rayleighPhase(mu.x);
vec3 BRT = betaRay * rayleighPhase;
vec3 BMT = betaMie * miePhase(mu.x, _atm_sun_partial_mie_phase);
BMT *= _atm_sun_mie_intensity * _atm_sun_mie_tint.rgb;
vec3 BRMT = (BRT + BMT) / (betaRay + betaMie);
vec3 scatter = _atm_sun_intensity * (BRMT * finalExtcFactor) * _atm_day_tint.rgb * mult.y;
scatter = mix(scatter, scatter * (1.0 - extcFactor), _atm_darkness);
vec3 lcol = mix(_atm_day_tint.rgb, _atm_horizon_light_tint.rgb, mult.x);
vec3 nscatter = (1.0 - extcFactor) * _atm_night_tint.rgb;
nscatter += miePhase(mu.y, _atm_moon_partial_mie_phase) *
_atm_moon_mie_tint.rgb * _atm_moon_mie_intensity * 0.005;
return (scatter * lcol) + nscatter;
}
// Clouds
//------------------------------------------------------------------------------
float noiseClouds(vec2 coords, vec2 offset){
float speed = TIME * _clouds_speed * .5; // .5 matches cumulus clouds
vec2 wind = offset * speed;
vec2 wind2 = (offset + offset) * speed;
float a = textureLod(_clouds_texture, coords.xy * _clouds_uv - wind, 0.0).r;
float b = textureLod(_clouds_texture, coords.xy * _clouds_uv - wind2, 0.0).r;
return ((a + b) * 0.5);
}
float cloudsDensity(vec2 p, vec2 offset){
float d = noiseClouds(p, offset);
float c = 1.0 - _clouds_coverage;
d = d - c;
//d += d;
return saturate(d);
}
vec4 renderClouds(vec3 pos){
pos.xy = pos.xz / pos.y;
pos *= _clouds_size;
float density = cloudsDensity(pos.xy, _clouds_direction);
float sh = saturate(exp(-_clouds_absorption * density));
float a = saturate(density * _clouds_thickness);
return vec4(vec3(density*sh) * _clouds_intensity, a);
}
// Varyings
//------------------------------------------------------------------------------
varying vec4 world_pos;
varying vec4 moon_coords;
varying vec3 deep_space_coords;
varying vec4 angle_mult;
void vertex(){
vec4 vert = vec4(VERTEX, 0.0);
POSITION = PROJECTION_MATRIX * MODELVIEW_MATRIX * vert;
POSITION.z = 0.00000001;
world_pos = MODEL_MATRIX * vert;
moon_coords.xyz = (_moon_matrix * VERTEX) / _moon_size + 0.5;
moon_coords.w = dot(world_pos.xyz, _moon_direction.xyz);
deep_space_coords.xyz = (_deep_space_matrix * VERTEX).xyz;
angle_mult.x = saturate(1.0 - _sun_direction.y);
angle_mult.y = saturate(_sun_direction.y + 0.45);
angle_mult.z = saturate(-_sun_direction.y + 0.30);
angle_mult.w = saturate(-_sun_direction.y + 0.60);
}
void fragment(){
vec3 col = vec3(0.0);
vec3 worldPos = normalize(world_pos).xyz;
vec3 cloudsPos = worldPos;
// Atmosphere
vec2 mu = vec2(dot(_sun_direction, worldPos), dot(_moon_direction, worldPos));
float sr, sm;
simpleOpticalDepth(worldPos.y + _atm_level_params.z + _horizon_level, sr, sm);
worldPos.y += _horizon_level;
float horizonBlend = saturate((worldPos.y - 0.03) * 3.0);
vec3 scatter = atmosphericScattering(sr, sm, mu.xy, angle_mult.xyz);
col.rgb += scatter.rgb;
// Near Space
vec3 nearSpace = vec3(0.0);
vec3 sunDisk = disk(worldPos, _sun_direction, _sun_disk_size) *
_sun_disk_color.rgb * scatter.rgb;
sunDisk *= _sun_disk_intensity;
// Moon
vec4 moon = texture(_moon_texture, vec2(-moon_coords.x+1.0, moon_coords.y));
moon.rgb = contrastLevel(moon.rgb * _moon_color.rgb, _moon_color.a);
moon *= saturate(moon_coords.w);
float moonMask = saturate(1.0 - moon.a);
nearSpace = moon.rgb + (sunDisk.rgb * moonMask);
col.rgb += nearSpace;
vec3 deepSpace = vec3(0.0);
vec2 deepSpaceUV = equirectUV(normalize(deep_space_coords));
// Background
vec3 deepSpaceBackground = textureLod(_background_texture, deepSpaceUV, 0.0).rgb;
deepSpaceBackground *= _background_color.rgb;
deepSpaceBackground = contrastLevel(deepSpaceBackground, _background_color.a);
deepSpace.rgb += deepSpaceBackground.rgb * moonMask;
// Stars Field
float starsScintillation = textureLod(_noise_tex, UV + (TIME * _stars_scintillation_speed), 0.0).r;
starsScintillation = mix(1.0, starsScintillation * 1.5, _stars_scintillation);
vec3 starsField = textureLod(_stars_field_texture, deepSpaceUV, 0.0).rgb * _stars_field_color.rgb;
starsField = saturateRGB(mix(starsField.rgb, starsField.rgb * starsScintillation, _stars_scintillation));
//deepSpace.rgb -= saturate(starsField.r*10.0);
deepSpace.rgb += starsField.rgb * moonMask;
deepSpace.rgb *= angle_mult.z;
col.rgb += deepSpace.rgb * horizonBlend;
// Clouds
vec4 clouds = renderClouds(cloudsPos);
clouds.a = saturate(clouds.a);
clouds.rgb *= mix(mix(_clouds_day_color.rgb, _clouds_horizon_light_color.rgb, angle_mult.x),
_clouds_night_color.rgb, angle_mult.w);
clouds.a = mix(0.0, clouds.a, horizonBlend);
col.rgb = mix(col.rgb, clouds.rgb + mix(vec3(0.0), scatter, _clouds_sky_tint_fade), clouds.a);
col.rgb = mix(col.rgb, _ground_color.rgb * scatter, saturate((-worldPos.y - _atm_level_params.z)*100.0));
col.rgb = tonemapPhoto(col.rgb, _color_correction_params.y, _color_correction_params.x);
ALBEDO = col.rgb;
}

View File

@ -0,0 +1 @@
uid://cgjdgr8w1b5y

View File

@ -0,0 +1,28 @@
# Copyright (c) 2023-2025 Cory Petkovsek and Contributors
# Copyright (c) 2021 J. Cuellar
class_name DateTimeUtil
const TOTAL_HOURS: int = 24
static func compute_leap_year(year: int) -> bool:
return (year % 4 == 0) && (year % 100 != 0) || (year % 400 == 0);
static func hour_to_total_hours(hour: int) -> float:
return float(hour)
static func hour_minutes_to_total_hours(hour: int, minutes: int) -> float:
return float(hour) + float(minutes) / 60.0
static func hours_to_total_hours(hour:int, minutes: int, seconds: int) -> float:
return float(hour) + float(minutes) / 60.0 + float(seconds) / 3600.0
static func full_time_to_total_hours(hour: int, minutes: int, seconds: int, milliseconds: int) -> float:
return float(hour) + float(minutes) / 60.0 + float(seconds) / 3600.0 + \
float(milliseconds) / 3600000.0

View File

@ -0,0 +1 @@
uid://rb48skheqwhk

View File

@ -0,0 +1,31 @@
# Copyright (c) 2023-2025 Cory Petkovsek and Contributors
# Copyright (c) 2021 J. Cuellar
class_name OrbitalElements
# Handles Orbital elements for planetary system
var N: float # Longitude of the ascending node.
var i: float # The Inclination to the ecliptic.
var w: float # Argument of perihelion.
var a: float # Semi-major axis, or mean distance from sun.
var e: float # Eccentricity.
var M: float # Mean anomaly.
func get_orbital_elements(index: int, timeScale: float) -> void:
if index == 0: # Sun
N = 0.0
i = 0.0
w = 282.9404 + 4.70935e-5 * timeScale
a = 0.0
e = 0.016709 - 1.151e-9 * timeScale
M = 356.0470 + 0.9856002585 * timeScale
else: # Moon
N = 125.1228 - 0.0529538083 * timeScale
i = 5.1454
w = 318.0634 + 0.1643573223 * timeScale
a = 60.2666
e = 0.054900
M = 115.3654 + 13.0649929509 * timeScale

View File

@ -0,0 +1 @@
uid://d0fv2uybi1xxl

View File

@ -0,0 +1,24 @@
# Copyright (c) 2023-2025 Cory Petkovsek and Contributors
# Copyright (c) 2021 J. Cuellar
@tool
extends EditorPlugin
const __sky3d_script: String = "res://addons/sky_3d/src/Sky3D.gd"
const __sky3d_icon: String = "res://addons/sky_3d/assets/textures/SkyIcon.png"
const __skydome_script: String = "res://addons/sky_3d/src/Skydome.gd"
const __skydome_icon: String = "res://addons/sky_3d/assets/textures/SkyIcon.png"
const __time_of_day_script: String = "res://addons/sky_3d/src/TimeOfDay.gd"
const __time_of_day_icon: String = "res://addons/sky_3d/assets/textures/SkyIcon.png"
func _enter_tree() -> void:
add_custom_type("Sky3D", "Node", load(__sky3d_script), load(__sky3d_icon))
add_custom_type("Skydome", "Node", load(__skydome_script), load(__skydome_icon))
add_custom_type("TimeOfDay", "Node", load(__time_of_day_script), load(__time_of_day_icon))
func _exit_tree() -> void:
remove_custom_type("Sky3D")
remove_custom_type("Skydome")
remove_custom_type("TimeOfDay")

View File

@ -0,0 +1 @@
uid://bag65s8e7l2tq

View File

@ -0,0 +1,51 @@
# Copyright (c) 2023-2025 Cory Petkovsek and Contributors
# Copyright (c) 2021 J. Cuellar
class_name ScatterLib
# Atmospheric Scattering Lib.
# References:
# - Preetham and Hoffman Paper:
# See: https://developer.amd.com/wordpress/media/2012/10/ATI-LightScattering.pdf
const n: float = 1.0003 # Index of the air refraction
const n2: float = 1.00060009 # Index of the air refraction ˆ 2
const N: float = 2.545e25 # Molecular Density
const pn: float = 0.035 # Depolatization factor for standard air.
static func compute_wavelenghts_lambda(value: Vector3) -> Vector3:
return value * 1e-9
static func compute_wavlenghts(lambda: Vector3) -> Vector3:
var k = 4.0
var ret: Vector3 = lambda
ret.x = pow(lambda.x, k)
ret.y = pow(lambda.y, k)
ret.z = pow(lambda.z, k)
return ret
static func compute_beta_ray(wavelenghts: Vector3) -> Vector3:
var kr: float = (8.0 * pow(PI, 3.0) * pow(n2 - 1.0, 2.0) * (6.0 + 3.0 * pn))
var ret: Vector3 = 3.0 * N * wavelenghts * (6.0 - 7.0 * pn)
ret.x = kr / ret.x
ret.y = kr / ret.y
ret.z = kr / ret.z
return ret
static func compute_beta_mie(mie: float, turbidity: float) -> Vector3:
var k: float = 434e-6
return Vector3.ONE * mie * turbidity * k
static func get_partial_mie_phase(g: float) -> Vector3:
var g2: float = g * g
var ret: Vector3
# ret.x = ((1.0 - g2) / (2.0 + g2))
ret.x = 1.0 - g2
ret.y = 1.0 + g2
ret.z = 2.0 * g
return ret

View File

@ -0,0 +1 @@
uid://dus2oqhioyqwy

587
addons/sky_3d/src/Sky3D.gd Normal file
View File

@ -0,0 +1,587 @@
# Copyright (c) 2023-2025 Cory Petkovsek and Contributors
# Copyright (c) 2021 J. Cuellar
## Sky3D is an Atmosphereic Day/Night Cycle for Godot 4.
##
## It manages time, moving the sun, moon, and stars, and consolidates environmental lighting controls.
## To use it, remove any WorldEnvironment node from you scene, then add a new Sky3D node.
## Explore and configure the settings in the Sky3D, SunLight, MoonLight, TimeOfDay, and Skydome nodes.
@tool
class_name Sky3D
extends WorldEnvironment
## Emitted when the environment variable has changed.
signal environment_changed
## The Sun DirectionalLight.
var sun: DirectionalLight3D
## The Moon DirectionalLight.
var moon: DirectionalLight3D
## The TimeOfDay node.
var tod: TimeOfDay
## The Skydome node.
var sky: Skydome
## Enables all rendering and time tracking.
@export var sky3d_enabled: bool = true : set = set_sky3d_enabled
func set_sky3d_enabled(value: bool) -> void:
sky3d_enabled = value
if value:
show_sky()
resume()
else:
hide_sky()
pause()
#####################
## Visibility
#####################
@export_group("Visibility")
## Enables the sky shader. Disable sky, lights, fog for a black sky or call hide_sky().
@export var sky_enabled: bool = true : set = set_sky_enabled
func set_sky_enabled(value: bool) -> void:
sky_enabled = value
if not sky:
return
sky.sky_visible = value
sky.clouds_cumulus_visible = clouds_enabled and value
## Enables the Sun and Moon DirectionalLights.
@export var lights_enabled: bool = true : set = set_lights_enabled
func set_lights_enabled(value: bool) -> void:
lights_enabled = value
if not sky:
return
sky.sun_light_enable = value
sky.moon_light_enable = value
sky.__sun_light_node.visible = value && sky.__sun_light_node.light_energy > 0
sky.__moon_light_node.visible = value && sky.__moon_light_node.light_energy > 0
## Enables the screen space fog shader.
@export var fog_enabled: bool = true : set = set_fog_enabled
func set_fog_enabled(value: bool) -> void:
fog_enabled = value
if sky:
sky.fog_visible = value
## Enables the 2D and cumulus cloud layers.
@export var clouds_enabled: bool = true : set = set_clouds_enabled
func set_clouds_enabled(value: bool) -> void:
clouds_enabled = value
if not sky:
return
sky.clouds_cumulus_visible = value
sky.clouds_thickness = float(value) * 1.7
# TODO should create an on/off in skydome so disabling this doesn't change the enabled value
## Disables rendering of sky, fog, and lights
func hide_sky() -> void:
sky_enabled = false
lights_enabled = false
fog_enabled = false
## Enables rendering of sky, fog, and lights
func show_sky() -> void:
sky_enabled = true
lights_enabled = true
fog_enabled = true
#####################
## Time
#####################
@export_group("Time")
## Move time forward in the editor.
@export var enable_editor_time: bool = true : set = set_editor_time_enabled
func set_editor_time_enabled(value: bool) -> void:
enable_editor_time = value
if tod:
tod.update_in_editor = value
## Move time forward in game.
@export var enable_game_time: bool = true : set = set_game_time_enabled
func set_game_time_enabled(value: bool) -> void:
enable_game_time = value
if tod:
tod.update_in_game = value
## The time right now in hours, 0-23.99. Larger and smaller values will wrap
@export_range(0.0, 23.99, .01, "or_greater", "or_less") var current_time: float = 8.0 : set = set_current_time
func set_current_time(value: float) -> void:
current_time = value
if tod and tod.total_hours != current_time:
tod.total_hours = value
## The length of a full day in real minutes. +/-1440 (24 hours), forward or backwards.
@export_range(-1440,1440,.1) var minutes_per_day: float = 15.0 : set = set_minutes_per_day
func set_minutes_per_day(value):
minutes_per_day = value
if tod:
tod.total_cycle_in_minutes = value
## Frequency of updates. Set to 0.016 for 60fps.
@export_range(0.016, 10.0) var update_interval: float = 0.1 : set = set_update_interval
func set_update_interval(value: float) -> void:
update_interval = value
if tod:
tod.update_interval = value
## Tracks if the sun is above the horizon.
var _is_day: bool = true
## Returns true if the sun is above the horizon.
func is_day() -> bool:
return _is_day
## Returns true if the sun is below the horizon.
func is_night() -> bool:
return not _is_day
## Pauses time calculation.
func pause() -> void:
if tod:
tod.pause()
## Resumes time calculation.
func resume() -> void:
if tod:
tod.resume()
func _on_timeofday_updated(time: float) -> void:
if tod:
minutes_per_day = tod.total_cycle_in_minutes
current_time = tod.total_hours
update_interval = tod.update_interval
update_day_night()
## Recalculates if it's currently day or night. Adjusts night ambient light if changing state or forced.
func update_day_night(force: bool = false) -> void:
if not (sky and environment):
return
# If day transitioning to night
if abs(sky.sun_altitude) > 87 and (_is_day or force):
_is_day = false
var tween: Tween = get_tree().create_tween()
tween.set_parallel(true)
var contrib: float = minf(night_ambient_min, sky_contribution) if night_ambient else sky_contribution
tween.tween_property(environment, "ambient_light_sky_contribution", contrib, ambient_tween_time)
tween.tween_property(environment.sky.sky_material, "energy_multiplier", 1., ambient_tween_time)
# Else if night transitioning to day
elif abs(sky.sun_altitude) <= 87 and (not _is_day or force):
_is_day = true
var tween: Tween = get_tree().create_tween()
tween.set_parallel(true)
tween.tween_property(environment, "ambient_light_sky_contribution", sky_contribution, ambient_tween_time)
tween.tween_property(environment.sky.sky_material, "energy_multiplier", reflected_energy, ambient_tween_time)
#####################
## Lighting
#####################
@export_group("Lighting")
## Exposure used for the tonemapper. See Evironment.tonemap_exposure
@export_range(0,16,.005) var tonemap_exposure: float = 1.0: set = set_tonemap_exposure
func set_tonemap_exposure(value: float) -> void:
if environment:
tonemap_exposure = value
environment.tonemap_exposure = value
## Strength of skydome and fog.
@export_range(0,16,.005) var skydome_energy: float = 1.3: set = set_skydome_energy
func set_skydome_energy(value: float) -> void:
if sky:
skydome_energy = value
sky.exposure = value
sky.clouds_cumulus_intensity = value * .769 # (1/1.3 default sun energy)
## Exposure of camera connected to Environment.camera_attributes.
@export_range(0,16,.005) var camera_exposure: float = 1.0: set = set_camera_exposure
func set_camera_exposure(value: float) -> void:
if camera_attributes:
camera_exposure = value
camera_attributes.exposure_multiplier = value
## Maximum strength of Sun DirectionalLight, visible during the day.
@export_range(0,16,.005) var sun_energy: float = 1.0: set = set_sun_energy
func set_sun_energy(value: float) -> void:
sun_energy = value
if sky:
sky.sun_light_energy = value
## Opacity of Sun DirectionalLight shadow.
@export_range(0,1,.005) var sun_shadow_opacity: float = 1.0: set = set_sun_shadow_opacity
func set_sun_shadow_opacity(value: float) -> void:
sun_shadow_opacity = value
if sun:
sun.shadow_opacity = value
## Strength of refelcted light from the PhysicalSky. See PhysicalSkyMaterial.energy_multiplier
@export_range(0,128,.005) var reflected_energy: float = 1.0: set = set_reflected_energy
func set_reflected_energy(value: float) -> void:
if environment:
reflected_energy = value
if environment.sky:
environment.sky.sky_material.energy_multiplier = value
## Ratio of ambient light to sky light. See Environment.ambient_light_sky_contribution.
@export_range(0,1,.005) var sky_contribution: float = 1.0: set = set_sky_contribution
func set_sky_contribution(value: float) -> void:
if environment:
sky_contribution = value
environment.ambient_light_sky_contribution = value
update_day_night(true)
## Strength of ambient light. Works outside of Reflection Probe / GI volumes and sky_contribution < 1.
## See Environment.ambient_light_energy.
@export_range(0,16,.005) var ambient_energy: float = 1.0: set = set_ambient_energy
func set_ambient_energy(value: float) -> void:
if environment:
ambient_energy = value
environment.ambient_light_energy = value
update_day_night(true)
@export_subgroup("Auto Exposure")
## Enables CameraAttributes.auto_exposure_enabled.
@export var auto_exposure: bool = false: set = set_auto_exposure_enabled
func set_auto_exposure_enabled(value: bool) -> void:
if camera_attributes:
auto_exposure = value
camera_attributes.auto_exposure_enabled = value
## Sets CameraAttributes.auto_exposure_scale.
@export_range(0.01,16,.005) var auto_exposure_scale: float = 0.2: set = set_auto_exposure_scale
func set_auto_exposure_scale(value: float) -> void:
if camera_attributes:
auto_exposure_scale = value
camera_attributes.auto_exposure_scale = value
## Sets CameraAttributesPractical.auto_exposure_min_sensitivity.
@export_range(0,1600,.5) var auto_exposure_min: float = 0.0: set = set_auto_exposure_min
func set_auto_exposure_min(value: float) -> void:
if camera_attributes:
auto_exposure_min = value
camera_attributes.auto_exposure_min_sensitivity = value
## Sets CameraAttributesPractical.auto_exposure_max_sensitivity.
@export_range(30,64000,.5) var auto_exposure_max: float = 800.0: set = set_auto_exposure_max
func set_auto_exposure_max(value: float) -> void:
if camera_attributes:
auto_exposure_max = value
camera_attributes.auto_exposure_max_sensitivity = value
## Sets CameraAttributes.auto_exposure_speed.
@export_range(0.1,64,.1) var auto_exposure_speed: float = 0.5: set = set_auto_exposure_speed
func set_auto_exposure_speed(value: float) -> void:
if camera_attributes:
auto_exposure_speed = value
camera_attributes.auto_exposure_speed = value
@export_subgroup("Night")
## Maximum strength of Moon DirectionalLight, visible at night.
@export_range(0,16,.005) var moon_energy: float = .3: set = set_moon_energy
func set_moon_energy(value: float) -> void:
moon_energy = value
if moon:
sky.moon_light_energy = value
## Opacity of Moon DirectionalLight shadow.
@export_range(0,1,.005) var moon_shadow_opacity: float = 1.0: set = set_moon_shadow_opacity
func set_moon_shadow_opacity(value: float) -> void:
moon_shadow_opacity = value
if moon:
moon.shadow_opacity = value
## Enables a different ambient light setting at night.
@export var night_ambient: bool = true: set = set_night_ambient
func set_night_ambient(value: bool) -> void:
night_ambient = value
update_day_night(true)
## Strength of ambient light at night. Sky_contribution must be < 1. See Environment.ambient_light_energy.
@export_range(0,1,.005) var night_ambient_min: float = .7: set = set_night_ambient_min
func set_night_ambient_min(value: float) -> void:
night_ambient_min = value
if night_ambient:
update_day_night(true)
## Transition time for ambient light change, typically transitioning between day and night.
@export_range(0,30,.05) var ambient_tween_time: float = 3.: set = set_ambient_tween_time
func set_ambient_tween_time(value: float) -> void:
ambient_tween_time = value
#####################
## Setup
#####################
func _notification(what: int) -> void:
# Must be after _init and before _enter_tree to properly set vars like 'sky' for setters
if what in [ NOTIFICATION_SCENE_INSTANTIATED, NOTIFICATION_ENTER_TREE ]:
_initialize()
func _initialize() -> void:
# Create default environment
if environment == null:
environment = Environment.new()
environment.background_mode = Environment.BG_SKY
environment.sky = Sky.new()
environment.sky.sky_material = PhysicalSkyMaterial.new()
environment.sky.sky_material.use_debanding = false
environment.ambient_light_source = Environment.AMBIENT_SOURCE_SKY
environment.ambient_light_sky_contribution = 0.7
environment.ambient_light_energy = 1.0
environment.reflected_light_source = Environment.REFLECTION_SOURCE_SKY
environment.tonemap_mode = Environment.TONE_MAPPER_ACES
environment.tonemap_white = 6
emit_signal("environment_changed", environment)
# Create default camera attributes
if camera_attributes == null:
camera_attributes = CameraAttributesPractical.new()
# Assign children nodes
if has_node("SunLight"):
sun = $SunLight
elif is_inside_tree():
sun = DirectionalLight3D.new()
sun.name = "SunLight"
add_child(sun, true)
sun.owner = get_tree().edited_scene_root
sun.shadow_enabled = true
if has_node("MoonLight"):
moon = $MoonLight
elif is_inside_tree():
moon = DirectionalLight3D.new()
moon.name = "MoonLight"
add_child(moon, true)
moon.owner = get_tree().edited_scene_root
moon.shadow_enabled = true
if has_node("Skydome"):
sky = $Skydome
sky.environment = environment
elif is_inside_tree():
sky = Skydome.new()
sky.name = "Skydome"
add_child(sky, true)
sky.owner = get_tree().edited_scene_root
sky.sun_light_path = "../SunLight"
sky.moon_light_path = "../MoonLight"
sky.environment = environment
if has_node("TimeOfDay"):
tod = $TimeOfDay
elif is_inside_tree():
tod = TimeOfDay.new()
tod.name = "TimeOfDay"
add_child(tod, true)
tod.owner = get_tree().edited_scene_root
tod.dome_path = "../Skydome"
if tod and not tod.time_changed.is_connected(_on_timeofday_updated):
tod.time_changed.connect(_on_timeofday_updated)
func _enter_tree() -> void:
update_day_night(true)
func _set(property: StringName, value: Variant) -> bool:
match property:
"environment":
sky.environment = value
environment = value
emit_signal("environment_changed", environment)
return true
return false
#####################
## Constants
#####################
# Node names
const SKY_INSTANCE:= "_SkyMeshI"
const FOG_INSTANCE:= "_FogMeshI"
const MOON_INSTANCE:= "MoonRender"
const CLOUDS_C_INSTANCE:= "_CloudsCumulusI"
# Shaders
const _sky_shader: Shader = preload("res://addons/sky_3d/shaders/Sky.gdshader")
const _pv_sky_shader: Shader = preload("res://addons/sky_3d/shaders/PerVertexSky.gdshader")
const _clouds_cumulus_shader: Shader = preload("res://addons/sky_3d/shaders/CloudsCumulus.gdshader")
const _fog_shader: Shader = preload("res://addons/sky_3d/shaders/AtmFog.gdshader")
# Scenes
const _moon_render: PackedScene = preload("res://addons/sky_3d/assets/resources/MoonRender.tscn")
# Textures
const _moon_texture: Texture2D = preload("res://addons/sky_3d/assets/thirdparty/textures/moon/MoonMap.png")
const _background_texture: Texture2D = preload("res://addons/sky_3d/assets/thirdparty/textures/milkyway/Milkyway.jpg")
const _stars_field_texture: Texture2D = preload("res://addons/sky_3d/assets/thirdparty/textures/milkyway/StarField.jpg")
const _sun_moon_curve_fade: Curve = preload("res://addons/sky_3d/assets/resources/SunMoonLightFade.tres")
const _stars_field_noise: Texture2D = preload("res://addons/sky_3d/assets/textures/noise.jpg")
const _clouds_texture: Texture2D = preload("res://addons/sky_3d/assets/resources/SNoise.tres")
const _clouds_cumulus_texture: Texture2D = preload("res://addons/sky_3d/assets/textures/noiseClouds.png")
# Skydome
const DEFAULT_POSITION:= Vector3(0.0000001, 0.0000001, 0.0000001)
# Coords
const SUN_DIR_P:= "_sun_direction"
const MOON_DIR_P:= "_moon_direction"
const MOON_MATRIX:= "_moon_matrix"
# General
const TEXTURE_P:= "_texture"
const COLOR_CORRECTION_P:= "_color_correction_params"
const GROUND_COLOR_P:= "_ground_color"
const NOISE_TEX:= "_noise_tex"
const HORIZON_LEVEL = "_horizon_level"
# Atmosphere
const ATM_DARKNESS_P:= "_atm_darkness"
const ATM_BETA_RAY_P:= "_atm_beta_ray"
const ATM_SUN_INTENSITY_P:= "_atm_sun_intensity"
const ATM_DAY_TINT_P:= "_atm_day_tint"
const ATM_HORIZON_LIGHT_TINT_P:= "_atm_horizon_light_tint"
const ATM_NIGHT_TINT_P:= "_atm_night_tint"
const ATM_LEVEL_PARAMS_P:= "_atm_level_params"
const ATM_THICKNESS_P:= "_atm_thickness"
const ATM_BETA_MIE_P:= "_atm_beta_mie"
const ATM_SUN_MIE_TINT_P:= "_atm_sun_mie_tint"
const ATM_SUN_MIE_INTENSITY_P:= "_atm_sun_mie_intensity"
const ATM_SUN_PARTIAL_MIE_PHASE_P:= "_atm_sun_partial_mie_phase"
const ATM_MOON_MIE_TINT_P:= "_atm_moon_mie_tint"
const ATM_MOON_MIE_INTENSITY_P:= "_atm_moon_mie_intensity"
const ATM_MOON_PARTIAL_MIE_PHASE_P:= "_atm_moon_partial_mie_phase"
# Fog
const ATM_FOG_DENSITY_P:= "_fog_density"
const ATM_FOG_RAYLEIGH_DEPTH_P:= "_fog_rayleigh_depth"
const ATM_FOG_MIE_DEPTH_P:= "_fog_mie_depth"
const ATM_FOG_FALLOFF:= "_fog_falloff"
const ATM_FOG_START:= "_fog_start"
const ATM_FOG_END:= "_fog_end"
# Near Space
const SUN_DISK_COLOR_P:= "_sun_disk_color"
const SUN_DISK_INTENSITY_P:= "_sun_disk_intensity"
const SUN_DISK_SIZE_P:= "_sun_disk_size"
const MOON_COLOR_P:= "_moon_color"
const MOON_SIZE_P:= "_moon_size"
const MOON_TEXTURE_P:= "_moon_texture"
# Deep Space
const DEEP_SPACE_MATRIX_P:= "_deep_space_matrix"
const BG_COL_P:= "_background_color"
const BG_TEXTURE_P:= "_background_texture"
const STARS_COLOR_P:= "_stars_field_color"
const STARS_TEXTURE_P:= "_stars_field_texture"
const STARS_SC_P:= "_stars_scintillation"
const STARS_SC_SPEED_P:= "_stars_scintillation_speed"
# Clouds
const CLOUDS_THICKNESS:= "_clouds_thickness"
const CLOUDS_COVERAGE:= "_clouds_coverage"
const CLOUDS_ABSORPTION:= "_clouds_absorption"
const CLOUDS_SKY_TINT_FADE:= "_clouds_sky_tint_fade"
const CLOUDS_INTENSITY:= "_clouds_intensity"
const CLOUDS_SIZE:= "_clouds_size"
const CLOUDS_NOISE_FREQ:= "_clouds_noise_freq"
const CLOUDS_UV:= "_clouds_uv"
const CLOUDS_DIRECTION:= "_clouds_direction"
const CLOUDS_SPEED:= "_clouds_speed"
const CLOUDS_TEXTURE:= "_clouds_texture"
const CLOUDS_DAY_COLOR:= "_clouds_day_color"
const CLOUDS_HORIZON_LIGHT_COLOR:= "_clouds_horizon_light_color"
const CLOUDS_NIGHT_COLOR:= "_clouds_night_color"
const CLOUDS_MIE_INTENSITY:= "_clouds_mie_intensity"
const CLOUDS_PARTIAL_MIE_PHASE:= "_clouds_partial_mie_phase"

View File

@ -0,0 +1 @@
uid://bmywk4wvcp0lr

1865
addons/sky_3d/src/Skydome.gd Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1 @@
uid://27fj74ofndim

View File

@ -0,0 +1,77 @@
# Copyright (c) 2023-2025 Cory Petkovsek and Contributors
# Copyright (c) 2021 J. Cuellar
class_name TOD_Math
const RAD_TO_DEG: float = 57.2957795
const DEG_TO_RAD: float = 0.0174533
static func saturate(value: float) -> float:
return 0.0 if value < 0.0 else 1.0 if value > 1.0 else value
static func saturate_vec3(value: Vector3) -> Vector3:
var ret: Vector3
ret.x = 0.0 if value.x < 0.0 else 1.0 if value.x > 1.0 else value.x
ret.y = 0.0 if value.y < 0.0 else 1.0 if value.y > 1.0 else value.y
ret.z = 0.0 if value.z < 0.0 else 1.0 if value.z > 1.0 else value.z
return ret
static func saturate_color(value: Color) -> Color:
var ret: Color
ret.r = 0.0 if value.r < 0.0 else 1.0 if value.r > 1.0 else value.r
ret.g = 0.0 if value.g < 0.0 else 1.0 if value.g > 1.0 else value.g
ret.b = 0.0 if value.b < 0.0 else 1.0 if value.b > 1.0 else value.b
ret.a = 0.0 if value.a < 0.0 else 1.0 if value.a > 1.0 else value.a
return ret
static func rev(val: float) -> float:
return val - int(floor(val / 360.0)) * 360.0
static func lerp_f(from: float, to: float, t: float) -> float:
return (1 - t) * from + t * to
static func plerp_vec3(from: Vector3, to: Vector3, t: float) -> Vector3:
var ret: Vector3
ret.x = (1 - t) * from.x + t * to.x
ret.y = (1 - t) * from.y + t * to.y
ret.z = (1 - t) * from.z + t * to.z
return ret
static func plerp_color(from: Color, to: Color, t: float) -> Color:
var ret: Color
ret.r = (1 - t) * from.r + t * to.r
ret.g = (1 - t) * from.g + t * to.g
ret.b = (1 - t) * from.b + t * to.b
ret.a = (1 - t) * from.a + t * to.a
return ret
static func distance(a: Vector3, b: Vector3) -> float:
var ret: float
var x: float = a.x - b.x
var y: float = a.y - b.y
var z: float = a.z - b.z
ret = x * x + y * y + z * z
return sqrt(ret)
static func to_orbit(theta: float, pi: float, radius: float = 1.0) -> Vector3:
var ret: Vector3
var sinTheta: float = sin(theta)
var cosTheta: float = cos(theta)
var sinPI: float = sin(pi)
var cosPI: float = cos(pi)
ret.x = sinTheta * sinPI
ret.y = cosTheta
ret.z = sinTheta * cosPI
return ret * radius

View File

@ -0,0 +1 @@
uid://dtsesagkhvc07

View File

@ -0,0 +1,592 @@
# Copyright (c) 2023-2025 Cory Petkovsek and Contributors
# Copyright (c) 2021 J. Cuellar
@tool
class_name TimeOfDay
extends Node
signal time_changed(value)
signal day_changed(value)
signal month_changed(value)
signal year_changed(value)
var _update_timer: Timer
var _last_update: int = 0
@export var update_in_game: bool = true :
set(value):
update_in_game = value
if not Engine.is_editor_hint():
if update_in_game:
resume()
else:
pause()
@export var update_in_editor: bool = true :
set(value):
update_in_editor = value
if Engine.is_editor_hint():
if update_in_editor:
resume()
else:
pause()
@export_range(.016, 10) var update_interval: float = 0.1 :
set(value):
update_interval = clamp(value, .016, 10)
if is_instance_valid(_update_timer):
_update_timer.wait_time = update_interval
resume()
func _init() -> void:
set_total_hours(total_hours)
set_day(day)
set_month(month)
set_year(year)
set_latitude(latitude)
set_longitude(longitude)
set_utc(utc)
func _ready() -> void:
set_dome_path(dome_path)
_update_timer = Timer.new()
_update_timer.name = "Timer"
add_child(_update_timer)
_update_timer.timeout.connect(_on_timeout)
_update_timer.wait_time = update_interval
resume()
func _on_timeout() -> void:
if system_sync:
__get_date_time_os()
else:
var delta: float = .001 * (Time.get_ticks_msec() - _last_update)
__progress_time(delta)
__update_celestial_coords()
_last_update = Time.get_ticks_msec()
func pause() -> void:
if is_instance_valid(_update_timer):
_update_timer.stop()
func resume() -> void:
if is_instance_valid(_update_timer):
# Assume resuming from a pause, so timer only gets one tick
_last_update = Time.get_ticks_msec() - update_interval
if (Engine.is_editor_hint() and update_in_editor) or \
(not Engine.is_editor_hint() and update_in_game):
_update_timer.start()
#####################
## Target
#####################
var __dome: Skydome = null
var __dome_found: bool = false
var dome_path: NodePath: set = set_dome_path
func set_dome_path(value: NodePath) -> void:
dome_path = value
if value != null:
__dome = get_node_or_null(value) as Skydome
__dome_found = false if __dome == null else true
__update_celestial_coords()
#####################
## DateTime
#####################
var date_time_os: Dictionary
var system_sync: bool = false
var total_cycle_in_minutes: float = 15.0
var total_hours: float = 7.0 : set = set_total_hours
var day: int = 1: set = set_day
var month: int = 1: set = set_month
var year: int = 2025: set = set_year
func set_total_hours(value: float) -> void:
if total_hours != value:
total_hours = value
while total_hours > 23.9999:
total_hours -= 24
day += 1
while total_hours < 0.0000:
total_hours += 24
day -= 1
emit_signal("time_changed", total_hours)
__update_celestial_coords()
func set_day(value: int) -> void:
if day != value:
day = value
while day > max_days_per_month():
day -= max_days_per_month()
month += 1
while day < 1:
month -= 1
day += max_days_per_month()
emit_signal("day_changed", day)
__update_celestial_coords()
func set_month(value: int) -> void:
if month != value:
month = value
while month > 12:
month -= 12
year += 1
while month < 1:
month += 12
year -= 1
emit_signal("month_changed", month)
__update_celestial_coords()
func set_year(value: int) -> void:
if year != value:
year = value
emit_signal("year_changed", year)
__update_celestial_coords()
func is_learp_year() -> bool:
return DateTimeUtil.compute_leap_year(year)
func max_days_per_month() -> int:
match month:
1, 3, 5, 7, 8, 10, 12:
return 31
2:
return 29 if is_learp_year() else 28
return 30
func time_cycle_duration() -> float:
return total_cycle_in_minutes * 60.0
func is_begin_of_time() -> bool:
return year == 1 && month == 1 && day == 1
func is_end_of_time() -> bool:
return year == 9999 && month == 12 && day == 31
#####################
## Planetary
#####################
enum CelestialCalculationsMode{
Simple = 0,
Realistic
}
var celestials_calculations: int = 1: set = set_celestials_calculations
var latitude: float = 16.0: set = set_latitude
var longitude: float = 108.0: set = set_longitude
var utc: float = 7.0: set = set_utc
var compute_moon_coords: bool = true: set = set_compute_moon_coords
var compute_deep_space_coords: bool = true: set = set_compute_deep_space_coords
var moon_coords_offset := Vector2(0.0, 0.0): set = set_moon_coords_offset
var __sun_coords := Vector2.ZERO
var __moon_coords := Vector2.ZERO
var __sun_distance: float
var __true_sun_longitude: float
var __mean_sun_longitude: float
var __sideral_time: float
var __local_sideral_time: float
var __sun_orbital_elements := OrbitalElements.new()
var __moon_orbital_elements := OrbitalElements.new()
func set_celestials_calculations(value: int) -> void:
celestials_calculations = value
__update_celestial_coords()
notify_property_list_changed()
func set_latitude(value: float) -> void:
latitude = value
__update_celestial_coords()
func set_longitude(value: float) -> void:
longitude = value
__update_celestial_coords()
func set_utc(value: float) -> void:
utc = value
__update_celestial_coords()
func set_compute_moon_coords(value: bool) -> void:
compute_moon_coords = value
__update_celestial_coords()
notify_property_list_changed()
func set_compute_deep_space_coords(value: bool) -> void:
compute_deep_space_coords = value
__update_celestial_coords()
func set_moon_coords_offset(value: Vector2) -> void:
moon_coords_offset = value
__update_celestial_coords()
func __get_latitude_rad() -> float:
return latitude * TOD_Math.DEG_TO_RAD
func __get_total_hours_utc() -> float:
return total_hours - utc
func __get_time_scale() -> float:
return (367.0 * year - (7.0 * (year + ((month + 9.0) / 12.0))) / 4.0 +\
(275.0 * month) / 9.0 + day - 730530.0) + total_hours / 24.0
func __get_oblecl() -> float:
return (23.4393 - 2.563e-7 * __get_time_scale()) * TOD_Math.DEG_TO_RAD
#####################
## DateTime
#####################
func set_time(hour: int, minute: int, second: int) -> void:
set_total_hours(DateTimeUtil.hours_to_total_hours(hour, minute, second))
func set_from_datetime_dict(datetime_dict: Dictionary) -> void:
set_year(datetime_dict.year)
set_month(datetime_dict.month)
set_day(datetime_dict.day)
set_time(datetime_dict.hour, datetime_dict.minute, datetime_dict.second)
func get_datetime_dict() -> Dictionary:
var datetime_dict := {
"year": year,
"month": month,
"day": day,
"hour": floor(total_hours),
"minute": floor(fmod(total_hours, 1.0) * 60.0),
"second": floor(fmod(total_hours * 60.0, 1.0) * 60.0)
}
return datetime_dict
func set_from_unix_timestamp(timestamp: int) -> void:
set_from_datetime_dict(Time.get_datetime_dict_from_unix_time(timestamp))
func get_unix_timestamp() -> int:
return Time.get_unix_time_from_datetime_dict(get_datetime_dict())
func __progress_time(delta: float) -> void:
if not is_zero_approx(time_cycle_duration()):
set_total_hours(total_hours + delta / time_cycle_duration() * DateTimeUtil.TOTAL_HOURS)
func __get_date_time_os() -> void:
date_time_os = Time.get_datetime_dict_from_system()
set_time(date_time_os.hour, date_time_os.minute, date_time_os.second)
set_day(date_time_os.day)
set_month(date_time_os.month)
set_year(date_time_os.year)
#####################
## Planetary
#####################
func __update_celestial_coords() -> void:
if not __dome_found:
return
match celestials_calculations:
CelestialCalculationsMode.Simple:
__compute_simple_sun_coords()
__dome.sun_altitude = __sun_coords.y
__dome.sun_azimuth = __sun_coords.x
if compute_moon_coords:
__compute_simple_moon_coords()
__dome.moon_altitude = __moon_coords.y
__dome.moon_azimuth = __moon_coords.x
if compute_deep_space_coords:
var x = Quaternion.from_euler(Vector3( (90 + latitude) * TOD_Math.DEG_TO_RAD, 0.0, 0.0))
var y = Quaternion.from_euler(Vector3(0.0, 0.0, __sun_coords.y * TOD_Math.DEG_TO_RAD))
__dome.deep_space_quat = x * y
CelestialCalculationsMode.Realistic:
__compute_realistic_sun_coords()
__dome.sun_altitude = -__sun_coords.y * TOD_Math.RAD_TO_DEG
__dome.sun_azimuth = -__sun_coords.x * TOD_Math.RAD_TO_DEG
if compute_moon_coords:
__compute_realistic_moon_coords()
__dome.moon_altitude = -__moon_coords.y * TOD_Math.RAD_TO_DEG
__dome.moon_azimuth = -__moon_coords.x * TOD_Math.RAD_TO_DEG
if compute_deep_space_coords:
var x = Quaternion.from_euler(Vector3( (90 + latitude) * TOD_Math.DEG_TO_RAD, 0.0, 0.0) )
var y = Quaternion.from_euler(Vector3(0.0, 0.0, (180.0 - __local_sideral_time * TOD_Math.RAD_TO_DEG) * TOD_Math.DEG_TO_RAD))
__dome.deep_space_quat = x * y
func __compute_simple_sun_coords() -> void:
var altitude = (__get_total_hours_utc() + (TOD_Math.DEG_TO_RAD * longitude)) * (360/24)
__sun_coords.y = (180.0 - altitude)
__sun_coords.x = latitude
func __compute_simple_moon_coords() -> void:
__moon_coords.y = (180.0 - __sun_coords.y) + moon_coords_offset.y
__moon_coords.x = (180.0 + __sun_coords.x) + moon_coords_offset.x
func __compute_realistic_sun_coords() -> void:
# Orbital Elements
__sun_orbital_elements.get_orbital_elements(0, __get_time_scale())
__sun_orbital_elements.M = TOD_Math.rev(__sun_orbital_elements.M)
# Mean anomaly in radians
var MRad: float = TOD_Math.DEG_TO_RAD * __sun_orbital_elements.M
# Eccentric Anomaly
var E: float = __sun_orbital_elements.M + TOD_Math.RAD_TO_DEG * __sun_orbital_elements.e *\
sin(MRad) * (1 + __sun_orbital_elements.e * cos(MRad))
var ERad: float = E * TOD_Math.DEG_TO_RAD
# Rectangular coordinates of the sun in the plane of the ecliptic
var xv: float = cos(ERad) - __sun_orbital_elements.e
var yv: float = sin(ERad) * sqrt(1 - __sun_orbital_elements.e * __sun_orbital_elements.e)
# Distance and true anomaly
# Convert to distance and true anomaly(r = radians, v = degrees)
var r: float = sqrt(xv * xv + yv * yv)
var v: float = TOD_Math.RAD_TO_DEG * atan2(yv, xv)
__sun_distance = r
# True longitude
var lonSun: float = v + __sun_orbital_elements.w
lonSun = TOD_Math.rev(lonSun)
var lonSunRad = TOD_Math.DEG_TO_RAD * lonSun
__true_sun_longitude = lonSunRad
## Ecliptic and ecuatorial coords
# Ecliptic rectangular coords
var xs: float = r * cos(lonSunRad)
var ys: float = r * sin(lonSunRad)
# Ecliptic rectangular coordinates rotate these to equatorial coordinates
var obleclCos: float = cos(__get_oblecl())
var obleclSin: float = sin(__get_oblecl())
var xe: float = xs
var ye: float = ys * obleclCos - 0.0 * obleclSin
var ze: float = ys * obleclSin + 0.0 * obleclCos
# Ascencion and declination
var RA: float = TOD_Math.RAD_TO_DEG * atan2(ye, xe) / 15 # right ascension.
var decl: float = atan2(ze, sqrt(xe * xe + ye * ye)) # declination
# Mean longitude
var L: float = __sun_orbital_elements.w + __sun_orbital_elements.M
L = TOD_Math.rev(L)
__mean_sun_longitude = L
# Sideral time and hour angle
var GMST0: float = ((L/15) + 12)
__sideral_time = GMST0 + __get_total_hours_utc() + longitude / 15 # +15/15
__local_sideral_time = TOD_Math.DEG_TO_RAD * __sideral_time * 15
var HA: float = (__sideral_time - RA) * 15
var HARAD: float = TOD_Math.DEG_TO_RAD * HA
# Hour angle and declination in rectangular coords
# HA and Decl in rectangular coords
var declCos: float = cos(decl)
var x = cos(HARAD) * declCos # X Axis points to the celestial equator in the south.
var y = sin(HARAD) * declCos # Y axis points to the horizon in the west.
var z = sin(decl) # Z axis points to the north celestial pole.
# Rotate the rectangualar coordinates system along of the Y axis
var sinLat: float = sin(latitude * TOD_Math.DEG_TO_RAD)
var cosLat: float = cos(latitude * TOD_Math.DEG_TO_RAD)
var xhor: float = x * sinLat - z * cosLat
var yhor: float = y
var zhor: float = x * cosLat + z * sinLat
# Azimuth and altitude
__sun_coords.x = atan2(yhor, xhor) + PI
__sun_coords.y = (PI * 0.5) - asin(zhor) # atan2(zhor, sqrt(xhor * xhor + yhor * yhor))
func __compute_realistic_moon_coords() -> void:
# Orbital Elements
__moon_orbital_elements.get_orbital_elements(1, __get_time_scale())
__moon_orbital_elements.N = TOD_Math.rev(__moon_orbital_elements.N)
__moon_orbital_elements.w = TOD_Math.rev(__moon_orbital_elements.w)
__moon_orbital_elements.M = TOD_Math.rev(__moon_orbital_elements.M)
var NRad: float = TOD_Math.DEG_TO_RAD * __moon_orbital_elements.N
var IRad: float = TOD_Math.DEG_TO_RAD * __moon_orbital_elements.i
var MRad: float = TOD_Math.DEG_TO_RAD * __moon_orbital_elements.M
# Eccentric anomaly
var E: float = __moon_orbital_elements.M + TOD_Math.RAD_TO_DEG * __moon_orbital_elements.e * sin(MRad) *\
(1 + __sun_orbital_elements.e * cos(MRad))
var ERad = TOD_Math.DEG_TO_RAD * E
# Rectangular coords and true anomaly
# Rectangular coordinates of the sun in the plane of the ecliptic
var xv: float = __moon_orbital_elements.a * (cos(ERad) - __moon_orbital_elements.e)
var yv: float = __moon_orbital_elements.a * (sin(ERad) * sqrt(1 - __moon_orbital_elements.e * \
__moon_orbital_elements.e)) * sin(ERad)
# Convert to distance and true anomaly(r = radians, v = degrees)
var r: float = sqrt(xv * xv + yv * yv)
var v: float = TOD_Math.RAD_TO_DEG * atan2(yv, xv)
v = TOD_Math.rev(v)
var l: float = TOD_Math.DEG_TO_RAD * v + __moon_orbital_elements.w
var cosL: float = cos(l)
var sinL: float = sin(l)
var cosNRad: float = cos(NRad)
var sinNRad: float = sin(NRad)
var cosIRad: float = cos(IRad)
var xeclip: float = r * (cosNRad * cosL - sinNRad * sinL * cosIRad)
var yeclip: float = r * (sinNRad * cosL + cosNRad * sinL * cosIRad)
var zeclip: float = r * (sinL * sin(IRad))
# Geocentric coords
# Geocentric position for the moon and Heliocentric position for the planets
var lonecl: float = TOD_Math.RAD_TO_DEG * atan2(yeclip, xeclip)
lonecl = TOD_Math.rev(lonecl)
var latecl: float = TOD_Math.RAD_TO_DEG * atan2(zeclip, sqrt(xeclip * xeclip + yeclip * yeclip))
# Get true sun longitude
var lonsun: float = __true_sun_longitude
# Ecliptic longitude and latitude in radians
var loneclRad: float = TOD_Math.DEG_TO_RAD * lonecl
var lateclRad: float = TOD_Math.DEG_TO_RAD * latecl
var nr: float = 1.0
var xh: float = nr * cos(loneclRad) * cos(lateclRad)
var yh: float = nr * sin(loneclRad) * cos(lateclRad)
var zh: float = nr * sin(lateclRad)
# Geocentric coords
var xs: float = 0.0
var ys: float = 0.0
# Convert the geocentric position to heliocentric position
var xg: float = xh + xs
var yg: float = yh + ys
var zg: float = zh
# Ecuatorial coords
# Cobert xg, yg un equatorial coords
var obleclCos: float = cos(__get_oblecl())
var obleclSin: float = sin(__get_oblecl())
var xe: float = xg
var ye: float = yg * obleclCos - zg * obleclSin
var ze: float = yg * obleclSin + zg * obleclCos
# Right ascention
var RA: float = TOD_Math.RAD_TO_DEG * atan2(ye, xe)
RA = TOD_Math.rev(RA)
# Declination
var decl: float = TOD_Math.RAD_TO_DEG * atan2(ze, sqrt(xe * xe + ye * ye))
var declRad: float = TOD_Math.DEG_TO_RAD * decl
# Sideral time and hour angle
var HA: float = ((__sideral_time * 15) - RA)
HA = TOD_Math.rev(HA)
var HARAD: float = TOD_Math.DEG_TO_RAD * HA
# HA y Decl in rectangular coordinates
var declCos: float = cos(declRad)
var xr: float = cos(HARAD) * declCos
var yr: float = sin(HARAD) * declCos
var zr: float = sin(declRad)
# Rotate the rectangualar coordinates system along of the Y axis(radians)
var sinLat: float = sin(__get_latitude_rad())
var cosLat: float = cos(__get_latitude_rad())
var xhor: float = xr * sinLat - zr * cosLat
var yhor: float = yr
var zhor: float = xr * cosLat + zr * sinLat
# Azimuth and altitude
__moon_coords.x = atan2(yhor, xhor) + PI
__moon_coords.y = (PI *0.5) - atan2(zhor, sqrt(xhor * xhor + yhor * yhor)) # Mathf.Asin(zhor)
func _get_property_list() -> Array:
var ret: Array
ret.push_back({name = "Time Of Day", type=TYPE_NIL, usage=PROPERTY_USAGE_CATEGORY})
ret.push_back({name = "Target", type=TYPE_NIL, usage=PROPERTY_USAGE_GROUP})
ret.push_back({name = "dome_path", type=TYPE_NODE_PATH})
ret.push_back({name = "DateTime", type=TYPE_NIL, usage=PROPERTY_USAGE_GROUP})
ret.push_back({name = "system_sync", type=TYPE_BOOL})
ret.push_back({name = "total_cycle_in_minutes", type=TYPE_FLOAT})
ret.push_back({name = "total_hours", type=TYPE_FLOAT, hint=PROPERTY_HINT_RANGE, hint_string="0.0, 24.0"})
ret.push_back({name = "day", type=TYPE_INT, hint=PROPERTY_HINT_RANGE, hint_string="0, 31"})
ret.push_back({name = "month", type=TYPE_INT, hint=PROPERTY_HINT_RANGE, hint_string="0, 12"})
ret.push_back({name = "year", type=TYPE_INT, hint=PROPERTY_HINT_RANGE, hint_string="-9999, 9999"})
ret.push_back({name = "Planetary And Location", type=TYPE_NIL, usage=PROPERTY_USAGE_GROUP})
ret.push_back({name = "celestials_calculations", type=TYPE_INT, hint=PROPERTY_HINT_ENUM, hint_string="Simple, Realistic"})
ret.push_back({name = "compute_moon_coords", type=TYPE_BOOL})
if celestials_calculations == 0 && compute_moon_coords:
ret.push_back({name = "moon_coords_offset", type=TYPE_VECTOR2})
ret.push_back({name = "compute_deep_space_coords", type=TYPE_BOOL})
ret.push_back({name = "latitude", type=TYPE_FLOAT, hint=PROPERTY_HINT_RANGE, hint_string="-90.0, 90.0"})
ret.push_back({name = "longitude", type=TYPE_FLOAT, hint=PROPERTY_HINT_RANGE, hint_string="-180.0, 180.0"})
ret.push_back({name = "utc", type=TYPE_FLOAT, hint=PROPERTY_HINT_RANGE, hint_string="-12.0, 12.0"})
return ret

View File

@ -0,0 +1 @@
uid://bm0hx4mklpml

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 Cory Petkovsek, Roope Palmroos, and Contributors.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,47 @@
![Terrain3D Logo](/doc/docs/images/terrain3d.jpg)
# Terrain3D
A high performance, editable terrain system for Godot 4.
## Features
* Written in C++ as a GDExtension addon, which works with official builds of Godot Engine
* Can be accessed by GDScript, C#, and any language Godot supports
* Geomorphing Geometric Clipmap Mesh Terrain, as used in The Witcher 3. See [System Architecture](https://terrain3d.readthedocs.io/en/stable/docs/system_architecture.html)
* Terrains as small as 64x64m up to 65.5x65.5km (4295km^2) in variable sized regions
* Up to 32 textures
* Up to 10 levels of detail for the terrain mesh
* Foliage instancing, with up to 10 levels of detail, and a shadow impostor
* Sculpting, holes, texture painting, texture detiling, painting colors and wetness
* Imports heightmaps from [HTerrain](https://github.com/Zylann/godot_heightmap_plugin/), Gaea, World Creator, World Machine, Unity, Unreal and any tool that can export a heightmap. See [heightmaps](https://terrain3d.readthedocs.io/en/stable/docs/heightmaps.html)
## Getting Started
1. Read the [Installation & Upgrades](https://terrain3d.readthedocs.io/en/stable/docs/installation.html) instructions.
2. For support, read [Getting Help](https://terrain3d.readthedocs.io/en/stable/docs/getting_help.html) and join our [Discord server](https://tokisan.com/discord).
3. Watch the [tutorial videos](https://terrain3d.readthedocs.io/en/stable/docs/tutorial_videos.html).
## Credit
Developed for the Godot community by:
|||
|--|--|
| **Cory Petkovsek, Tokisan Games** | [<img src="https://github.com/dmhendricks/signature-social-icons/blob/master/icons/round-flat-filled/35px/twitter.png?raw=true" width="24"/>](https://twitter.com/TokisanGames) [<img src="https://github.com/dmhendricks/signature-social-icons/blob/master/icons/round-flat-filled/35px/github.png?raw=true" width="24"/>](https://github.com/TokisanGames) [<img src="https://github.com/dmhendricks/signature-social-icons/blob/master/icons/round-flat-filled/35px/www.png?raw=true" width="24"/>](https://tokisan.com/) [<img src="https://github.com/dmhendricks/signature-social-icons/blob/master/icons/round-flat-filled/35px/discord.png?raw=true" width="24"/>](https://tokisan.com/discord) [<img src="https://github.com/dmhendricks/signature-social-icons/blob/master/icons/round-flat-filled/35px/youtube.png?raw=true" width="24"/>](https://www.youtube.com/@TokisanGames)|
| **Roope Palmroos, Outobugi Games** | [<img src="https://github.com/dmhendricks/signature-social-icons/blob/master/icons/round-flat-filled/35px/twitter.png?raw=true" width="24"/>](https://twitter.com/outobugi) [<img src="https://github.com/dmhendricks/signature-social-icons/blob/master/icons/round-flat-filled/35px/github.png?raw=true" width="24"/>](https://github.com/outobugi) [<img src="https://github.com/dmhendricks/signature-social-icons/blob/master/icons/round-flat-filled/35px/www.png?raw=true" width="24"/>](https://outobugi.com/) [<img src="https://github.com/dmhendricks/signature-social-icons/blob/master/icons/round-flat-filled/35px/youtube.png?raw=true" width="24"/>](https://www.youtube.com/@outobugi)|
And other contributors displayed on the right of the github page and in [AUTHORS.md](https://terrain3d.readthedocs.io/en/stable/docs/authors.html).
## Contributing
Please see [CONTRIBUTING.md](https://github.com/TokisanGames/Terrain3D/blob/main/CONTRIBUTING.md) if you would like to help make Terrain3D the best terrain system for Godot.
## License
This addon has been released under the [MIT License](https://github.com/TokisanGames/Terrain3D/blob/main/LICENSE.txt).

Binary file not shown.

Binary file not shown.

View File

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More