diff --git a/previewer/previewer.gd b/previewer/previewer.gd index 0c65a9f..be8a423 100644 --- a/previewer/previewer.gd +++ b/previewer/previewer.gd @@ -23,6 +23,8 @@ func _ready(): $settings.show() + $sky/viewport/sprite.set_time_of_day( 8.0, $light_system/directional_light, 25.0 ) + func _process( delta ): iTime+=delta diff --git a/previewer/previewer.tscn b/previewer/previewer.tscn index 5abd48e..b7a2967 100644 --- a/previewer/previewer.tscn +++ b/previewer/previewer.tscn @@ -1,16 +1,17 @@ -[gd_scene load_steps=22 format=2] +[gd_scene load_steps=23 format=2] [ext_resource path="res://previewer/previewer.gd" type="Script" id=1] [ext_resource path="res://shaders/sky.shader" type="Shader" id=2] -[ext_resource path="res://previewer/sky.gd" type="Script" id=3] -[ext_resource path="res://previewer/dummy/dummy.tscn" type="PackedScene" id=4] -[ext_resource path="res://textures/tilables/basic_texture_1024.png" type="Texture" id=5] -[ext_resource path="res://meshes/decors/rocks/cliff_001.tscn" type="PackedScene" id=6] -[ext_resource path="res://meshes/props/pendo_teddy/pendo_teddy.tscn" type="PackedScene" id=7] -[ext_resource path="res://meshes/props/travel_box/container.tscn" type="PackedScene" id=8] -[ext_resource path="res://meshes/props/reference_box/reference_box.tscn" type="PackedScene" id=9] -[ext_resource path="res://meshes/props/fountain_suzanha/Fountain_suzanha.tscn" type="PackedScene" id=10] -[ext_resource path="res://previewer/settings.tscn" type="PackedScene" id=11] +[ext_resource path="res://textures/sky/milkywaypan_brunier_2048.jpg" type="Texture" id=3] +[ext_resource path="res://previewer/sky.gd" type="Script" id=4] +[ext_resource path="res://previewer/dummy/dummy.tscn" type="PackedScene" id=5] +[ext_resource path="res://textures/tilables/basic_texture_1024.png" type="Texture" id=6] +[ext_resource path="res://meshes/decors/rocks/cliff_001.tscn" type="PackedScene" id=7] +[ext_resource path="res://meshes/props/pendo_teddy/pendo_teddy.tscn" type="PackedScene" id=8] +[ext_resource path="res://meshes/props/travel_box/container.tscn" type="PackedScene" id=9] +[ext_resource path="res://meshes/props/reference_box/reference_box.tscn" type="PackedScene" id=10] +[ext_resource path="res://meshes/props/fountain_suzanha/Fountain_suzanha.tscn" type="PackedScene" id=11] +[ext_resource path="res://previewer/settings.tscn" type="PackedScene" id=12] [sub_resource type="OpenSimplexNoise" id=1] period = 8.0 @@ -29,7 +30,19 @@ shader_param/COVERAGE = 0.5 shader_param/THICKNESS = 25.0 shader_param/ABSORPTION = 1.031 shader_param/STEPS = 25 +shader_param/earth_radius_km = 6371.0 +shader_param/atmo_radius_km = 6471.0 +shader_param/cam_height_m = 1.8 +shader_param/sun_pos = Vector3( 1, 1, 1 ) +shader_param/sun_intensity = 22.0 +shader_param/rayleigh_coeff = Vector3( 5.5, 13, 22.4 ) +shader_param/mie_coeff = 21.0 +shader_param/rayleigh_scale = 800.0 +shader_param/mie_scale = 120.0 +shader_param/mie_scatter_dir = 0.758 +shader_param/rotate_night_sky = null shader_param/iChannel0 = SubResource( 2 ) +shader_param/night_sky = ExtResource( 3 ) [sub_resource type="ImageTexture" id=4] size = Vector2( 1280, 720 ) @@ -51,7 +64,7 @@ ambient_light_energy = 3.82 [sub_resource type="SpatialMaterial" id=8] flags_unshaded = true flags_world_triplanar = true -albedo_texture = ExtResource( 5 ) +albedo_texture = ExtResource( 6 ) uv1_scale = Vector3( 122, 122, 122 ) [sub_resource type="PlaneMesh" id=9] @@ -80,12 +93,12 @@ render_target_update_mode = 3 material = SubResource( 3 ) texture = SubResource( 4 ) centered = false -script = ExtResource( 3 ) +script = ExtResource( 4 ) [node name="world_environment" type="WorldEnvironment" parent="."] environment = SubResource( 7 ) -[node name="dummy" parent="." instance=ExtResource( 4 )] +[node name="dummy" parent="." instance=ExtResource( 5 )] [node name="terrain" type="Spatial" parent="."] @@ -93,44 +106,44 @@ environment = SubResource( 7 ) transform = Transform( 60.964, 0, 0, 0, 1.21928, 0, 0, 0, 60.964, 0, 0, 0 ) mesh = SubResource( 9 ) -[node name="cliff" parent="terrain" instance=ExtResource( 6 )] +[node name="cliff" parent="terrain" instance=ExtResource( 7 )] transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -48.2121 ) moss_height = 15.0 moss_fade = 2.5 [node name="props" type="Spatial" parent="."] -[node name="pendo_teddy" parent="props" instance=ExtResource( 7 )] +[node name="pendo_teddy" parent="props" instance=ExtResource( 8 )] transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -3 ) -[node name="container" parent="props" instance=ExtResource( 8 )] +[node name="container" parent="props" instance=ExtResource( 9 )] transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -5 ) color = Color( 0.145098, 0.0980392, 0.713726, 1 ) lid_angle = 45.0 -[node name="container_2" parent="props" instance=ExtResource( 8 )] +[node name="container_2" parent="props" instance=ExtResource( 9 )] transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -1.24144, 0, -5 ) color = Color( 0.491686, 0.159256, 0.832031, 1 ) lid_angle = 90.0 -[node name="container_3" parent="props" instance=ExtResource( 8 )] +[node name="container_3" parent="props" instance=ExtResource( 9 )] transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -2.6614, 0, -5 ) color = Color( 0.360784, 1, 0, 1 ) lid_angle = 12.0 -[node name="container_4" parent="props" instance=ExtResource( 8 )] +[node name="container_4" parent="props" instance=ExtResource( 9 )] transform = Transform( 0.457191, 0, 0.889369, 0, 1, 0, -0.889369, 0, 0.457191, -3.94754, 4.76837e-007, -4.27729 ) color = Color( 0.972549, 0.196078, 0.0431373, 1 ) -[node name="reference_box" parent="props" instance=ExtResource( 9 )] +[node name="reference_box" parent="props" instance=ExtResource( 10 )] -[node name="Fountain_suzanha" parent="props" instance=ExtResource( 10 )] +[node name="Fountain_suzanha" parent="props" instance=ExtResource( 11 )] transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 5, 0.472, -5 ) [node name="light_system" type="Spatial" parent="."] [node name="directional_light" type="DirectionalLight" parent="light_system"] -transform = Transform( 0.522088, 0.655715, -0.545401, 0, 0.639473, 0.768814, 0.852892, -0.401389, 0.333861, 0, 13.7088, 0 ) +transform = Transform( 0.522088, 0.655715, -0.545401, 0, 0.639473, 0.768814, 0.852892, -0.401388, 0.333861, 0, 13.7088, 0 ) light_energy = 2.21 shadow_enabled = true @@ -139,7 +152,7 @@ transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 21.7307, 0 ) extents = Vector3( 63.192, 25, 76.323 ) data = SubResource( 10 ) -[node name="settings" parent="." instance=ExtResource( 11 )] +[node name="settings" parent="." instance=ExtResource( 12 )] margin_left = -475.0 margin_top = -243.0 margin_right = -219.0 diff --git a/previewer/settings.gd b/previewer/settings.gd index 385decd..c896675 100644 --- a/previewer/settings.gd +++ b/previewer/settings.gd @@ -13,3 +13,7 @@ func _on_sky_absorption_value_changed(value): func _on_sky_steps_value_changed(value): sky_sprite.step_scb( value ) + + +func _on_sky_time_value_changed(value): + sky_sprite.set_time_of_day( value, get_tree().get_root().get_node("$light_system/directional_light"), 25.0 ) diff --git a/previewer/settings.tscn b/previewer/settings.tscn index d4229fe..b3d528a 100644 --- a/previewer/settings.tscn +++ b/previewer/settings.tscn @@ -63,12 +63,12 @@ max_value = 1.0 step = 0.001 value = 0.5 -[node name="sky_thickness_box_2" type="HBoxContainer" parent="scroll_container/controls/sky_box"] +[node name="sky_thickness_box" type="HBoxContainer" parent="scroll_container/controls/sky_box"] margin_top = 20.0 margin_right = 256.0 margin_bottom = 36.0 -[node name="label" type="Label" parent="scroll_container/controls/sky_box/sky_thickness_box_2"] +[node name="label" type="Label" parent="scroll_container/controls/sky_box/sky_thickness_box"] margin_top = 1.0 margin_right = 126.0 margin_bottom = 15.0 @@ -76,19 +76,19 @@ size_flags_horizontal = 3 text = "Thickness" align = 2 -[node name="sky_thickness" type="HSlider" parent="scroll_container/controls/sky_box/sky_thickness_box_2"] +[node name="sky_thickness" type="HSlider" parent="scroll_container/controls/sky_box/sky_thickness_box"] margin_left = 130.0 margin_right = 256.0 margin_bottom = 16.0 size_flags_horizontal = 3 value = 25.0 -[node name="sky_absorption_box_3" type="HBoxContainer" parent="scroll_container/controls/sky_box"] +[node name="sky_absorption_box" type="HBoxContainer" parent="scroll_container/controls/sky_box"] margin_top = 40.0 margin_right = 256.0 margin_bottom = 56.0 -[node name="label" type="Label" parent="scroll_container/controls/sky_box/sky_absorption_box_3"] +[node name="label" type="Label" parent="scroll_container/controls/sky_box/sky_absorption_box"] margin_top = 1.0 margin_right = 126.0 margin_bottom = 15.0 @@ -96,7 +96,7 @@ size_flags_horizontal = 3 text = "Absorbtion" align = 2 -[node name="sky_absorption" type="HSlider" parent="scroll_container/controls/sky_box/sky_absorption_box_3"] +[node name="sky_absorption" type="HSlider" parent="scroll_container/controls/sky_box/sky_absorption_box"] margin_left = 130.0 margin_right = 256.0 margin_bottom = 16.0 @@ -105,12 +105,12 @@ max_value = 10.0 step = 0.001 value = 1.031 -[node name="sky_steps_box_4" type="HBoxContainer" parent="scroll_container/controls/sky_box"] +[node name="sky_steps_box" type="HBoxContainer" parent="scroll_container/controls/sky_box"] margin_top = 60.0 margin_right = 256.0 margin_bottom = 76.0 -[node name="label" type="Label" parent="scroll_container/controls/sky_box/sky_steps_box_4"] +[node name="label" type="Label" parent="scroll_container/controls/sky_box/sky_steps_box"] margin_top = 1.0 margin_right = 126.0 margin_bottom = 15.0 @@ -118,13 +118,36 @@ size_flags_horizontal = 3 text = "Steps" align = 2 -[node name="sky_steps" type="HSlider" parent="scroll_container/controls/sky_box/sky_steps_box_4"] +[node name="sky_steps" type="HSlider" parent="scroll_container/controls/sky_box/sky_steps_box"] margin_left = 130.0 margin_right = 256.0 margin_bottom = 16.0 size_flags_horizontal = 3 value = 25.0 + +[node name="sky_time_box" type="HBoxContainer" parent="scroll_container/controls/sky_box"] +margin_top = 60.0 +margin_right = 256.0 +margin_bottom = 76.0 + +[node name="label" type="Label" parent="scroll_container/controls/sky_box/sky_time_box"] +margin_top = 1.0 +margin_right = 126.0 +margin_bottom = 15.0 +size_flags_horizontal = 3 +text = "Time of day" +align = 2 + +[node name="sky_time" type="HSlider" parent="scroll_container/controls/sky_box/sky_time_box"] +margin_left = 130.0 +margin_right = 256.0 +margin_bottom = 16.0 +size_flags_horizontal = 3 +max_value = 24.0 +step = 0.01 +value = 8.0 [connection signal="value_changed" from="scroll_container/controls/sky_box/sky_coverage_box/sky_coverage" to="." method="_on_sky_coverage_value_changed"] -[connection signal="value_changed" from="scroll_container/controls/sky_box/sky_thickness_box_2/sky_thickness" to="." method="_on_sky_thickness_value_changed"] -[connection signal="value_changed" from="scroll_container/controls/sky_box/sky_absorption_box_3/sky_absorption" to="." method="_on_sky_absorption_value_changed"] -[connection signal="value_changed" from="scroll_container/controls/sky_box/sky_steps_box_4/sky_steps" to="." method="_on_sky_steps_value_changed"] +[connection signal="value_changed" from="scroll_container/controls/sky_box/sky_thickness_box/sky_thickness" to="." method="_on_sky_thickness_value_changed"] +[connection signal="value_changed" from="scroll_container/controls/sky_box/sky_absorption_box/sky_absorption" to="." method="_on_sky_absorption_value_changed"] +[connection signal="value_changed" from="scroll_container/controls/sky_box/sky_steps_box/sky_steps" to="." method="_on_sky_steps_value_changed"] +[connection signal="value_changed" from="scroll_container/controls/sky_box/sky_time_box/sky_time" to="." method="_on_sky_time_value_changed"] diff --git a/previewer/sky.gd b/previewer/sky.gd index d67983c..7d6e12a 100644 --- a/previewer/sky.gd +++ b/previewer/sky.gd @@ -20,3 +20,27 @@ func absb_scb(value): func step_scb(value): self.material.set("shader_param/STEPS",value) + + +export var sun_position = Vector3(0.0, 1.0, 0.0) setget set_sun_position, get_sun_position +func set_sun_position(new_position): + sun_position = new_position + if self.material: + self.material.set_shader_param("sun_pos", sun_position) +# _trigger_update_sky() +func get_sun_position(): + return sun_position + +func set_time_of_day(hours, directional_light, horizontal_angle = 0.0): + var sun_position = Vector3(0.0, -100.0, 0.0) + sun_position = sun_position.rotated(Vector3(1.0, 0.0, 0.0), hours * PI / 12.0) + sun_position = sun_position.rotated(Vector3(0.0, 1.0, 0.0), horizontal_angle) + + if directional_light: + var t = directional_light.transform + t.origin = sun_position + directional_light.transform = t.looking_at(Vector3(0.0, 0.0, 0.0), Vector3(0.0, 1.0, 0.0)) + directional_light.light_energy = 1.0 - clamp(abs(hours - 12.0) / 6.0, 0.0, 1.0) + + # and update our sky + set_sun_position(sun_position) \ No newline at end of file diff --git a/shaders/sky.shader b/shaders/sky.shader index 5e04d81..77e8b59 100644 --- a/shaders/sky.shader +++ b/shaders/sky.shader @@ -10,6 +10,171 @@ uniform float THICKNESS :hint_range(0,100); //25. uniform float ABSORPTION :hint_range(0,10); //1.030725 uniform int STEPS :hint_range(0,100); //25 + + +//////////////////////////////// +uniform float earth_radius_km = 6371; +uniform float atmo_radius_km = 6471; +uniform float cam_height_m = 1.8; +//uniform vec3 sun_pos = vec3(0.0, 0.1, -0.5); +uniform vec3 sun_pos = vec3(1.0, 1.0, 1.0); +uniform float sun_intensity = 22.0; +uniform vec3 rayleigh_coeff = vec3(5.5, 13.0, 22.4); // we divide this by 100000 +uniform float mie_coeff = 21.0; // we divide this by 100000 +uniform float rayleigh_scale = 800; +uniform float mie_scale = 120; +uniform float mie_scatter_dir = 0.758; + +uniform sampler2D night_sky : hint_black_albedo; +uniform mat3 rotate_night_sky; + + + +// Atmosphere code from: https://github.com/wwwtyro/glsl-atmosphere +vec2 rsi(vec3 r0, vec3 rd, float sr) { + // ray-sphere intersection that assumes + // the sphere is centered at the origin. + // No intersection when result.x > result.y + float a = dot(rd, rd); + float b = 2.0 * dot(rd, r0); + float c = dot(r0, r0) - (sr * sr); + float d = (b*b) - 4.0*a*c; + if (d < 0.0) return vec2(100000.0,-100000.0); + return vec2( + (-b - sqrt(d))/(2.0*a), + (-b + sqrt(d))/(2.0*a) + ); +} + +vec3 atmosphere(vec3 r, vec3 r0, vec3 pSun, float iSun, float rPlanet, float rAtmos, vec3 kRlh, float kMie, float shRlh, float shMie, float g) { + float PI = 3.14159265358979; + int iSteps = 16; + int jSteps = 8; + + // Normalize the sun and view directions. + pSun = normalize(pSun); + r = normalize(r); + + // Calculate the step size of the primary ray. + vec2 p = rsi(r0, r, rAtmos); + if (p.x > p.y) return vec3(0,0,0); + p.y = min(p.y, rsi(r0, r, rPlanet).x); + float iStepSize = (p.y - p.x) / float(iSteps); + + // Initialize the primary ray time. + float iTimeBis = 0.0; + + // Initialize accumulators for Rayleigh and Mie scattering. + vec3 totalRlh = vec3(0,0,0); + vec3 totalMie = vec3(0,0,0); + + // Initialize optical depth accumulators for the primary ray. + float iOdRlh = 0.0; + float iOdMie = 0.0; + + // Calculate the Rayleigh and Mie phases. + float mu = dot(r, pSun); + float mumu = mu * mu; + float gg = g * g; + float pRlh = 3.0 / (16.0 * PI) * (1.0 + mumu); + float pMie = 3.0 / (8.0 * PI) * ((1.0 - gg) * (mumu + 1.0)) / (pow(1.0 + gg - 2.0 * mu * g, 1.5) * (2.0 + gg)); + + // Sample the primary ray. + for (int i = 0; i < iSteps; i++) { + // Calculate the primary ray sample position. + vec3 iPos = r0 + r * (iTimeBis + iStepSize * 0.5); + + // Calculate the height of the sample. + float iHeight = length(iPos) - rPlanet; + + // Calculate the optical depth of the Rayleigh and Mie scattering for this step. + float odStepRlh = exp(-iHeight / shRlh) * iStepSize; + float odStepMie = exp(-iHeight / shMie) * iStepSize; + + // Accumulate optical depth. + iOdRlh += odStepRlh; + iOdMie += odStepMie; + + // Calculate the step size of the secondary ray. + float jStepSize = rsi(iPos, pSun, rAtmos).y / float(jSteps); + + // Initialize the secondary ray time. + float jTime = 0.0; + + // Initialize optical depth accumulators for the secondary ray. + float jOdRlh = 0.0; + float jOdMie = 0.0; + + // Sample the secondary ray. + for (int j = 0; j < jSteps; j++) { + // Calculate the secondary ray sample position. + vec3 jPos = iPos + pSun * (jTime + jStepSize * 0.5); + + // Calculate the height of the sample. + float jHeight = length(jPos) - rPlanet; + + // Accumulate the optical depth. + jOdRlh += exp(-jHeight / shRlh) * jStepSize; + jOdMie += exp(-jHeight / shMie) * jStepSize; + + // Increment the secondary ray time. + jTime += jStepSize; + } + + // Calculate attenuation. + vec3 attn = exp(-(kMie * (iOdMie + jOdMie) + kRlh * (iOdRlh + jOdRlh))); + + // Accumulate scattering. + totalRlh += odStepRlh * attn; + totalMie += odStepMie * attn; + + // Increment the primary ray time. + iTimeBis += iStepSize; + + } + + // Calculate and return the final color. + return iSun * (pRlh * kRlh * totalRlh + pMie * kMie * totalMie); +} + +// and our application + +vec3 ray_dir_from_uv(vec2 uv) { + float PI = 3.14159265358979; + vec3 dir; + + float x = sin(PI * uv.y); + dir.y = cos(PI * uv.y); + + dir.x = x * sin(2.0 * PI * (0.5 - uv.x)); + dir.z = x * cos(2.0 * PI * (0.5 - uv.x)); + + return dir; +} + +vec2 uv_from_ray_dir(vec3 dir) { + float PI = 3.14159265358979; + vec2 uv; + + uv.y = acos(dir.y) / PI; + + dir.y = 0.0; + dir = normalize(dir); + uv.x = acos(dir.z) / (2.0 * PI); + if (dir.x < 0.0) { + uv.x = 1.0 - uv.x; + } + uv.x = 0.5 - uv.x; + if (uv.x < 0.0) { + uv.x += 1.0; + } + + return uv; +} +//////////////////////////////// + + + float noise( in vec3 x ) { x*=0.01; @@ -166,7 +331,8 @@ void mainImage( out vec4 fragColor, in vec2 fragCoord, in vec2 iResolution) panorama_uv(fragCoord,ro,rd,iResolution); - vec3 sky = render_sky_color(rd); +// vec3 sky = render_sky_color(rd); + vec3 sky = vec3( 0.0, 0.0, 0.0); vec4 cld = vec4(0.); float skyPow = dot(rd, vec3(0.0, -1.0, 0.0)); float horizonPow =1.-pow(1.0-abs(skyPow), 5.0); @@ -189,6 +355,42 @@ void mainImage( out vec4 fragColor, in vec2 fragCoord, in vec2 iResolution) } void fragment(){ + ////////////////////////////////// + vec3 dir = ray_dir_from_uv(UV); + + // determine our sky color + vec3 color = atmosphere( + vec3( dir.x, -dir.y, dir.z ) + , vec3(0.0, earth_radius_km * 100.0 + cam_height_m * 0.1, 0.0) + , sun_pos + , sun_intensity + , earth_radius_km * 100.0 + , atmo_radius_km * 100.0 + , rayleigh_coeff / 100000.0 + , mie_coeff / 100000.0 + , rayleigh_scale + , mie_scale + , mie_scatter_dir + ); + + // Apply exposure. + color = 1.0 - exp(-1.0 * color); + + // Mix in night sky (already sRGB) + if (dir.y > 0.0) { + float f = (0.21 * color.r) + (0.72 * color.g) + (0.07 * color.b); + float cutoff = 0.1; + + vec2 ns_uv = uv_from_ray_dir(rotate_night_sky * dir); + color += texture(night_sky, ns_uv).rgb * clamp((cutoff - f) / cutoff, 0.0, 1.0); + } + + COLOR = vec4(color, 1.0); + //////////////////////////////////////// + + + vec2 iResolution=1./TEXTURE_PIXEL_SIZE; mainImage(COLOR,UV*iResolution,iResolution); + COLOR = vec4(color, 1.0)+COLOR; }