# Moon
* Added a realistically lit moon influenced by the sun, resulting in different moon phases, including Earth blocking moon (new moon phase, and blood moon). * Moving camera very high on the Y axis, or changing the `Height` parameter brings the moon closer # Misc * Added support for moon and ground texture, accurate textures included. * Moving the camera on the X and Z axis (very far) changes the sky and ground texture position. * Cloud coverage now affects the brightness of the sky and sun. # Regression * Issues with cloud alpha at edges at high sun brightness, currently cutting out the sun from the clouds
377
NishitaSky.gd
@ -4,81 +4,119 @@ extends Node3D
|
||||
var sun_color := Color.BLACK
|
||||
@export var sun_enabled := true
|
||||
@export var light_color := Color.WHITE
|
||||
@export var sky_material : Material = null
|
||||
@export var sky_material: Material = null
|
||||
@export var sun_object_path: NodePath
|
||||
@export var moon_object_path: NodePath
|
||||
@export var sun_ground_Height := 1000.0
|
||||
@export var sun_saturation_scale := 100.0
|
||||
@export var sun_saturation_mult := 0.3
|
||||
@export_range(0.0000001, 1.0) var sun_desaturation_height := 0.25
|
||||
@export var sun_gradient : GradientTexture1D = null
|
||||
@export var sun_cloud_gradient : GradientTexture1D = null
|
||||
@export var sun_cloud_ambient_gradient : GradientTexture1D = null
|
||||
@export var sun_cloud_ground_gradient : GradientTexture1D = null
|
||||
@export var sun_gradient: GradientTexture1D = null
|
||||
@export var sun_cloud_gradient: GradientTexture1D = null
|
||||
@export var sun_cloud_ambient_gradient: GradientTexture1D = null
|
||||
@export var sun_cloud_ground_gradient: GradientTexture1D = null
|
||||
@export var compute_gradient_toggle := false:
|
||||
get:
|
||||
return compute_gradient_toggle
|
||||
set(value):
|
||||
if value:
|
||||
compute_gradient_toggle = false
|
||||
var cloud_height = (sky_material.get_shader_parameter("cloud_bottom")+sky_material.get_shader_parameter("cloud_top"))*0.5 + sky_material.get_shader_parameter("Height")
|
||||
var cloud_height = (
|
||||
(
|
||||
(
|
||||
get_param("cloud_bottom")
|
||||
+ get_param("cloud_top")
|
||||
)
|
||||
* 0.5
|
||||
)
|
||||
+ get_param("Height")
|
||||
)
|
||||
var sun_min_angle_mult := 1.0
|
||||
var min_sun_y := sun_min_angle_mult*sin(acos(sky_material.get_shader_parameter("earthRadius") / (sky_material.get_shader_parameter("earthRadius") + sun_ground_Height)))
|
||||
var min_cloud_sun_y := sun_min_angle_mult*sin(acos(sky_material.get_shader_parameter("earthRadius") / (sky_material.get_shader_parameter("earthRadius") + cloud_height)))
|
||||
var min_sun_y := (
|
||||
sun_min_angle_mult
|
||||
* sin( acos(
|
||||
get_param("earthRadius") / (get_param("earthRadius") + sun_ground_Height)
|
||||
)
|
||||
)
|
||||
)
|
||||
var min_cloud_sun_y := (
|
||||
sun_min_angle_mult
|
||||
* sin( acos(
|
||||
get_param("earthRadius") / (get_param("earthRadius") + cloud_height)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
sun_gradient = compute_sun_gradient(sun_ground_Height, min_sun_y)
|
||||
sun_cloud_gradient = compute_sun_gradient(min_cloud_sun_y, cloud_height)
|
||||
sun_cloud_ambient_gradient = compute_sun_gradient(min_cloud_sun_y, sky_material.get_shader_parameter("cloud_top"), true)
|
||||
sun_cloud_ground_gradient = compute_sun_gradient(min_cloud_sun_y, sky_material.get_shader_parameter("cloud_bottom"))
|
||||
sun_cloud_ambient_gradient = compute_sun_gradient(
|
||||
min_cloud_sun_y, get_param("cloud_top"), true
|
||||
)
|
||||
sun_cloud_ground_gradient = compute_sun_gradient(
|
||||
min_cloud_sun_y, get_param("cloud_bottom")
|
||||
)
|
||||
|
||||
func compute_sun_gradient(h: float, min_sun_y : float, ambient: bool = false):
|
||||
func set_param(param: String, value):
|
||||
sky_material.set_shader_parameter(param, value)
|
||||
|
||||
func get_param(param: String):
|
||||
return sky_material.get_shader_parameter(param)
|
||||
|
||||
func compute_sun_gradient(h: float, min_sun_y: float, ambient: bool = false):
|
||||
var gradient := GradientTexture1D.new()
|
||||
gradient.gradient = Gradient.new()
|
||||
var sample_count := 256
|
||||
var max_col := 0.0
|
||||
var cols : Array[Color] = []
|
||||
var poss : Array[float] = []
|
||||
var cols: Array[Color] = []
|
||||
var poss: Array[float] = []
|
||||
|
||||
var max_sky : Vector4
|
||||
var max_sky: Vector4
|
||||
if ambient:
|
||||
max_sky = sample_sky(Basis.from_euler(Vector3(PI*0.5, PI*0.5, 0.0)).z, Vector3.UP*h, Vector3.UP)
|
||||
max_sky = sample_sky(
|
||||
Basis.from_euler(Vector3(PI * 0.5, PI * 0.5, 0.0)).z, Vector3.UP * h, Vector3.UP
|
||||
)
|
||||
else:
|
||||
max_sky = sample_sky(Vector3.UP, Vector3.UP*h, Vector3.UP)
|
||||
max_sky = sample_sky(Vector3.UP, Vector3.UP * h, Vector3.UP)
|
||||
for i in range(sample_count):
|
||||
var new_i : float = i/(sample_count+1.0)
|
||||
var dir : float = lerp(-0.5*PI, 0.5*PI, new_i)
|
||||
var b_sun : Basis
|
||||
var new_i: float = i / (sample_count + 1.0)
|
||||
var dir: float = lerp(-0.5 * PI, 0.5 * PI, new_i)
|
||||
var b_sun: Basis
|
||||
|
||||
var sun_rot := Vector3(dir, 0.0, 0.0)
|
||||
sun_rot.x = min(Vector3(dir, 0.0, 0.0).x, asin(min_sun_y))
|
||||
b_sun = Basis.from_euler(sun_rot)
|
||||
|
||||
var b_sample : Basis = Basis.from_euler(Vector3(dir, 0.0, 0.0))
|
||||
var b_sample: Basis = Basis.from_euler(Vector3(dir, 0.0, 0.0))
|
||||
if ambient:
|
||||
b_sample = Basis.from_euler(Vector3(PI*0.5, PI*0.5, 0.0))
|
||||
b_sample = Basis.from_euler(Vector3(PI * 0.5, PI * 0.5, 0.0))
|
||||
|
||||
var sky : Vector4 = sample_sky(b_sample.z, Vector3.UP*h, b_sun.z)
|
||||
var col : Color = Color(sky.x, sky.y, sky.z).srgb_to_linear()
|
||||
var sky: Vector4 = sample_sky(b_sample.z, Vector3.UP * h, b_sun.z)
|
||||
var col: Color = Color(sky.x, sky.y, sky.z).srgb_to_linear()
|
||||
if not ambient:
|
||||
col = saturate(col, clamp((sun_desaturation_height-b_sun.z.y)/sun_desaturation_height, 0.0, 1.0))
|
||||
col = saturate(
|
||||
col,
|
||||
clamp((sun_desaturation_height - b_sun.z.y) / sun_desaturation_height, 0.0, 1.0)
|
||||
)
|
||||
max_col = max(max_col, col.r, col.g, col.b)
|
||||
cols.append(col)
|
||||
poss.append(new_i)
|
||||
|
||||
for i in range(sample_count):
|
||||
var new_i : float = i/(sample_count+1.0)
|
||||
var new_i: float = i / (sample_count + 1.0)
|
||||
cols[i] /= max_col
|
||||
cols[i].r *= light_color.r
|
||||
cols[i].g *= light_color.g
|
||||
cols[i].b *= light_color.b
|
||||
cols[i].a = 1.0
|
||||
if i > 0 and cols[i]==cols[i-1]:
|
||||
if i > 0 and cols[i] == cols[i - 1]:
|
||||
continue
|
||||
gradient.gradient.add_point(poss[i], cols[i])
|
||||
|
||||
gradient.gradient.remove_point(len(gradient.gradient.offsets)-1)
|
||||
gradient.gradient.remove_point(len(gradient.gradient.offsets) - 1)
|
||||
gradient.gradient.remove_point(0)
|
||||
return gradient
|
||||
|
||||
|
||||
#func rot_to_gradient(rot: float) -> float:
|
||||
# if rot > 0.5*PI:
|
||||
# return fmod(rot, 0.5*PI)/PI - 0.5
|
||||
@ -86,8 +124,10 @@ func compute_sun_gradient(h: float, min_sun_y : float, ambient: bool = false):
|
||||
# return 0.5-fmod(rot, 0.5*PI)/PI
|
||||
# return rot/PI
|
||||
|
||||
|
||||
func rot_to_gradient(rot: float) -> float:
|
||||
return (1.0-rot)*0.5
|
||||
return (1.0 - rot) * 0.5
|
||||
|
||||
|
||||
func normalized_color(col: Vector4) -> Vector4:
|
||||
if max(col.x, col.y, col.z) == 0.0:
|
||||
@ -97,89 +137,185 @@ func normalized_color(col: Vector4) -> Vector4:
|
||||
|
||||
return col
|
||||
|
||||
|
||||
func saturate(col: Color, saturation: float) -> Color:
|
||||
return Color.from_hsv(col.h,
|
||||
clamp(log(col.s*saturation*sun_saturation_scale+1.0)*sun_saturation_mult, 0.0, 1.0),
|
||||
col.v)
|
||||
return Color.from_hsv(
|
||||
col.h,
|
||||
clamp(log(col.s * saturation * sun_saturation_scale + 1.0) * sun_saturation_mult, 0.0, 1.0),
|
||||
col.v
|
||||
)
|
||||
|
||||
|
||||
func loop(val: float, val_range: float) -> float:
|
||||
if val > val_range:
|
||||
return fmod(val, val_range) - val_range
|
||||
elif val < -val_range:
|
||||
if val < -val_range:
|
||||
return fmod(val, -val_range) + val_range
|
||||
return val
|
||||
|
||||
func loop_angle(val: float) -> float:
|
||||
if val > 2*PI:
|
||||
return fmod(val, 2*PI) - 2*PI
|
||||
elif val < -2*PI:
|
||||
return -fmod(val, -2*PI) + 2*PI
|
||||
return val
|
||||
|
||||
func _process(delta):
|
||||
var cloud_height = (sky_material.get_shader_parameter("cloud_bottom")+sky_material.get_shader_parameter("cloud_top"))*0.5 + sky_material.get_shader_parameter("Height")
|
||||
var sun_dir : Vector3 = global_transform.basis.z
|
||||
var cloud_height = (
|
||||
(get_param("cloud_bottom") + get_param("cloud_top"))
|
||||
* 0.5 + get_param("Height")
|
||||
)
|
||||
var sun_dir: Vector3 = global_transform.basis.z
|
||||
var sun_min_angle_mult := 1.0
|
||||
var min_sun_y := sun_min_angle_mult*sin(acos(sky_material.get_shader_parameter("earthRadius") / (sky_material.get_shader_parameter("earthRadius") + sun_ground_Height)))
|
||||
var min_cloud_sun_y := sun_min_angle_mult*sin(acos(sky_material.get_shader_parameter("earthRadius") / (sky_material.get_shader_parameter("earthRadius") + cloud_height)))
|
||||
var min_sun_y := (
|
||||
sun_min_angle_mult
|
||||
* sin( acos(
|
||||
get_param("earthRadius") / (get_param("earthRadius") + sun_ground_Height)
|
||||
)
|
||||
)
|
||||
)
|
||||
var min_cloud_sun_y := (
|
||||
sun_min_angle_mult
|
||||
* sin( acos(
|
||||
get_param("earthRadius") / (get_param("earthRadius") + cloud_height)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
var sun_object = get_node(sun_object_path)
|
||||
|
||||
# print(loop_angle(rotation.x))
|
||||
rotation.x = loop(rotation.x, PI)
|
||||
rotation.y = loop(rotation.y, PI)
|
||||
rotation.z = loop(rotation.z,PI)
|
||||
rotation.z = loop(rotation.z, PI)
|
||||
|
||||
var moon_object = get_node(moon_object_path)
|
||||
set_param("precomputed_moon_dir", moon_object.global_transform.basis)
|
||||
set_param(
|
||||
"precomputed_sun_size", deg_to_rad(sun_object.light_angular_distance)
|
||||
)
|
||||
|
||||
|
||||
var precomputed_sun_size : float = deg_to_rad(sun_object.light_angular_distance)
|
||||
var moonRadius : float = get_param("moonRadius")
|
||||
var moonDistance : float = get_param("moonDistance")
|
||||
var earthRadius : float = get_param("earthRadius")
|
||||
var moon_dir : Vector3 = moon_object.global_transform.basis.z
|
||||
|
||||
var moon_size : float = (moonRadius /
|
||||
((moonDistance + earthRadius) * moon_dir -
|
||||
Vector3.UP * (get_viewport().get_camera_3d().global_position.y + earthRadius + get_param("Height"))).length() *
|
||||
2.0) * get_param("moon_size_mult")
|
||||
|
||||
|
||||
var sun_passthrough := 1.0
|
||||
if (moon_size > 0.0):
|
||||
var sun_atten_range := sin(precomputed_sun_size)
|
||||
var moon_atten_range := sin(deg_to_rad(moon_size)) * 0.5
|
||||
sun_passthrough = pow(clamp(1.0 - clamp(min(
|
||||
moon_object.global_transform.basis.z.dot(sun_dir),
|
||||
1.0) -
|
||||
(1.0 - moon_atten_range),
|
||||
0.0, 1.0) /
|
||||
moon_atten_range,
|
||||
0.0, 1.0),
|
||||
2.0)
|
||||
|
||||
sun_object.light_energy = sun_passthrough * lerp(1.0, 0.0, pow(clamp((get_param("cloud_coverage") - 0.25) / 0.75, 0.0, 1.0), 0.5));
|
||||
|
||||
set_param(
|
||||
"precomputed_sun_energy",
|
||||
sun_object.light_intensity_lux / get_world_3d().get_environment().background_intensity
|
||||
)
|
||||
|
||||
set_param("precomputed_background_intensity", get_world_3d().get_environment().background_intensity)
|
||||
|
||||
sun_object.rotation = rotation
|
||||
sun_object.rotation.x = max(rotation.x, PI-asin(min_sun_y)) if (rotation.x > PI*0.5) else min(rotation.x, asin(min_sun_y))
|
||||
sun_object.rotation.x = (
|
||||
max(rotation.x, PI - asin(min_sun_y))
|
||||
if (rotation.x > PI * 0.5)
|
||||
else min(rotation.x, asin(min_sun_y))
|
||||
)
|
||||
|
||||
if sun_enabled:
|
||||
sun_object.visible = sun_dir.y > -sin(deg_to_rad(sun_object.light_angular_distance)+acos(sky_material.get_shader_parameter("earthRadius") / (sky_material.get_shader_parameter("earthRadius") + sky_material.get_shader_parameter("cloud_top") * float(sky_material.get_shader_parameter("clouds")) )))
|
||||
sky_material.set_shader_parameter("precomputed_sun_visible", sun_object.visible)
|
||||
sky_material.set_shader_parameter("precomputed_sun_enabled", sun_enabled)
|
||||
sun_object.visible = (
|
||||
sun_dir.y > -sin(
|
||||
deg_to_rad(sun_object.light_angular_distance)
|
||||
+ acos(
|
||||
get_param("earthRadius")
|
||||
/ (
|
||||
get_param("earthRadius")
|
||||
+ (
|
||||
get_param("cloud_top")
|
||||
* float(get_param("clouds"))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
set_param("precomputed_sun_visible", sun_object.visible)
|
||||
set_param("precomputed_sun_enabled", sun_enabled)
|
||||
else:
|
||||
sun_object.visible = false
|
||||
sky_material.set_shader_parameter("precomputed_sun_visible", false)
|
||||
sky_material.set_shader_parameter("precomputed_sun_enabled", false)
|
||||
set_param("precomputed_sun_visible", false)
|
||||
set_param("precomputed_sun_enabled", false)
|
||||
|
||||
var gradient_pos := rot_to_gradient(sun_dir.y)
|
||||
sun_object.light_color = sun_gradient.gradient.sample(gradient_pos)
|
||||
sky_material.set_shader_parameter("precomputed_sun_dir", sun_dir)
|
||||
sky_material.set_shader_parameter("precomputed_sun_color", light_color)
|
||||
var sun_ratio := asin(deg_to_rad(sun_object.light_angular_distance)) / PI
|
||||
var sun_gradient_offset: float = -clamp(1.0 - sun_dir.y / sun_ratio, 0.0, 1.0) * sun_ratio
|
||||
sun_object.light_color = sun_gradient.gradient.sample(gradient_pos + sun_gradient_offset)
|
||||
set_param("precomputed_sun_dir", sun_dir)
|
||||
set_param("precomputed_sun_color", light_color)
|
||||
|
||||
#Precomputed cloud lighting
|
||||
if sky_material.get_shader_parameter("clouds"):
|
||||
if get_param("clouds"):
|
||||
var cloud_sun_rot := rotation
|
||||
cloud_sun_rot.x = min(rotation.x, asin(min_cloud_sun_y))
|
||||
sky_material.set_shader_parameter("precomputed_Atmosphere_sun", sun_cloud_gradient.gradient.sample(gradient_pos))
|
||||
sky_material.set_shader_parameter("precomputed_Atmosphere_ambient", sun_cloud_ambient_gradient.gradient.sample(gradient_pos))
|
||||
sky_material.set_shader_parameter("precomputed_Atmosphere_ground", sun_cloud_ground_gradient.gradient.sample(gradient_pos))
|
||||
set_param(
|
||||
"precomputed_Atmosphere_sun",
|
||||
sun_cloud_gradient.gradient.sample(gradient_pos + sun_gradient_offset)
|
||||
)
|
||||
set_param(
|
||||
"precomputed_Atmosphere_ambient",
|
||||
sun_cloud_ambient_gradient.gradient.sample(gradient_pos)
|
||||
)
|
||||
set_param(
|
||||
"precomputed_Atmosphere_ground", sun_cloud_ground_gradient.gradient.sample(gradient_pos)
|
||||
)
|
||||
|
||||
var ground_color : Vector3 = Vector3(0.1, 0.07, 0.034)
|
||||
var ground_brightness : float = 1.0
|
||||
|
||||
func solve_quadratic(origin : Vector3, dir : Vector3, Radius : float) -> Vector3:
|
||||
var ground_color: Vector3 = Vector3(0.1, 0.07, 0.034)
|
||||
var ground_brightness: float = 1.0
|
||||
|
||||
|
||||
func solve_quadratic(origin: Vector3, dir: Vector3, Radius: float) -> Vector3:
|
||||
var b := 2.0 * dir.dot(origin)
|
||||
var c := origin.dot(origin) - Radius * Radius
|
||||
var d := b*b - 4.0 * c
|
||||
var d := b * b - 4.0 * c
|
||||
var det := sqrt(d)
|
||||
return Vector3((-b + det) * 0.5, (-b - det) * 0.5, d)
|
||||
|
||||
func atmosphere(Direction: Vector3, pos: Vector3, SunDirection: Vector3, intensity: float = 1.0) -> Array[Vector3]:
|
||||
|
||||
func atmosphere(
|
||||
Direction: Vector3, pos: Vector3, SunDirection: Vector3, intensity: float = 1.0
|
||||
) -> Array[Vector3]:
|
||||
var shader_Height := 1.0
|
||||
# var intensity : float = sky_material.get_shader_parameter("intensity")
|
||||
var Re : float = sky_material.get_shader_parameter("earthRadius")
|
||||
var Ra : float = sky_material.get_shader_parameter("atmosphereRadius")
|
||||
var Hr : float = sky_material.get_shader_parameter("rayleighScaleHeight")
|
||||
var Hm : float = sky_material.get_shader_parameter("mieScaleHeight")
|
||||
var mie_eccentricity : float = sky_material.get_shader_parameter("mie_eccentricity")
|
||||
var turbidity : float = sky_material.get_shader_parameter("turbidity")
|
||||
# var intensity : float = get_param("intensity")
|
||||
var Re: float = get_param("earthRadius")
|
||||
var Ra: float = get_param("atmosphereRadius")
|
||||
var Hr: float = get_param("rayleighScaleHeight")
|
||||
var Hm: float = get_param("mieScaleHeight")
|
||||
var mie_eccentricity: float = get_param("mie_eccentricity")
|
||||
var turbidity: float = get_param("turbidity")
|
||||
|
||||
var ground := 0.0
|
||||
|
||||
var mu := Direction.dot(SunDirection)
|
||||
var phaseR := (3.0 / (16.0 * PI)) * (1.0 + mu * mu)
|
||||
var phaseM := (3.0 / (8.0 * PI)) * ((1.0 - mie_eccentricity * mie_eccentricity) * (1.0 + mu * mu) / ((2.0 + mie_eccentricity * mie_eccentricity) * pow(1.0 + mie_eccentricity * mie_eccentricity - 2.0 * mie_eccentricity * mu, 1.5)))
|
||||
var phaseM := (
|
||||
(3.0 / (8.0 * PI))
|
||||
* (
|
||||
(1.0 - mie_eccentricity * mie_eccentricity)
|
||||
* (1.0 + mu * mu)
|
||||
/ (
|
||||
(2.0 + mie_eccentricity * mie_eccentricity)
|
||||
* pow(1.0 + mie_eccentricity * mie_eccentricity - 2.0 * mie_eccentricity * mu, 1.5)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
var SumR := Vector3.ZERO
|
||||
var SumM := Vector3.ZERO
|
||||
@ -187,41 +323,48 @@ func atmosphere(Direction: Vector3, pos: Vector3, SunDirection: Vector3, intensi
|
||||
var begin := Vector3.ZERO
|
||||
var end := Vector3.ZERO
|
||||
|
||||
var cameraPos := Vector3(0,Re + sun_ground_Height + max(0.0, pos.y),0)
|
||||
var cameraPos := Vector3(0, Re + sun_ground_Height + max(0.0, pos.y), 0)
|
||||
begin = cameraPos
|
||||
|
||||
var d1 := solve_quadratic(cameraPos, Direction, Ra)
|
||||
if (d1.x > d1.y && d1.x > 0.0):
|
||||
if d1.x > d1.y && d1.x > 0.0:
|
||||
end = cameraPos + Direction * d1.x
|
||||
|
||||
if (d1.y > 0.0):
|
||||
if d1.y > 0.0:
|
||||
begin = cameraPos + Direction * d1.y
|
||||
else:
|
||||
return [Vector3.ZERO, Vector3.ONE, Vector3.ONE]
|
||||
|
||||
|
||||
var d2 = solve_quadratic(cameraPos, Direction, Re)
|
||||
if (d2.x > 0.0 && d2.y > 0.0):
|
||||
if d2.x > 0.0 && d2.y > 0.0:
|
||||
end = begin + Direction * d2.y
|
||||
ground=1.0
|
||||
ground = 1.0
|
||||
|
||||
var numSamples := 16*16
|
||||
var numSamplesL := 8*2
|
||||
var numSamples := 16 * 16
|
||||
var numSamplesL := 8 * 2
|
||||
|
||||
var segmentLength := begin.distance_to(end) / float(numSamples)
|
||||
var opticalDepthR := 0.0
|
||||
var opticalDepthM := 0.0
|
||||
var atmosphere_atten := Vector3.ZERO
|
||||
|
||||
var BetaR : Vector3 = sky_material.get_shader_parameter("rayleigh_color") * 22.4e-6 * sky_material.get_shader_parameter("rayleigh")
|
||||
var BetaM : Vector3 = sky_material.get_shader_parameter("mie_color") * 20e-6 * sky_material.get_shader_parameter("mie")
|
||||
var BetaR: Vector3 = (
|
||||
get_param("rayleigh_color")
|
||||
* 22.4e-6
|
||||
* get_param("rayleigh")
|
||||
)
|
||||
var BetaM: Vector3 = (
|
||||
get_param("mie_color")
|
||||
* 20e-6
|
||||
* get_param("mie")
|
||||
)
|
||||
|
||||
for i in range(numSamples):
|
||||
var Px := begin + Direction * segmentLength * (float(i) + 0.5)
|
||||
var sampleHeight := Px.length() - Re
|
||||
|
||||
var Hr_sample := exp(-sampleHeight/(Hr*turbidity)) * segmentLength
|
||||
var Hm_sample := exp(-sampleHeight/(Hm*turbidity)) * segmentLength
|
||||
var Hr_sample := exp(-sampleHeight / (Hr * turbidity)) * segmentLength
|
||||
var Hm_sample := exp(-sampleHeight / (Hm * turbidity)) * segmentLength
|
||||
|
||||
opticalDepthR += Hr_sample
|
||||
opticalDepthM += Hm_sample
|
||||
@ -232,26 +375,29 @@ func atmosphere(Direction: Vector3, pos: Vector3, SunDirection: Vector3, intensi
|
||||
var d3 = solve_quadratic(Px, SunDirection, Ra)
|
||||
var d4 = solve_quadratic(Px, SunDirection, Re)
|
||||
|
||||
if (d4.x > 0.0 and d4.y > 0.0):
|
||||
if d4.x > 0.0 and d4.y > 0.0:
|
||||
continue
|
||||
|
||||
var j2 := 0
|
||||
|
||||
var segmentLengthL : float = max(d3.x, d3.y) / float(numSamplesL)
|
||||
var segmentLengthL: float = max(d3.x, d3.y) / float(numSamplesL)
|
||||
|
||||
for j in range(numSamplesL):
|
||||
var Pl : Vector3 = Px + SunDirection * segmentLengthL * (j + 0.5)
|
||||
var sampleHeightL : float = Pl.length() - Re
|
||||
if (sampleHeightL < 0.0):
|
||||
var Pl: Vector3 = Px + SunDirection * segmentLengthL * (j + 0.5)
|
||||
var sampleHeightL: float = Pl.length() - Re
|
||||
if sampleHeightL < 0.0:
|
||||
break
|
||||
opticalDepthLR += exp(-sampleHeightL/(Hr*turbidity))
|
||||
opticalDepthLM += exp(-sampleHeightL/(Hm*turbidity))
|
||||
opticalDepthLR += exp(-sampleHeightL / (Hr * turbidity))
|
||||
opticalDepthLM += exp(-sampleHeightL / (Hm * turbidity))
|
||||
j2 += 1
|
||||
|
||||
if (j2 == numSamplesL):
|
||||
if j2 == numSamplesL:
|
||||
opticalDepthLR *= segmentLengthL
|
||||
opticalDepthLM *= segmentLengthL
|
||||
var tau := BetaR * (opticalDepthR + opticalDepthLR) + BetaM * 1.1 * (opticalDepthM + opticalDepthLM)
|
||||
var tau := (
|
||||
BetaR * (opticalDepthR + opticalDepthLR)
|
||||
+ BetaM * 1.1 * (opticalDepthM + opticalDepthLM)
|
||||
)
|
||||
var attenuation := v3exp(-tau)
|
||||
atmosphere_atten += tau
|
||||
|
||||
@ -259,23 +405,56 @@ func atmosphere(Direction: Vector3, pos: Vector3, SunDirection: Vector3, intensi
|
||||
SumM += Hm_sample * attenuation
|
||||
|
||||
var sky := SumR * phaseR * BetaR + SumM * phaseM * BetaM
|
||||
return [sky, atmosphere_atten*(1.0-ground), v3exp(-(opticalDepthR * BetaR + opticalDepthM * BetaM))]
|
||||
return [
|
||||
sky,
|
||||
atmosphere_atten * (1.0 - ground),
|
||||
v3exp(-(opticalDepthR * BetaR + opticalDepthM * BetaM))
|
||||
]
|
||||
|
||||
|
||||
func v3exp(input: Vector3) -> Vector3:
|
||||
return Vector3(exp(input.x), exp(input.y), exp(input.z))
|
||||
|
||||
func sample_sky(dir: Vector3, pos: Vector3, sun_dir: Vector3, LIGHT0_ENERGY: Vector3 = Vector3.ONE, LIGHT0_COLOR: Vector3 = Vector3.ONE) -> Vector4:
|
||||
|
||||
func sample_sky(
|
||||
dir: Vector3,
|
||||
pos: Vector3,
|
||||
sun_dir: Vector3,
|
||||
LIGHT0_ENERGY: Vector3 = Vector3.ONE,
|
||||
LIGHT0_COLOR: Vector3 = Vector3.ONE
|
||||
) -> Vector4:
|
||||
var sun_object = get_node(sun_object_path)
|
||||
var sky : Array[Vector3] = atmosphere(dir, pos, sun_dir)
|
||||
var skyxyz : Vector3 = sky[0]
|
||||
var sun : Vector3 = Vector3.ZERO
|
||||
var sky: Array[Vector3] = atmosphere(dir, pos, sun_dir)
|
||||
var skyxyz: Vector3 = sky[0]
|
||||
var sun: Vector3 = Vector3.ZERO
|
||||
sun = (
|
||||
(Vector3.ONE-v3exp(-sky[1])) * ( Vector3.ONE*max(max(dir.dot(sun_dir),0.0)-(cos( deg_to_rad(sun_object.light_angular_distance) )), 0.0) * sky_material.get_shader_parameter("sun_brightness")
|
||||
+ (Vector3.ONE-v3exp(-sky[2])) * ground_color * max(sun_dir.y, 0.0) * sky[2].x * ground_brightness )
|
||||
* LIGHT0_ENERGY)
|
||||
(Vector3.ONE - v3exp(-sky[1]))
|
||||
* (
|
||||
(
|
||||
Vector3.ONE
|
||||
* max(
|
||||
(
|
||||
max(dir.dot(sun_dir), 0.0)
|
||||
- (cos(deg_to_rad(sun_object.light_angular_distance)))
|
||||
),
|
||||
0.0
|
||||
)
|
||||
* get_param("sun_brightness")
|
||||
)
|
||||
+ (
|
||||
(Vector3.ONE - v3exp(-sky[2]))
|
||||
* ground_color
|
||||
* max(sun_dir.y, 0.0)
|
||||
* sky[2].x
|
||||
* ground_brightness
|
||||
)
|
||||
)
|
||||
* LIGHT0_ENERGY
|
||||
)
|
||||
|
||||
var col := skyxyz + sun
|
||||
return Vector4(col.x, col.y, col.z, 1.0)
|
||||
|
||||
|
||||
func mix(start: Vector3, end: Vector3, factor: float):
|
||||
return lerp(start, end, factor)
|
||||
|
107
README.md
@ -1,67 +1,98 @@
|
||||
# Nishita Sky With Volumetric Clouds
|
||||
|
||||
This is a Nishita sky shader for godot 4.0, with [Clay John's volumetric clouds](https://github.com/clayjohn/godot-volumetric-cloud-demo) based on [a tutorial by scratch pixel](https://www.scratchapixel.com/lessons/procedural-generation-virtual-worlds/simulating-sky/simulating-colors-of-the-sky.html), which is recommended to read to understand what the sky parameters represent, when configuring the sky.
|
||||
This is a Nishita sky shader for Godot 4.0, with [Clay John's volumetric clouds](https://github.com/clayjohn/godot-volumetric-cloud-demo) based on [a tutorial by scratch pixel](https://www.scratchapixel.com/lessons/procedural-generation-virtual-worlds/simulating-sky/simulating-colors-of-the-sky.html), which is recommended to read to understand what the sky parameters represent, when configuring the sky.
|
||||
|
||||
## Screenshots (stars amplified for demonstration purposes)
|
||||
## Screenshots
|
||||
<div style="display:flex">
|
||||
<div style="flex:1;padding-right:10px;">
|
||||
<img src="Screenshots/1%20day.webp" width="200"/>
|
||||
<p>Day</p>
|
||||
</div>
|
||||
<div style="flex:1;padding-left:10px;">
|
||||
<img src="Screenshots/2 sunset.webp" width="300"/>
|
||||
<p>Sunset</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
**Day**
|
||||
![day](Screenshots/day.png)
|
||||
<div style="display:flex">
|
||||
<div style="flex:1;padding-right:10px;">
|
||||
<img src="Screenshots/3%20cloud%20sky.webp" width="200"/>
|
||||
<p>Cloudy Sky</p>
|
||||
</div>
|
||||
<div style="flex:1;padding-left:10px;">
|
||||
<img src="Screenshots/4%20 partial%20eclipse.webp" width="300"/>
|
||||
<p>Partial Eclipse</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
**Day Without Clouds**
|
||||
![day without clouds](Screenshots/day%20without%20clouds.png)
|
||||
<div style="display:flex">
|
||||
<div style="flex:1;padding-right:10px;">
|
||||
<img src="Screenshots/5%20full%20eclipse.webp" width="200"/>
|
||||
<p>Full Eclipse</p>
|
||||
</div>
|
||||
<div style="flex:1;padding-left:10px;">
|
||||
<img src="Screenshots/6%20blood%20moon.webp" width="300"/>
|
||||
<p>Blood Moon</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
**High Quality Day**
|
||||
![high quality day](Screenshots/high%20quality%20day.png)
|
||||
<div style="display:flex">
|
||||
<div style="flex:1;padding-right:10px;">
|
||||
<img src="Screenshots/7%20night%20sky%20with%20clouds.webp" width="200"/>
|
||||
<p>Night Sky</p>
|
||||
</div>
|
||||
<div style="flex:1;padding-left:10px;">
|
||||
<img src="Screenshots/8%20night%20sky%20without%20clouds.webp" width="300"/>
|
||||
<p>Night Sky Without Clouds</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
**Sunset**
|
||||
![sunset](Screenshots/sunset.png)
|
||||
|
||||
**After Sunset**
|
||||
![after sunset](Screenshots/after%20sunset.png)
|
||||
|
||||
**Cloudy Night Sky After Sunset**
|
||||
![cloudy night sky after sunset](Screenshots/cloudy%20night%20sky%20after%20sunset.png)
|
||||
|
||||
**Cloudy Night Sky**
|
||||
![cloudy night sky](Screenshots/cloudy%20night%20sky.png)
|
||||
|
||||
**Atmosphere from 100km**
|
||||
![atmosphere from 100km](Screenshots/atmosphere%20from%20100km.png)
|
||||
|
||||
**Low Sun Atmosphere from 100km**
|
||||
![low sun atmosphere from 100km](Screenshots/low%20sun%20atmosphere%20from%20100km.png)
|
||||
|
||||
**Very Low Sun Atmosphere From 100km**
|
||||
![very low sun atmosphere from 100km](Screenshots/very%20low%20sun%20atmosphere%20from%20100km.png)
|
||||
<div style="display:flex">
|
||||
<div style="flex:1;padding-right:10px;">
|
||||
<img src="Screenshots/9%20earth%20from%20above.webp" width="200"/>
|
||||
<p>Earth From Above</p>
|
||||
</div>
|
||||
<div style="flex:1;padding-left:10px;">
|
||||
<img src="Screenshots/10%20earth%20from%20above%20sunset.webp" width="300"/>
|
||||
<p>Earth From Above Sunset</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
## Features
|
||||
* Game-ready asset (although in alpha)
|
||||
* Game-ready asset
|
||||
* Raymarched sky
|
||||
* Raymarched clouds that move with the camera
|
||||
* Different times of day by rotating the "NishitaSky" node
|
||||
* Realistic lighting at different altitudes
|
||||
* A night sky
|
||||
* A night sky, with Milky Way texture
|
||||
* A directional light that takes on the color of the sun in the shader
|
||||
* All elements interact with each other: the night sky is blocked by the clouds and attenuated by the atmosphere
|
||||
* Ability to configure quality of the shader and turn the clouds on/off
|
||||
* Moon
|
||||
* Realistically lit moon influenced by the sun, resulting in different moon phases, including Earth blocking moon (new moon phase, and blood moon)
|
||||
* Support for moon and ground textures, accurate textures included
|
||||
* Performance optimizations
|
||||
|
||||
## Bonus Features
|
||||
* Raising the camera high on the Y axis brings the moon closer
|
||||
* Moving the camera on the XZ axis (very far) changes the sky and ground texture position
|
||||
|
||||
## Limitations
|
||||
* Performance heavy, especially with clouds on
|
||||
* The camera must remain below the clouds (but is clamped to cloud height if it goes higher), since the clouds do not actully exist
|
||||
* The camera must remain below the clouds (but is clamped to cloud height if it goes higher), since the clouds do not actually exist
|
||||
|
||||
## Improvements
|
||||
* For the sky precompute the optical depth between the sun and an arbitrary point along the ray (from Nishita's paper)
|
||||
* Add multiple scattering to clouds and sky
|
||||
* Physical raytraced clouds, with better lighting (curently the clouds are evenly lit)
|
||||
* Physical raytraced clouds, with better lighting (currently the clouds are evenly lit)
|
||||
* Better cloud density textures
|
||||
* Use cloud sample distance for cloud fog (currently uses distance to clouds)
|
||||
* Physically accurate ground material (currently the brightness is just a dot product to the sun)
|
||||
* Better sun color saturation (currently some hacks are nessary to get the expected sun brightness and saturation)
|
||||
* Better sun color saturation (currently some hacks are necessary to get the expected sun brightness and saturation)
|
||||
|
||||
## How to Use
|
||||
To implement this sky into a project
|
||||
1. Copy the "NishitaSky" node from the main scene into a the project
|
||||
1. Copy the "NishitaSky" node from the main scene into the project
|
||||
2. In the "NishitaSky" node set "sun_object_path" variable to the desired directional light, do not make this directional light a child of the "NishitaSky" node
|
||||
3. Create an "WorldEnvironment" node, set the sky material to the "nishita_sky" material
|
||||
4. Click copy on the sky section of the "WorldEnvironment" node, and paste it into the "sky_material" section of the "NishitaSky" node. **THE MATERIALS MUST BE LINKED FOR THE SKY PARAMETERS TO BE THE SAME ON THE SCRIPT AND THE SHADER**
|
||||
@ -72,5 +103,13 @@ To implement this sky into a project
|
||||
|
||||
## Todo
|
||||
* Fix clouds "jumping" after some time
|
||||
* Clean up code
|
||||
* Rework sun saturation
|
||||
* Set WorldEnvironment fog color based on sky color
|
||||
* Make stars move with the sun
|
||||
* Position sun, stars, and moon using a real world date/time
|
||||
|
||||
## Images
|
||||
* Moon albedo image was rendered from [NASA](https://svs.gsfc.nasa.gov/cgi-bin/details.cgi?aid=4720)
|
||||
* Night sky HDRI was underexposed and compressed to webp from [NASA](https://svs.gsfc.nasa.gov/4851#media_group_5169)
|
||||
* Earth image was color corrected and converted to webp from [NASA](https://visibleearth.nasa.gov/images/74142/september-blue-marble-next-generation/74159l)
|
||||
|
0
Screenshots/.gdignore
Normal file
BIN
Screenshots/1 day.webp
Normal file
After Width: | Height: | Size: 125 KiB |
BIN
Screenshots/10 earth from above sunset.webp
Normal file
After Width: | Height: | Size: 135 KiB |
BIN
Screenshots/2 sunset.webp
Normal file
After Width: | Height: | Size: 268 KiB |
BIN
Screenshots/3 cloudy sky.webp
Normal file
After Width: | Height: | Size: 57 KiB |
BIN
Screenshots/4 partial eclipse.webp
Normal file
After Width: | Height: | Size: 81 KiB |
BIN
Screenshots/5 full eclipse.webp
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
Screenshots/6 blood moon.webp
Normal file
After Width: | Height: | Size: 243 KiB |
BIN
Screenshots/7 night sky with clouds.webp
Normal file
After Width: | Height: | Size: 320 KiB |
BIN
Screenshots/8 night sky without clouds.webp
Normal file
After Width: | Height: | Size: 619 KiB |
BIN
Screenshots/9 earth from above.webp
Normal file
After Width: | Height: | Size: 184 KiB |
BIN
earth albedo.webp
Normal file
After Width: | Height: | Size: 3.2 MiB |
35
earth albedo.webp.import
Normal file
@ -0,0 +1,35 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://bhpaqsnerf2bw"
|
||||
path.bptc="res://.godot/imported/earth albedo.webp-487e903020ebde7daefa19f384bb1069.bptc.ctex"
|
||||
metadata={
|
||||
"imported_formats": ["s3tc_bptc"],
|
||||
"vram_texture": true
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://earth albedo.webp"
|
||||
dest_files=["res://.godot/imported/earth albedo.webp-487e903020ebde7daefa19f384bb1069.bptc.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=2
|
||||
compress/high_quality=true
|
||||
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=true
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=0
|
@ -1,10 +1,22 @@
|
||||
extends Label
|
||||
|
||||
|
||||
func _ready():
|
||||
$"/root/Main/Camera3D".position.y = pow($"%HeightSlider".value, 4.0)-$"/root/Main/WorldEnvironment".environment.sky.sky_material.get_shader_parameter("Height")+1.0
|
||||
$"/root/Main/Camera3D".position.y = (
|
||||
pow($"%HeightSlider".value, 4.0)
|
||||
- $"/root/Main/WorldEnvironment".environment.sky.sky_material.get_shader_parameter("Height")
|
||||
+ 1.0
|
||||
)
|
||||
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
set_text("FPS: " + str(Engine.get_frames_per_second()))
|
||||
get_node("/root/Main/Moon Holder/Moon").transform.rotated(Vector3.UP, delta)
|
||||
|
||||
|
||||
func _on_height_slider_value_changed(value):
|
||||
$"/root/Main/Camera3D".position.y = pow(value, 4.0)-$"/root/Main/WorldEnvironment".environment.sky.sky_material.get_shader_parameter("Height")+1.0
|
||||
$"/root/Main/Camera3D".position.y = (
|
||||
pow(value, 4.0)
|
||||
- $"/root/Main/WorldEnvironment".environment.sky.sky_material.get_shader_parameter("Height")
|
||||
+ 1.0
|
||||
)
|
||||
|
@ -3,22 +3,23 @@
|
||||
importer="3d_texture"
|
||||
type="CompressedTexture3D"
|
||||
uid="uid://dbfbysid168mx"
|
||||
path="res://.godot/imported/perlworlnoise.tga-b9f270f21ab5670cff551f6d1621ed1d.ctex3d"
|
||||
path.bptc="res://.godot/imported/perlworlnoise.tga-c779d624a992ed3ab2c0ac1ff9dc86ba.bptc.ctex3d"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
"imported_formats": ["s3tc_bptc"],
|
||||
"vram_texture": true
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://godot-volumetric-cloud-demo-main/perlworlnoise.tga"
|
||||
dest_files=["res://.godot/imported/perlworlnoise.tga-b9f270f21ab5670cff551f6d1621ed1d.ctex3d"]
|
||||
source_file="res://godot-volumetric-cloud-demo textures/perlworlnoise.tga"
|
||||
dest_files=["res://.godot/imported/perlworlnoise.tga-c779d624a992ed3ab2c0ac1ff9dc86ba.bptc.ctex3d"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=3
|
||||
compress/mode=2
|
||||
compress/high_quality=true
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/bptc_ldr=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=true
|
||||
mipmaps/limit=-1
|
||||
|
@ -3,26 +3,25 @@
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://dfkye0uf4i6w1"
|
||||
path.s3tc="res://.godot/imported/weather.bmp-409063809cd2b4d1d20a0208167a841e.s3tc.ctex"
|
||||
path.etc2="res://.godot/imported/weather.bmp-409063809cd2b4d1d20a0208167a841e.etc2.ctex"
|
||||
path.bptc="res://.godot/imported/weather.bmp-875d1f4c165bb883d17be4b13da6595f.bptc.ctex"
|
||||
metadata={
|
||||
"imported_formats": ["s3tc", "etc2"],
|
||||
"imported_formats": ["s3tc_bptc"],
|
||||
"vram_texture": true
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://godot-volumetric-cloud-demo-main/weather.bmp"
|
||||
dest_files=["res://.godot/imported/weather.bmp-409063809cd2b4d1d20a0208167a841e.s3tc.ctex", "res://.godot/imported/weather.bmp-409063809cd2b4d1d20a0208167a841e.etc2.ctex"]
|
||||
source_file="res://godot-volumetric-cloud-demo textures/weather.bmp"
|
||||
dest_files=["res://.godot/imported/weather.bmp-875d1f4c165bb883d17be4b13da6595f.bptc.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=2
|
||||
compress/high_quality=true
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/bptc_ldr=0
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
compress/channel_pack=1
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
|
@ -3,24 +3,23 @@
|
||||
importer="3d_texture"
|
||||
type="CompressedTexture3D"
|
||||
uid="uid://c4dp6g6gouj2b"
|
||||
path.etc2="res://.godot/imported/worlnoise.bmp-1f9acdf96caf7345cd4596da56bb527c.etc2.ctex3d"
|
||||
path.s3tc="res://.godot/imported/worlnoise.bmp-1f9acdf96caf7345cd4596da56bb527c.s3tc.ctex3d"
|
||||
path.bptc="res://.godot/imported/worlnoise.bmp-07c9d5c2e8f73e8a112f07c06bc532f3.bptc.ctex3d"
|
||||
metadata={
|
||||
"imported_formats": ["etc2", "s3tc"],
|
||||
"imported_formats": ["s3tc_bptc"],
|
||||
"vram_texture": true
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://godot-volumetric-cloud-demo-main/worlnoise.bmp"
|
||||
dest_files=["res://.godot/imported/worlnoise.bmp-1f9acdf96caf7345cd4596da56bb527c.etc2.ctex3d", "res://.godot/imported/worlnoise.bmp-1f9acdf96caf7345cd4596da56bb527c.s3tc.ctex3d"]
|
||||
source_file="res://godot-volumetric-cloud-demo textures/worlnoise.bmp"
|
||||
dest_files=["res://.godot/imported/worlnoise.bmp-07c9d5c2e8f73e8a112f07c06bc532f3.bptc.ctex3d"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=2
|
||||
compress/high_quality=true
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/bptc_ldr=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=true
|
||||
mipmaps/limit=-1
|
||||
|
@ -3,25 +3,26 @@
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://c4hd3ttt8f2x8"
|
||||
path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
|
||||
path.s3tc="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.s3tc.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
"imported_formats": ["s3tc_bptc"],
|
||||
"vram_texture": true
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://icon.svg"
|
||||
dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"]
|
||||
dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.s3tc.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/mode=2
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/bptc_ldr=0
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/generate=true
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
@ -31,7 +32,7 @@ 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
|
||||
detect_3d/compress_to=0
|
||||
svg/scale=1.0
|
||||
editor/scale_with_editor_scale=false
|
||||
editor/convert_colors_with_editor_theme=false
|
||||
|
39
main.tscn
@ -37,6 +37,7 @@ sky_material = ExtResource("2_txcwo")
|
||||
|
||||
[sub_resource type="Environment" id="Environment_fb38y"]
|
||||
background_mode = 2
|
||||
background_intensity = 100000.0
|
||||
sky = SubResource("Sky_dunn8")
|
||||
tonemap_mode = 2
|
||||
tonemap_white = 16.0
|
||||
@ -51,7 +52,6 @@ glow_levels/4 = 2.0
|
||||
glow_levels/6 = 0.5
|
||||
glow_levels/7 = 0.25
|
||||
glow_normalized = true
|
||||
glow_bloom = 1.0
|
||||
glow_hdr_threshold = 0.0
|
||||
|
||||
[sub_resource type="CameraAttributesPhysical" id="CameraAttributesPhysical_5vtap"]
|
||||
@ -85,19 +85,39 @@ albedo_color = Color(0.286275, 0.701961, 0.294118, 1)
|
||||
[node name="Main" type="Node3D"]
|
||||
|
||||
[node name="NishitaSky" type="Node3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, -0.471007, 0.882119, 0, -0.882119, -0.471007, 0, 0, 0)
|
||||
transform = Transform3D(0.85681, -0.48743, 0.168147, 0.324956, 0.763631, 0.557873, -0.400348, -0.423352, 0.812679, 0, 0, 0)
|
||||
script = ExtResource("1_jf2ik")
|
||||
sky_material = ExtResource("2_txcwo")
|
||||
sun_object_path = NodePath("../DirectionalLight3D")
|
||||
sun_object_path = NodePath("../Sun")
|
||||
moon_object_path = NodePath("../Moon Holder/Moon")
|
||||
sun_gradient = SubResource("GradientTexture1D_b4qlm")
|
||||
sun_cloud_gradient = SubResource("GradientTexture1D_hfemd")
|
||||
sun_cloud_ambient_gradient = SubResource("GradientTexture1D_ihvx1")
|
||||
sun_cloud_ground_gradient = SubResource("GradientTexture1D_xb4xe")
|
||||
|
||||
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, -0.471011, 0.882126, 0, -0.882126, -0.471011, 0, 0, 0)
|
||||
light_color = Color(0.92075, 0.92075, 0.92075, 1)
|
||||
light_angular_distance = 0.53
|
||||
[node name="Press F - Space" type="Node3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1e+07, 0)
|
||||
|
||||
[node name="Press F - Space Other Side" type="Node3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1.00188e+07, 1e+07, 0)
|
||||
|
||||
[node name="Press F - Space Other Side 2" type="Node3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1e+07, 1.00188e+07)
|
||||
|
||||
[node name="Sun" type="DirectionalLight3D" parent="."]
|
||||
transform = Transform3D(0.856811, -0.487443, 0.168152, 0.324956, 0.763651, 0.557889, -0.400348, -0.423363, 0.812702, 0, 0, 0)
|
||||
light_color = Color(0.916235, 0.916235, 0.916235, 1)
|
||||
light_angular_distance = 2.35
|
||||
shadow_enabled = true
|
||||
directional_shadow_blend_splits = true
|
||||
|
||||
[node name="Moon Holder" type="Node3D" parent="."]
|
||||
transform = Transform3D(0.793073, -0.0738335, -0.604635, 0.498952, 0.648125, 0.575309, 0.349402, -0.757946, 0.55085, 0, 0, 0)
|
||||
|
||||
[node name="Moon" type="DirectionalLight3D" parent="Moon Holder"]
|
||||
visible = false
|
||||
light_intensity_lux = 1000.0
|
||||
light_color = Color(0.918936, 0.918936, 0.918936, 1)
|
||||
shadow_enabled = true
|
||||
directional_shadow_blend_splits = true
|
||||
|
||||
@ -106,6 +126,7 @@ environment = SubResource("Environment_fb38y")
|
||||
camera_attributes = SubResource("CameraAttributesPhysical_5vtap")
|
||||
|
||||
[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
|
||||
visible = false
|
||||
mesh = SubResource("PlaneMesh_7tyt4")
|
||||
surface_material_override/0 = SubResource("StandardMaterial3D_34618")
|
||||
|
||||
@ -128,10 +149,12 @@ skeleton = NodePath("../..")
|
||||
surface_material_override/0 = SubResource("StandardMaterial3D_70bv0")
|
||||
|
||||
[node name="Camera3D" type="Camera3D" parent="."]
|
||||
transform = Transform3D(0.866025, 0, -0.5, 0, 1, 0, 0.5, 0, 0.866025, 0, 0, 0)
|
||||
transform = Transform3D(-0.948323, 0.133597, 0.287809, 0, 0.907044, -0.421036, -0.317304, -0.399278, -0.860171, 0, 0, 0)
|
||||
cull_mask = 1048574
|
||||
fov = 90.0
|
||||
|
||||
[node name="Control" type="Control" parent="."]
|
||||
visible = false
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
|
BIN
moon albedo.webp
Normal file
After Width: | Height: | Size: 68 KiB |
35
moon albedo.webp.import
Normal file
@ -0,0 +1,35 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://cendachjh3ous"
|
||||
path.bptc="res://.godot/imported/moon albedo.webp-bb75edb645552e5cfb7fd5d75e51743f.bptc.ctex"
|
||||
metadata={
|
||||
"imported_formats": ["s3tc_bptc"],
|
||||
"vram_texture": true
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://moon albedo.webp"
|
||||
dest_files=["res://.godot/imported/moon albedo.webp-bb75edb645552e5cfb7fd5d75e51743f.bptc.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=2
|
||||
compress/high_quality=true
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=1
|
||||
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=true
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=0
|
@ -1,112 +1,147 @@
|
||||
shader_type sky;
|
||||
render_mode use_half_res_pass, use_quarter_res_pass;
|
||||
|
||||
//These properties are precomputed by the NishitaSky script, and cannot be modified
|
||||
// These properties are precomputed by the NishitaSky script, and cannot be modified
|
||||
uniform float precomputed_sun_visible = 1.0;
|
||||
uniform float precomputed_sun_enabled = 1.0;
|
||||
uniform mat3 precomputed_moon_dir = mat3(0.0);
|
||||
uniform vec3 precomputed_sun_dir = vec3(1.0, 0.0, 0.0);
|
||||
uniform vec3 precomputed_sun_color : source_color = vec3(1.0);
|
||||
uniform vec3 precomputed_Atmosphere_sun : source_color = vec3(0.0);
|
||||
uniform vec3 precomputed_Atmosphere_ambient : source_color = vec3(0.0);
|
||||
uniform vec3 precomputed_Atmosphere_ground : source_color = vec3(0.0);
|
||||
uniform float precomputed_sun_size
|
||||
: hint_range(0, 90.0) = 9.250245035569947e-03;
|
||||
uniform float precomputed_sun_energy = 1.0;
|
||||
uniform float precomputed_background_intensity = 1.0;
|
||||
|
||||
//Controls the scattering responsible for the blue color of a real life sky
|
||||
// Controls the scattering responsible for the blue color of a real life sky
|
||||
uniform vec3 rayleigh_color = vec3(0.258928571428571, 0.580357142857143, 1.0);
|
||||
uniform float rayleigh : hint_range(0, 64) = 1.0; // higher values absorb more rayleigh_color, more blue by default
|
||||
uniform float rayleigh
|
||||
: hint_range(0, 64) =
|
||||
1.0; // higher values absorb more rayleigh_color, more blue by default
|
||||
|
||||
//Controls the scattering responsible for the white horizon of a real life sky
|
||||
// Controls the scattering responsible for the white horizon of a real life sky
|
||||
uniform vec3 mie_color = vec3(1.0, 1.0, 1.0);
|
||||
uniform float mie : hint_range(0, 64) = 1.0; // higher values make a "foggy" atmosphere
|
||||
uniform float mie
|
||||
: hint_range(0, 64) = 1.0; // higher values make a "foggy" atmosphere
|
||||
uniform float mie_eccentricity : hint_range(-1, 0.99999) = 0.76;
|
||||
|
||||
//Sample counts for different parts of the sky
|
||||
uniform int atmosphere_samples_max = 32; //maximum allowed atmosphere samples per pixel
|
||||
uniform int atmosphere_samples_min = 12; //minimum allowed atmosphere samples per pixel
|
||||
uniform float atmosphere_samples_horizon_bias = 0.5; //lower values bias more samples towards the horizon
|
||||
uniform int atmosphere_sun_samples = 32; //extra samples around sun, does not exceed maximum
|
||||
uniform int atmosphere_light_samples = 8; //scattering samples from each direction towards the sun
|
||||
// Sample counts for different parts of the sky
|
||||
uniform int atmosphere_samples_max =
|
||||
32; // maximum allowed atmosphere samples per pixel
|
||||
uniform int atmosphere_samples_min =
|
||||
12; // minimum allowed atmosphere samples per pixel
|
||||
uniform float atmosphere_samples_horizon_bias =
|
||||
0.5; // lower values bias more samples towards the horizon
|
||||
uniform int atmosphere_sun_samples =
|
||||
32; // extra samples around sun, does not exceed maximum
|
||||
uniform int atmosphere_light_samples =
|
||||
8; // scattering samples from each direction towards the sun
|
||||
|
||||
uniform float turbidity : hint_range(0, 1000) = 1.0;
|
||||
uniform vec3 ground_color : source_color = vec3(0.1, 0.07, 0.034);
|
||||
|
||||
//Brightness controls
|
||||
uniform float intensity = 10.0; //Intensity of sky. Does not affect clouds
|
||||
uniform float sun_brightness = 100000.0; //brightness of only the solar disk
|
||||
uniform float ground_brightness = 0.5;
|
||||
uniform float night_sky_brightness = 0.001;
|
||||
// Brightness controls
|
||||
uniform float intensity = 10.0; // Intensity of sky. Does not affect clouds
|
||||
uniform float sun_brightness = 10000.0; // brightness of only the solar disk
|
||||
uniform float ground_brightness = 1.0;
|
||||
uniform float night_sky_brightness = 1000.0;
|
||||
|
||||
//Night sky texture
|
||||
// Night sky texture
|
||||
uniform sampler2D night_sky : source_color, hint_default_black;
|
||||
|
||||
//Height of viewer above the atmosphere, in addition to the camera's y position. Does not affect cloud height
|
||||
uniform sampler2D ground_texture : source_color, hint_default_white;
|
||||
uniform vec3 ground_rotation = vec3(0.0);
|
||||
|
||||
uniform vec3 moon_eclipse_color : source_color = vec3(1.0, 0.1, 0.0);
|
||||
uniform float moon_size_mult = 1.0;
|
||||
uniform sampler2D moon_texture : source_color, hint_default_black;
|
||||
|
||||
// Height of viewer above the atmosphere, in addition to the camera's y
|
||||
// position. Does not affect cloud height
|
||||
uniform float Height = 1000.0;
|
||||
|
||||
uniform float earthRadius = 6360e3;
|
||||
uniform float moonRadius = 1738e3;
|
||||
uniform float moonDistance = 384400e3;
|
||||
uniform float atmosphereRadius = 6420e3;
|
||||
uniform float rayleighScaleHeight = 7994.0; // Scale height for Rayleigh scattering
|
||||
uniform float rayleighScaleHeight =
|
||||
7994.0; // Scale height for Rayleigh scattering
|
||||
uniform float mieScaleHeight = 1200.0; // Scale height for Mie scattering
|
||||
|
||||
const float BetaRScale = 22.4e-6;
|
||||
const float BetaMScale = 20e-6;
|
||||
//const vec3 BetaR = vec3(5.8e-6,13.0e-6,22.4e-6);
|
||||
//const vec3 BetaM = vec3(20e-6);
|
||||
// const vec3 BetaR = vec3(5.8e-6,13.0e-6,22.4e-6);
|
||||
// const vec3 BetaM = vec3(20e-6);
|
||||
|
||||
//dir is normalized
|
||||
vec3 solve_quadratic(vec3 origin, vec3 dir, float Radius){
|
||||
// dir is normalized
|
||||
vec3 solve_quadratic(vec3 origin, vec3 dir, float Radius) {
|
||||
float b = 2.0 * dot(dir, origin);
|
||||
float c = dot(origin, origin) - Radius * Radius;
|
||||
float d = b*b - 4.0 * c;
|
||||
float d = b * b - 4.0 * c;
|
||||
float dsqrt = sqrt(d);
|
||||
float x1 = (-b + dsqrt) * 0.5;
|
||||
float x2 = (-b - dsqrt) * 0.5;
|
||||
return vec3(x1, x2, d);
|
||||
}
|
||||
|
||||
vec3[4] atmosphere(vec3 dir, vec3 pos){
|
||||
vec3[5] atmosphere(vec3 dir, vec3 pos) {
|
||||
vec3 SunDirection = precomputed_sun_dir;
|
||||
vec3 begin = vec3(0.0);
|
||||
vec3 start = vec3(0.0);
|
||||
vec3 end = vec3(0.0);
|
||||
|
||||
vec3 cameraPos = vec3(0,earthRadius + Height + max(0.0, pos.y),0);
|
||||
begin = cameraPos;
|
||||
vec3 cameraPos = vec3(0, earthRadius + Height + max(0.0, pos.y), 0);
|
||||
start = cameraPos;
|
||||
|
||||
vec3 d1 = solve_quadratic(cameraPos, dir, atmosphereRadius);
|
||||
// Find atmosphere end point, exit if no intersection
|
||||
if (d1.x > d1.y && d1.x > 0.0){
|
||||
if (d1.x > d1.y && d1.x > 0.0) {
|
||||
end = cameraPos + dir * d1.x;
|
||||
|
||||
// If the ray starts outside the atmosphere, set the origin to the edge of the atmosphere
|
||||
if (d1.y > 0.0){
|
||||
begin = cameraPos + dir * d1.y;
|
||||
// If the ray starts outside the atmosphere, set the origin to the edge
|
||||
// of the atmosphere
|
||||
if (d1.y > 0.0) {
|
||||
start = cameraPos + dir * d1.y;
|
||||
}
|
||||
} else {
|
||||
return {vec3(0.0), vec3(1.0), vec3(0.0), vec3(1.0) };
|
||||
return {vec3(0.0), vec3(1.0), vec3(0.0), vec3(1.0), end};
|
||||
}
|
||||
|
||||
float ground = 0.0;
|
||||
// Check if ray intersects with ground, and set the end point to the ground if it intersects
|
||||
// Check if ray intersects with ground, and set the end point to the ground
|
||||
// if it intersects
|
||||
vec3 d2 = solve_quadratic(cameraPos, dir, earthRadius);
|
||||
if (d2.x > 0.0 && d2.y > 0.0){
|
||||
end = cameraPos + dir * d2.y; ground=1.0; // enable ground
|
||||
// end = cameraPos + dir * d1.y; // optionally disable ground, buggy at high altitudes and low sample counts, set a higher height instead.
|
||||
// return {vec3(0.0), vec3(1.0), vec3(1.0), vec3(1.0) }; // optionally disable atmosphere lighting, must set ground brightness to 0 as well.
|
||||
if (d2.x > 0.0 && d2.y > 0.0) {
|
||||
end = cameraPos + dir * d2.y;
|
||||
ground = 1.0; // enable ground
|
||||
//end = cameraPos + dir * d1.y; // optionally disable ground, buggy at high altitudes and low sample counts, set a higher height instead.
|
||||
//return {vec3(0.0), vec3(1.0), vec3(1.0), vec3(1.0), end}; // optionally disable atmosphere lighting, must set ground brightness to 0 as well.
|
||||
}
|
||||
|
||||
vec3 SumR = vec3(0.0);
|
||||
vec3 SumM = vec3(0.0);
|
||||
float mu = dot(dir, SunDirection);
|
||||
float phaseR = (3.0 / (16.0 * PI)) * (1.0 + mu * mu);
|
||||
float phaseM = (3.0 / (8.0 * PI)) * ((1.0 - mie_eccentricity*mie_eccentricity) * (1.0 + mu * mu) / ((2.0 + mie_eccentricity * mie_eccentricity) * pow(1.0 + mie_eccentricity * mie_eccentricity - 2.0 * mie_eccentricity * mu, 1.5)));
|
||||
float phaseM =
|
||||
(3.0 / (8.0 * PI)) *
|
||||
((1.0 - mie_eccentricity * mie_eccentricity) * (1.0 + mu * mu) /
|
||||
((2.0 + mie_eccentricity * mie_eccentricity) *
|
||||
pow(1.0 + mie_eccentricity * mie_eccentricity -
|
||||
2.0 * mie_eccentricity * mu,
|
||||
1.5)));
|
||||
|
||||
float segmentLength = distance (begin, end);
|
||||
float segmentLength = distance(start, end);
|
||||
float horizon = sin(acos(earthRadius / (earthRadius + Height)));
|
||||
|
||||
// Bias atmosphere samples towards sun and horizon
|
||||
float weighted_atmosphere_samples = ceil(clamp(
|
||||
(max(clamp(1.0 - pow(abs(dir.y + horizon), atmosphere_samples_horizon_bias), 0.0, 1.0)
|
||||
* float(atmosphere_samples_max)
|
||||
, pow(max(mu, 0.0), 3.0) * float(atmosphere_sun_samples))
|
||||
), float(atmosphere_samples_min), float(atmosphere_samples_max)));
|
||||
float weighted_atmosphere_samples = ceil(
|
||||
clamp((max(clamp(1.0 - pow(abs(dir.y + horizon),
|
||||
atmosphere_samples_horizon_bias),
|
||||
0.0, 1.0) *
|
||||
float(atmosphere_samples_max),
|
||||
pow(max(mu, 0.0), 3.0) * float(atmosphere_sun_samples))),
|
||||
float(atmosphere_samples_min), float(atmosphere_samples_max)));
|
||||
|
||||
segmentLength /= weighted_atmosphere_samples;
|
||||
|
||||
@ -117,18 +152,20 @@ vec3[4] atmosphere(vec3 dir, vec3 pos){
|
||||
vec3 BetaR = rayleigh_color * BetaRScale * rayleigh;
|
||||
vec3 BetaM = mie_color * BetaMScale * mie;
|
||||
|
||||
|
||||
for (float i = 0.5; i < weighted_atmosphere_samples + 0.5; i++) {
|
||||
vec3 Px = begin + dir * segmentLength * i;
|
||||
vec3 Px = start + dir * segmentLength * i;
|
||||
float sampleHeight = length(Px) - earthRadius;
|
||||
|
||||
float Hr_sample = exp(-sampleHeight / (rayleighScaleHeight * turbidity)) * segmentLength;
|
||||
float Hm_sample = exp(-sampleHeight / (mieScaleHeight * turbidity)) * segmentLength;
|
||||
float Hr_sample =
|
||||
exp(-sampleHeight / (rayleighScaleHeight * turbidity)) *
|
||||
segmentLength;
|
||||
float Hm_sample =
|
||||
exp(-sampleHeight / (mieScaleHeight * turbidity)) * segmentLength;
|
||||
|
||||
opticalDepthR += Hr_sample;
|
||||
opticalDepthM += Hm_sample;
|
||||
|
||||
if (precomputed_sun_enabled<0.5)
|
||||
if (precomputed_sun_enabled < 0.5)
|
||||
continue;
|
||||
|
||||
float opticalDepthLR = 0.0;
|
||||
@ -137,29 +174,36 @@ vec3[4] atmosphere(vec3 dir, vec3 pos){
|
||||
vec3 d3 = solve_quadratic(Px, SunDirection, atmosphereRadius);
|
||||
vec3 d4 = solve_quadratic(Px, SunDirection, earthRadius);
|
||||
|
||||
// Ignore sample if sun is below horizon, used for performance boost at night time. Also fixes spots at edges at high altitudes
|
||||
// Ignore sample if sun is below horizon, used for performance boost at
|
||||
// night time. Also fixes spots at edges at high altitudes
|
||||
if ((d4.x > 0.0 && d4.y > 0.0) || d3.z < 0.0)
|
||||
continue;
|
||||
|
||||
float segmentLengthL = max(d3.x, d3.y) / float(atmosphere_light_samples);
|
||||
float segmentLengthL =
|
||||
max(d3.x, d3.y) / float(atmosphere_light_samples);
|
||||
|
||||
int j2 = 0;
|
||||
for (float j = 0.5; j < float(atmosphere_light_samples) + 0.5; j++) {
|
||||
float sampleHeightL = length(Px + SunDirection * segmentLengthL * j) - earthRadius;
|
||||
float sampleHeightL =
|
||||
length(Px + SunDirection * segmentLengthL * j) - earthRadius;
|
||||
|
||||
// Ignore light samples inside planet, used for performance boost at night time
|
||||
// Ignore light samples inside planet, used for performance boost at
|
||||
// night time
|
||||
if (sampleHeightL < 0.0)
|
||||
break;
|
||||
opticalDepthLR += exp(-sampleHeightL/(rayleighScaleHeight*turbidity));
|
||||
opticalDepthLM += exp(-sampleHeightL/(mieScaleHeight*turbidity));
|
||||
opticalDepthLR +=
|
||||
exp(-sampleHeightL / (rayleighScaleHeight * turbidity));
|
||||
opticalDepthLM +=
|
||||
exp(-sampleHeightL / (mieScaleHeight * turbidity));
|
||||
j2++;
|
||||
}
|
||||
|
||||
// Attenuation
|
||||
if (j2 == atmosphere_light_samples){
|
||||
if (j2 == atmosphere_light_samples) {
|
||||
opticalDepthLR *= segmentLengthL;
|
||||
opticalDepthLM *= segmentLengthL;
|
||||
vec3 tau = BetaR * (opticalDepthR + opticalDepthLR) + BetaM * 1.1 * (opticalDepthM + opticalDepthLM);
|
||||
vec3 tau = BetaR * (opticalDepthR + opticalDepthLR) +
|
||||
BetaM * 1.1 * (opticalDepthM + opticalDepthLM);
|
||||
vec3 attenuation = exp(-tau);
|
||||
|
||||
atmosphere_atten += attenuation;
|
||||
@ -169,26 +213,90 @@ vec3[4] atmosphere(vec3 dir, vec3 pos){
|
||||
}
|
||||
|
||||
vec3 Sky = SumR * phaseR * BetaR + SumM * phaseM * BetaM;
|
||||
return {Sky, atmosphere_atten, vec3(ground), exp(-(opticalDepthR * BetaR + opticalDepthM * BetaM)) };
|
||||
return {Sky, atmosphere_atten, vec3(ground),
|
||||
exp(-(opticalDepthR * BetaR + opticalDepthM * BetaM)), end};
|
||||
}
|
||||
|
||||
vec4[2] sample_sky(vec3 dir, vec3 pos){
|
||||
vec3[4] sky = atmosphere(dir, pos);
|
||||
vec3 sun = vec3(0.0);
|
||||
sun =
|
||||
vec3 rotate(vec3 point, vec3 axis, float angle) {
|
||||
float s = sin(angle);
|
||||
float c = cos(angle);
|
||||
float oc = 1.0 - c;
|
||||
|
||||
vec3 rotatedPoint;
|
||||
rotatedPoint.x = point.x * (oc * axis.x * axis.x + c) +
|
||||
point.y * (oc * axis.x * axis.y - axis.z * s) +
|
||||
point.z * (oc * axis.x * axis.z + axis.y * s);
|
||||
rotatedPoint.y = point.x * (oc * axis.x * axis.y + axis.z * s) +
|
||||
point.y * (oc * axis.y * axis.y + c) +
|
||||
point.z * (oc * axis.y * axis.z - axis.x * s);
|
||||
rotatedPoint.z = point.x * (oc * axis.x * axis.z - axis.y * s) +
|
||||
point.y * (oc * axis.y * axis.z + axis.x * s) +
|
||||
point.z * (oc * axis.z * axis.z + c);
|
||||
|
||||
return rotatedPoint;
|
||||
}
|
||||
|
||||
vec2 sphereToUV(vec3 point, vec3 rot) {
|
||||
point = rotate(rotate(point, vec3(1.0, 0.0, 0.0), rot.x),
|
||||
vec3(0.0, 1.0, 0.0), rot.y);
|
||||
float theta = atan(point.x, point.y);
|
||||
float phi = acos(-point.z / length(point));
|
||||
|
||||
vec2 uv = vec2((theta - (rot.z - 1.0)) * 0.5, // Rotate U
|
||||
phi) /
|
||||
PI;
|
||||
|
||||
return uv;
|
||||
}
|
||||
|
||||
vec3 uvToSphere(vec2 uv) {
|
||||
float theta = (1.0 - uv.x) * PI;
|
||||
float phi = uv.y * TAU;
|
||||
return vec3(sin(theta) * cos(phi), sin(theta) * sin(phi), cos(theta));
|
||||
}
|
||||
|
||||
vec3 map_sphere_normal(vec3 x, vec3 y, vec3 z, vec2 point) {
|
||||
return x * point.x + y * point.y +
|
||||
z * sqrt(1.0 - point.x * point.x - point.y * point.y);
|
||||
}
|
||||
|
||||
vec4[4] sample_sky(vec3 dir, vec3 pos, float visiblity) {
|
||||
vec3[5] sky = atmosphere(dir, pos);
|
||||
|
||||
vec3 d2 =
|
||||
solve_quadratic(vec3(0, earthRadius + Height + max(0.0, POSITION.y), 0),
|
||||
dir, earthRadius);
|
||||
vec3 end = sky[4] / earthRadius * 2.0;
|
||||
vec2 uv =
|
||||
sphereToUV(rotate(rotate(end, vec3(0.0, 0.0, 1.0),
|
||||
pos.x * PI / (earthRadius + pos.y + Height)),
|
||||
vec3(1.0, 0.0, 0.0),
|
||||
pos.z * PI / (earthRadius + pos.y + Height)),
|
||||
ground_rotation * 0.5);
|
||||
|
||||
// Sun, with sun-specific attenuation
|
||||
( (vec3(1.0)-exp(-sky[1])) * max(max(dot(dir, precomputed_sun_dir), 0.0) - (cos(LIGHT0_SIZE * 0.5)), 0.0) * sun_brightness * (1.0 - sky[2].r) +
|
||||
vec3 sun = (vec3(1.0) - exp(-sky[1])) *
|
||||
max(max(dot(dir, precomputed_sun_dir), 0.0) -
|
||||
(cos(precomputed_sun_size)),
|
||||
0.0) *
|
||||
sun_brightness * (1.0 - sky[2].r) * visiblity * precomputed_sun_energy;
|
||||
|
||||
// ground, with generic attenuation
|
||||
(vec3(1.0)-exp(-sky[3])) * ground_color * max(precomputed_sun_dir.y, 0.0) * sky[2].r * ground_brightness ) * LIGHT0_ENERGY ;
|
||||
vec3 col = (sun + sky[0].xyz);
|
||||
return {vec4(col * precomputed_sun_color, sky[2].r), vec4(sky[3] * (1.0 - sky[2].r), 1.0)};
|
||||
vec3 ground = (vec3(1.0) - exp(-sky[3])) * ground_color *
|
||||
texture(ground_texture, uv).xyz * sky[2].r *
|
||||
ground_brightness;
|
||||
ground *= clamp(dot(end, precomputed_sun_dir), 0.0, 1.0);
|
||||
vec3 col = (ground + sky[0].xyz) * precomputed_sun_energy;
|
||||
return {vec4(col * precomputed_sun_color, sky[2].r),
|
||||
vec4(sky[3] * (1.0 - sky[2].r), 1.0), vec4(sun, 1.0),
|
||||
vec4(end, 0.0)};
|
||||
}
|
||||
|
||||
|
||||
/* Begin Cloud Parameters */
|
||||
|
||||
// Cloud Raymarching based on: A. Schneider. “The earthRadiusal-Time Volumetric Cloudscapes Of Horizon: Zero Dawn”. ACM SIGGRAPH. Los Angeles, CA: ACM SIGGRAPH, 2015. Web. 26 Aug. 2015.
|
||||
// Cloud Raymarching based on: A. Schneider. “The earthRadiusal-Time Volumetric
|
||||
// Cloudscapes Of Horizon: Zero Dawn”. ACM SIGGRAPH. Los Angeles, CA: ACM
|
||||
// SIGGRAPH, 2015. Web. 26 Aug. 2015.
|
||||
|
||||
uniform sampler3D worlnoise : filter_linear_mipmap, repeat_enable;
|
||||
uniform sampler3D perlworlnoise : filter_linear_mipmap, repeat_enable;
|
||||
@ -204,19 +312,22 @@ uniform float _time_offset = 0.0;
|
||||
|
||||
uniform float cloud_bottom = 1500.0;
|
||||
uniform float cloud_top = 4000.0;
|
||||
uniform float cloud_brightness = 1.5;
|
||||
uniform float cloud_brightness = 1.0;
|
||||
uniform float cloud_ambient_brightness = 0.5;
|
||||
|
||||
// From: https://www.shadertoy.com/view/4sfGzS credit to iq
|
||||
float hash(vec3 p) {
|
||||
p = fract( p * 0.3183099 + 0.1 );
|
||||
p = fract(p * 0.3183099 + 0.1);
|
||||
p *= 17.0;
|
||||
return fract(p.x * p.y * p.z * (p.x + p.y + p.z));
|
||||
}
|
||||
|
||||
// Utility function that maps a value from one range to another.
|
||||
float remap(float originalValue, float originalMin, float originalMax, float newMin, float newMax) {
|
||||
return newMin + (((originalValue - originalMin) / (originalMax - originalMin)) * (newMax - newMin));
|
||||
float remap(float originalValue, float originalMin, float originalMax,
|
||||
float newMin, float newMax) {
|
||||
return newMin +
|
||||
(((originalValue - originalMin) / (originalMax - originalMin)) *
|
||||
(newMax - newMin));
|
||||
}
|
||||
|
||||
// Phase function
|
||||
@ -225,25 +336,27 @@ float henyey_greenstein(float cos_theta, float G) {
|
||||
return k * (1.0 - G * G) / (pow(1.0 + G * G - 2.0 * G * cos_theta, 1.5));
|
||||
}
|
||||
|
||||
|
||||
float GetHeightFractionForPoint(float inPosition) {
|
||||
float height_fraction = (inPosition - cloud_bottom - earthRadius) / (cloud_top - cloud_bottom);
|
||||
float height_fraction =
|
||||
(inPosition - cloud_bottom - earthRadius) / (cloud_top - cloud_bottom);
|
||||
return clamp(height_fraction, 0.0, 1.0);
|
||||
}
|
||||
|
||||
vec4 mixGradients(float cloudType){
|
||||
vec4 mixGradients(float cloudType) {
|
||||
const vec4 STRATUS_GRADIENT = vec4(0.02f, 0.05f, 0.09f, 0.11f);
|
||||
const vec4 STRATOCUMULUS_GRADIENT = vec4(0.02f, 0.2f, 0.48f, 0.625f);
|
||||
const vec4 CUMULUS_GRADIENT = vec4(0.01f, 0.0625f, 0.78f, 1.0f);
|
||||
float stratus = 1.0f - clamp(cloudType * 2.0f, 0.0, 1.0);
|
||||
float stratocumulus = 1.0f - abs(cloudType - 0.5f) * 2.0f;
|
||||
float cumulus = clamp(cloudType - 0.5f, 0.0, 1.0) * 2.0f;
|
||||
return STRATUS_GRADIENT * stratus + STRATOCUMULUS_GRADIENT * stratocumulus + CUMULUS_GRADIENT * cumulus;
|
||||
return STRATUS_GRADIENT * stratus + STRATOCUMULUS_GRADIENT * stratocumulus +
|
||||
CUMULUS_GRADIENT * cumulus;
|
||||
}
|
||||
|
||||
float densityHeightGradient(float heightFrac, float cloudType) {
|
||||
vec4 cloudGradient = mixGradients(cloudType);
|
||||
return smoothstep(cloudGradient.x, cloudGradient.y, heightFrac) - smoothstep(cloudGradient.z, cloudGradient.w, heightFrac);
|
||||
return smoothstep(cloudGradient.x, cloudGradient.y, heightFrac) -
|
||||
smoothstep(cloudGradient.z, cloudGradient.w, heightFrac);
|
||||
}
|
||||
|
||||
// Returns density at a given point
|
||||
@ -253,28 +366,36 @@ float density(vec3 pip, vec3 weather, float mip) {
|
||||
vec3 p = pip;
|
||||
p.x += time * 1.0 * _time_scale + _time_offset;
|
||||
float height_fraction = GetHeightFractionForPoint(length(p));
|
||||
vec4 n = textureLod(perlworlnoise, p.xyz*0.00008, mip-2.0);
|
||||
float fbm = n.g*0.625+n.b*0.25+n.a*0.125;
|
||||
vec4 n = textureLod(perlworlnoise, p.xyz * 0.00008, mip - 2.0);
|
||||
float fbm = n.g * 0.625 + n.b * 0.25 + n.a * 0.125;
|
||||
float G = densityHeightGradient(height_fraction, weather.r);
|
||||
float base_cloud = remap(n.r, -(1.0-fbm), 1.0, 0.0, 1.0);
|
||||
float weather_coverage = cloud_coverage*weather.b;
|
||||
base_cloud = remap(base_cloud*G, 1.0-(weather_coverage), 1.0, 0.0, 1.0);
|
||||
float base_cloud = remap(n.r, -(1.0 - fbm), 1.0, 0.0, 1.0);
|
||||
float weather_coverage = cloud_coverage * weather.b;
|
||||
base_cloud = remap(base_cloud * G, 1.0 - (weather_coverage), 1.0, 0.0, 1.0);
|
||||
base_cloud *= weather_coverage;
|
||||
p.xy -= time * 4.0 * _time_scale + _time_offset;
|
||||
vec3 hn = textureLod(worlnoise, p*0.001, mip).rgb;
|
||||
float hfbm = hn.r*0.625+hn.g*0.25+hn.b*0.125;
|
||||
hfbm = mix(hfbm, 1.0-hfbm, clamp(height_fraction*4.0, 0.0, 1.0));
|
||||
base_cloud = remap(base_cloud, hfbm*0.4 * height_fraction, 1.0, 0.0, 1.0);
|
||||
return pow(clamp(base_cloud, 0.0, 1.0), (1.0 - height_fraction) * 0.8 + 0.5);
|
||||
vec3 hn = textureLod(worlnoise, p * 0.001, mip).rgb;
|
||||
float hfbm = hn.r * 0.625 + hn.g * 0.25 + hn.b * 0.125;
|
||||
hfbm = mix(hfbm, 1.0 - hfbm, clamp(height_fraction * 4.0, 0.0, 1.0));
|
||||
base_cloud = remap(base_cloud, hfbm * 0.4 * height_fraction, 1.0, 0.0, 1.0);
|
||||
return pow(clamp(base_cloud, 0.0, 1.0),
|
||||
(1.0 - height_fraction) * 0.8 + 0.5);
|
||||
}
|
||||
|
||||
vec4 march(vec3 pos, vec3 end, vec3 dir, int depth, float sun_visible, float true_density) {
|
||||
const vec3 RANDOM_VECTORS[6] = {vec3( 0.38051305f, 0.92453449f, -0.02111345f),vec3(-0.50625799f, -0.03590792f, -0.86163418f),vec3(-0.32509218f, -0.94557439f, 0.01428793f),vec3( 0.09026238f, -0.27376545f, 0.95755165f),vec3( 0.28128598f, 0.42443639f, -0.86065785f),vec3(-0.16852403f, 0.14748697f, 0.97460106f)};
|
||||
vec4 march(vec3 pos, vec3 end, vec3 dir, int depth, float sun_visible,
|
||||
float true_density) {
|
||||
const vec3 RANDOM_VECTORS[6] = {
|
||||
vec3(0.38051305f, 0.92453449f, -0.02111345f),
|
||||
vec3(-0.50625799f, -0.03590792f, -0.86163418f),
|
||||
vec3(-0.32509218f, -0.94557439f, 0.01428793f),
|
||||
vec3(0.09026238f, -0.27376545f, 0.95755165f),
|
||||
vec3(0.28128598f, 0.42443639f, -0.86065785f),
|
||||
vec3(-0.16852403f, 0.14748697f, 0.97460106f)};
|
||||
float T = 1.0;
|
||||
float alpha = 0.0;
|
||||
vec3 ldir = precomputed_sun_dir;
|
||||
float ss = length(dir);
|
||||
dir = dir/ss;
|
||||
dir = dir / ss;
|
||||
vec3 p = pos + hash(pos * 10.0) * ss;
|
||||
float t_dist = cloud_top - cloud_bottom;
|
||||
float lss = (t_dist / 36.0);
|
||||
@ -282,31 +403,40 @@ vec4 march(vec3 pos, vec3 end, vec3 dir, int depth, float sun_visible, float tru
|
||||
float t = 1.0;
|
||||
float costheta = dot(ldir, dir);
|
||||
// Stack multiple phase functions to emulate some backscattering
|
||||
float phase = max(max(henyey_greenstein(costheta, 0.6), henyey_greenstein(costheta, (0.4 - 1.4 * ldir.y))), henyey_greenstein(costheta, -0.2));
|
||||
vec3 atmosphere_sun = precomputed_Atmosphere_sun * ss * cloud_brightness * LIGHT0_ENERGY * phase;
|
||||
vec3 atmosphere_ambient = precomputed_Atmosphere_ambient * cloud_ambient_brightness * intensity;
|
||||
vec3 atmosphere_ground = precomputed_Atmosphere_ground*ground_color.xyz*ground_brightness * LIGHT0_ENERGY * intensity;
|
||||
float phase = max(max(henyey_greenstein(costheta, 0.6),
|
||||
henyey_greenstein(costheta, (0.4 - 1.4 * ldir.y))),
|
||||
henyey_greenstein(costheta, -0.2));
|
||||
vec3 atmosphere_sun = precomputed_Atmosphere_sun * ss * cloud_brightness *
|
||||
precomputed_sun_energy * phase;
|
||||
vec3 atmosphere_ambient =
|
||||
precomputed_Atmosphere_ambient * cloud_ambient_brightness * intensity;
|
||||
vec3 atmosphere_ground = precomputed_Atmosphere_ground * ground_color.xyz *
|
||||
ground_brightness * precomputed_sun_energy *
|
||||
intensity;
|
||||
|
||||
const float weather_scale = 0.00006;
|
||||
float time = mod(TIME, 100.0) * 0.0003 * _time_scale + 0.005*_time_offset;
|
||||
float time = mod(TIME, 10000.0) * 0.0003 * _time_scale + 0.005 * _time_offset;
|
||||
vec2 weather_pos = vec2(time * 0.9, time);
|
||||
|
||||
for (int i = 0; i < depth; i++) {
|
||||
p += dir * ss;
|
||||
vec3 weather_sample = texture(weathermap, p.xz * weather_scale + 0.5 + weather_pos).xyz;
|
||||
vec3 weather_sample =
|
||||
texture(weathermap, p.xz * weather_scale + 0.5 + weather_pos).xyz;
|
||||
float height_fraction = GetHeightFractionForPoint(length(p));
|
||||
|
||||
t = density(p, weather_sample, 0.0);
|
||||
float dt = exp(-true_density*t*ss);
|
||||
float dt = exp(-true_density * t * ss);
|
||||
T *= dt;
|
||||
vec3 lp = p;
|
||||
float lt = 1.0;
|
||||
float cd = 0.0;
|
||||
|
||||
if (t > 0.0) { //calculate lighting, but only when we are in the cloud
|
||||
if (t > 0.0) { // calculate lighting, but only when we are in the cloud
|
||||
for (float j = 0.0; j < 6.0 * sun_visible; j++) {
|
||||
lp += (ldir + RANDOM_VECTORS[int(j)]*j)*lss;
|
||||
vec3 lweather = texture(weathermap, lp.xz * weather_scale + 0.5 + weather_pos).xyz;
|
||||
lp += (ldir + RANDOM_VECTORS[int(j)] * j) * lss;
|
||||
vec3 lweather = texture(weathermap, lp.xz * weather_scale +
|
||||
0.5 + weather_pos)
|
||||
.xyz;
|
||||
lt = density(lp, lweather, j);
|
||||
cd += lt;
|
||||
}
|
||||
@ -314,8 +444,10 @@ vec4 march(vec3 pos, vec3 end, vec3 dir, int depth, float sun_visible, float tru
|
||||
// Take a single distant sample
|
||||
lp = p + ldir * 18.0 * lss;
|
||||
float lheight_fraction = GetHeightFractionForPoint(length(lp));
|
||||
vec3 lweather = texture(weathermap, lp.xz * weather_scale + 0.5).xyz;
|
||||
lt = pow(density(lp, lweather, 5.0), (1.0 - lheight_fraction) * 0.8 + 0.5);
|
||||
vec3 lweather =
|
||||
texture(weathermap, lp.xz * weather_scale + 0.5).xyz;
|
||||
lt = pow(density(lp, lweather, 5.0),
|
||||
(1.0 - lheight_fraction) * 0.8 + 0.5);
|
||||
cd += lt;
|
||||
|
||||
// captures the direct lighting from the sun
|
||||
@ -323,70 +455,219 @@ vec4 march(vec3 pos, vec3 end, vec3 dir, int depth, float sun_visible, float tru
|
||||
float beers2 = exp(-true_density * cd * lss * 0.25) * 0.7;
|
||||
float beers_total = max(beers, beers2);
|
||||
|
||||
vec3 ambient = mix(atmosphere_ground, atmosphere_ambient, smoothstep(0.0, 1.0, height_fraction)) * beers;
|
||||
// vec3 ambient = mix(atmosphere_ground, vec3(1.0), smoothstep(0.0, 1.0, height_fraction)) * true_density * mix(atmosphere_ambient, vec3(1.0), 0.4); // * (ldir .y);
|
||||
vec3 ambient = mix(atmosphere_ground, atmosphere_ambient,
|
||||
smoothstep(0.0, 1.0, height_fraction)) *
|
||||
beers;
|
||||
// vec3 ambient = mix(atmosphere_ground, vec3(1.0),
|
||||
//smoothstep(0.0, 1.0, height_fraction)) * true_density *
|
||||
//mix(atmosphere_ambient, vec3(1.0), 0.4); // * (ldir .y);
|
||||
alpha += (1.0 - dt) * (1.0 - alpha);
|
||||
L += ((ambient + beers_total * atmosphere_sun) * alpha) * T * t;
|
||||
}
|
||||
}
|
||||
return vec4(L*cloud_brightness, clamp(alpha, 0.0, 1.0));
|
||||
return vec4(L * cloud_brightness, clamp(alpha, 0.0, 1.0));
|
||||
}
|
||||
|
||||
/* End Cloud Parameters */
|
||||
|
||||
|
||||
void sky() {
|
||||
vec3 dir = EYEDIR;
|
||||
|
||||
// float sun_visible = precomputed_sun_visible * max(sign(precomputed_sun_dir.y + sin(acos(earthRadius / (earthRadius + cloud_top)) + LIGHT0_SIZE)), 0.0);
|
||||
float sun_visible =
|
||||
precomputed_sun_visible *
|
||||
max(sign(precomputed_sun_dir.y +
|
||||
sin(acos(earthRadius / (earthRadius + cloud_top)) +
|
||||
precomputed_sun_size)),
|
||||
0.0);
|
||||
vec4 cloud_col = vec4(0.0);
|
||||
float cloud_fade_stars = 1.0;
|
||||
float cloud_fade = 1.0;
|
||||
bool AT_FULL_RES_PASS = !(AT_HALF_RES_PASS || AT_QUARTER_RES_PASS);
|
||||
float horizon =
|
||||
sin(acos(earthRadius / (earthRadius + max(POSITION.y, 0.0) + Height)));
|
||||
float horizon_dist = dir.y + horizon;
|
||||
|
||||
if (clouds){
|
||||
|
||||
/* Begin Clouds */
|
||||
float horizon = sin(acos(earthRadius / (earthRadius + max(POSITION.y, 0.0) + Height)));
|
||||
|
||||
if ((AT_CUBEMAP_PASS && AT_QUARTER_RES_PASS) || (!AT_CUBEMAP_PASS && AT_HALF_RES_PASS)){
|
||||
float true_density = pow(1.0-clamp((POSITION.y-cloud_bottom)/(cloud_top-cloud_bottom), 0.0, 1.0),2.0)*_density;
|
||||
if (clouds) {
|
||||
/* start Clouds */
|
||||
// if (POSITION.y < cloud_top){
|
||||
if ((AT_CUBEMAP_PASS && AT_QUARTER_RES_PASS) ||
|
||||
(!AT_CUBEMAP_PASS && AT_HALF_RES_PASS)) {
|
||||
float true_density =
|
||||
_density * pow(1.0 - clamp((POSITION.y - cloud_bottom) /
|
||||
(cloud_top - cloud_bottom),
|
||||
0.0, 1.0),
|
||||
2.0);
|
||||
vec4 volume = vec4(0.0);
|
||||
|
||||
if (dir.y>-horizon && true_density>0.0){
|
||||
vec3 camPos = vec3(POSITION.x, min(POSITION.y, cloud_bottom) + earthRadius, POSITION.z);
|
||||
float cloud_start_distance = solve_quadratic(camPos, dir, cloud_bottom + earthRadius).x;
|
||||
float cloud_end_distance = solve_quadratic(camPos, dir, cloud_top + earthRadius).x;
|
||||
if (horizon_dist > 0.0 && true_density > 0.0) {
|
||||
vec3 camPos =
|
||||
vec3(POSITION.x, min(POSITION.y, cloud_bottom) + earthRadius, POSITION.z);
|
||||
vec3 d1 = solve_quadratic(camPos, dir, cloud_top + earthRadius);
|
||||
vec3 d2 =
|
||||
solve_quadratic(camPos, dir, cloud_bottom + earthRadius);
|
||||
float cloud_start_distance = d2.x;
|
||||
float cloud_end_distance = d1.x;
|
||||
vec3 start = camPos + dir * cloud_start_distance;
|
||||
vec3 end = camPos + dir * cloud_end_distance;
|
||||
float shelldist = (cloud_end_distance-cloud_start_distance);
|
||||
|
||||
/*// Find atmosphere end point, exit if no intersection
|
||||
if (d1.x > d1.y && d1.x > 0.0){
|
||||
end = camPos + dir * d1.x;
|
||||
|
||||
// If the ray starts outside the atmosphere, set the origin
|
||||
to the edge of the atmosphere if (d1.y > 0.0){ start = camPos +
|
||||
dir * d1.y;
|
||||
}
|
||||
}*/
|
||||
|
||||
// Take more steps towards horizon, less steps in foggy clouds, and less steps at night
|
||||
float steps = ceil(mix(float(cloud_samples_horizon) * (1.0 - 0.25 * (1.0 - precomputed_sun_visible * (1.0-cloud_coverage))),
|
||||
float(cloud_samples_sky) * (1.0 - 0.25 * (1.0 - precomputed_sun_visible)),
|
||||
sqrt(clamp(dir.y+horizon, 0.0, 1.0))) );
|
||||
float shelldist = (cloud_end_distance - cloud_start_distance);
|
||||
|
||||
// Take more steps towards horizon, less steps in foggy clouds,
|
||||
// and less steps at night
|
||||
float steps = ceil(mix(
|
||||
float(cloud_samples_horizon) *
|
||||
(1.0 -
|
||||
0.25 * (1.0 - sun_visible * (1.0 - cloud_coverage))),
|
||||
float(cloud_samples_sky) *
|
||||
(1.0 - 0.25 * (1.0 - sun_visible)),
|
||||
sqrt(clamp(dir.y + horizon, 0.0, 1.0))));
|
||||
vec3 raystep = dir * shelldist / steps;
|
||||
volume = march(start, end, raystep, int(steps), precomputed_sun_visible, true_density )*vec4(precomputed_sun_color, 1.0);
|
||||
volume.xyz *= precomputed_sun_visible;
|
||||
volume = march(start, end, raystep, int(steps),
|
||||
precomputed_sun_visible, true_density);
|
||||
volume.xyz *= precomputed_sun_visible * precomputed_sun_color;
|
||||
}
|
||||
COLOR = volume.xyz;
|
||||
ALPHA = volume.w;
|
||||
} else if (AT_FULL_RES_PASS){
|
||||
ALPHA = clamp(volume.w, 0.0, 1.0);
|
||||
} else if (AT_FULL_RES_PASS) {
|
||||
cloud_fade = clamp(dir.y, 0.0, 1.0);
|
||||
cloud_fade_stars = clamp(dir.y+horizon, 0.0, 1.0);
|
||||
cloud_fade_stars = clamp(horizon_dist, 0.0, 1.0);
|
||||
cloud_col = AT_CUBEMAP_PASS ? QUARTER_RES_COLOR : HALF_RES_COLOR;
|
||||
}
|
||||
// }
|
||||
/* End Clouds */
|
||||
|
||||
}
|
||||
|
||||
if (AT_FULL_RES_PASS){
|
||||
vec4[2] background = sample_sky(dir, POSITION);
|
||||
vec3 col_stars = texture(night_sky, SKY_COORDS ).xyz * night_sky_brightness * background[1].xyz;
|
||||
vec3 col = background[0].xyz * intensity * precomputed_sun_enabled;
|
||||
float moon_size =
|
||||
(moonRadius /
|
||||
length((moonDistance + earthRadius) * precomputed_moon_dir[2] -
|
||||
vec3(0.0, POSITION.y + earthRadius + Height, 0.0)) *
|
||||
2.0) *
|
||||
moon_size_mult;
|
||||
|
||||
COLOR = col*(1.0-cloud_col.a*cloud_fade_stars) + cloud_col.xyz*cloud_fade + col_stars * (1.0-cloud_col.a)*cloud_fade_stars;
|
||||
float sun_visibility = 1.0 - clamp((dot(EYEDIR, precomputed_moon_dir[2]) -
|
||||
sqrt(1.0 - 0.25 * (moon_size / 45.0))) *
|
||||
100000.0,
|
||||
0.0, 1.0);
|
||||
|
||||
if (AT_FULL_RES_PASS) {
|
||||
vec4[4] background = sample_sky(dir, POSITION, sun_visibility);
|
||||
vec4 col_moon = vec4(vec3(0.0), 0.0);
|
||||
vec2 moon_cord = vec2(dot(EYEDIR, precomputed_moon_dir[1]),
|
||||
dot(EYEDIR, precomputed_moon_dir[0])) /
|
||||
sqrt(moon_size / 45.0);
|
||||
|
||||
vec3 moon_to_sun = precomputed_sun_dir;
|
||||
if (dot(EYEDIR, precomputed_moon_dir[2]) >
|
||||
sqrt(1.0 - 0.25 * (moon_size / 45.0))) {
|
||||
vec3 moon_normal = normalize(map_sphere_normal(
|
||||
precomputed_moon_dir[1], precomputed_moon_dir[0],
|
||||
-precomputed_moon_dir[2] * 0.5, moon_cord * 2.0));
|
||||
float earth_shadow_sharpness = 200.0;
|
||||
col_moon = texture(moon_texture, vec2(0.5) - moon_cord.yx);
|
||||
float moon_dist_earth_ratio =
|
||||
1.0 - atan(earthRadius / (moonDistance + earthRadius)) / TAU;
|
||||
float moon_eclipse = (clamp((moon_dist_earth_ratio -
|
||||
max(dot(-normalize(
|
||||
precomputed_moon_dir[2] *
|
||||
(earthRadius + moonDistance) +
|
||||
vec3(0.0, POSITION.y + earthRadius + Height,
|
||||
0.0)),
|
||||
normalize(precomputed_sun_dir)),
|
||||
0.0)) /
|
||||
moon_dist_earth_ratio * earth_shadow_sharpness,
|
||||
0.0, 1.0));
|
||||
|
||||
col_moon.xyz *= precomputed_background_intensity *
|
||||
precomputed_sun_energy *
|
||||
(clamp(dot(moon_normal, moon_to_sun), 0.0, 1.0)) * moon_eclipse * mix(moon_eclipse_color, vec3(1.0), moon_eclipse)
|
||||
;
|
||||
}
|
||||
vec3 col_stars =
|
||||
(texture(night_sky,
|
||||
sphereToUV(EYEDIR,
|
||||
vec3(PI * 0.5 + POSITION.z * PI /
|
||||
(earthRadius + POSITION.y +
|
||||
Height),
|
||||
-POSITION.x * PI /
|
||||
(earthRadius + POSITION.y + Height),
|
||||
-PI * 0.5) +
|
||||
ground_rotation * 0.5))
|
||||
.xyz *
|
||||
night_sky_brightness * (1.0 - col_moon.w) +
|
||||
col_moon.xyz * col_moon.w) *
|
||||
background[1].xyz / precomputed_background_intensity;
|
||||
|
||||
cloud_col.a = clamp(cloud_col.a*precomputed_background_intensity/sun_brightness, 0.0, 1.0);
|
||||
float cloud_passthrough = (1.0 - cloud_col.a) * cloud_fade_stars;
|
||||
|
||||
// Eclipse needs reworking
|
||||
float sun_passthrough = 1.0;
|
||||
if (moon_size > 0.0) {
|
||||
float sun_atten_range = sin(precomputed_sun_size);
|
||||
float moon_atten_range = sin(radians(moon_size)) * 0.5;
|
||||
sun_passthrough =
|
||||
pow(clamp(1.0 - clamp(min(dot(precomputed_moon_dir[2],
|
||||
precomputed_sun_dir),
|
||||
1.0) -
|
||||
(1.0 - moon_atten_range),
|
||||
0.0, 1.0) /
|
||||
moon_atten_range,
|
||||
0.0, 1.0),
|
||||
2.0);
|
||||
// sun_passthrough =
|
||||
// sqrt(mix(clamp(sin(precomputed_sun_size)-sin(radians(moon_size)),
|
||||
// 0.0, 1.0), 1.0, sun_passthrough));
|
||||
}
|
||||
// Eclipse needs reworking
|
||||
|
||||
// float moon_tint_ratio
|
||||
//= 1.0-atan(moonRadius/(moonDistance+earthRadius))/TAU; sun_passthrough
|
||||
//= 1.0-clamp((dot(normalize(normalize(map_sphere_normal(vec3(1.0, 0.0,
|
||||
//0.0), vec3(0.0, 0.0, 1.0), vec3(0.0, 1.0, 0.0)*0.5,
|
||||
//background[3].xz*0.5)))
|
||||
// *earthRadius+precomputed_moon_dir[2]*(moonDistance+earthRadius),
|
||||
//precomputed_sun_dir)-moon_tint_ratio)/(1.0-moon_tint_ratio)*10.0,0.0,1.0);
|
||||
// COLOR = vec3(clamp(
|
||||
// clamp(dot(normalize(normalize(
|
||||
// map_sphere_normal(vec3(1.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0),
|
||||
//vec3(0.0, 0.0, 1.0)*0.5, background[3].xz*2.0))*earthRadius
|
||||
// -precomputed_moon_dir[2]*(moonDistance+earthRadius)),
|
||||
// precomputed_sun_dir)+moon_tint_ratio, 0.0, 1.0)*100000.0
|
||||
// , 0.0, 1.0));
|
||||
// COLOR = vec3(clamp(dot(normalize(normalize(
|
||||
// -map_sphere_normal(vec3(1.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0),
|
||||
//vec3(0.0, 0.0, 1.0), background[3].xz*0.5))*earthRadius
|
||||
// +precomputed_moon_dir[2]*(moonDistance+earthRadius)),
|
||||
// -precomputed_sun_dir)+moon_tint_ratio,
|
||||
//0.0, 1.0)/(1.0-moon_tint_ratio));
|
||||
|
||||
vec3 sky_col = background[0].xyz * intensity *
|
||||
(max(precomputed_sun_dir.y,
|
||||
clamp((POSITION.y + Height) /
|
||||
(atmosphereRadius - earthRadius),
|
||||
0.0, 1.0))) *
|
||||
precomputed_sun_enabled * sun_passthrough;
|
||||
sky_col =
|
||||
mix(sky_col,
|
||||
vec3(sky_col.x + sky_col.y + sky_col.z) * 0.0033333333,
|
||||
pow(clamp((cloud_coverage - 0.25) / 0.75, 0.0, 1.0), 0.5));
|
||||
cloud_col.xyz *= sun_passthrough;
|
||||
vec3 sun_col = background[2].xyz * intensity * precomputed_sun_enabled;
|
||||
// clamp(vec3(0.3)-clamp(cloud_col.www*cloud_fade_stars, 0.0, 1.0),
|
||||
// 0.0, 1.0)
|
||||
COLOR = sky_col
|
||||
+ sun_col * (1.0 - cloud_col.w)
|
||||
+ cloud_col.xyz * cloud_fade_stars * mix(cloud_fade_stars, 1.0, clamp(precomputed_sun_dir.y, 0.0, 1.0))
|
||||
+ col_stars * (1.0 - cloud_col.w);
|
||||
}
|
||||
}
|
||||
|
@ -1,33 +1,25 @@
|
||||
[gd_resource type="ShaderMaterial" load_steps=8 format=3 uid="uid://b45abiagp8tuf"]
|
||||
[gd_resource type="ShaderMaterial" load_steps=7 format=3 uid="uid://b45abiagp8tuf"]
|
||||
|
||||
[ext_resource type="Shader" path="res://nishita_sky.gdshader" id="1_3qhyv"]
|
||||
[ext_resource type="CompressedTexture3D" uid="uid://dbfbysid168mx" path="res://godot-volumetric-cloud-demo textures/perlworlnoise.tga" id="1_qd3aw"]
|
||||
[ext_resource type="Texture2D" uid="uid://dfkye0uf4i6w1" path="res://godot-volumetric-cloud-demo textures/weather.bmp" id="2_bohio"]
|
||||
[ext_resource type="CompressedTexture3D" uid="uid://c4dp6g6gouj2b" path="res://godot-volumetric-cloud-demo textures/worlnoise.bmp" id="3_5fbd6"]
|
||||
|
||||
[sub_resource type="Gradient" id="Gradient_gllyc"]
|
||||
interpolation_mode = 2
|
||||
offsets = PackedFloat32Array(0.693133, 1)
|
||||
|
||||
[sub_resource type="FastNoiseLite" id="FastNoiseLite_d5sdi"]
|
||||
seed = 309
|
||||
frequency = 1.0
|
||||
|
||||
[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_q4x3w"]
|
||||
width = 2048
|
||||
height = 2048
|
||||
color_ramp = SubResource("Gradient_gllyc")
|
||||
noise = SubResource("FastNoiseLite_d5sdi")
|
||||
[ext_resource type="Texture2D" uid="uid://bhpaqsnerf2bw" path="res://earth albedo.webp" id="2_8dcp8"]
|
||||
[ext_resource type="Texture2D" uid="uid://cendachjh3ous" path="res://moon albedo.webp" id="3_2bh7o"]
|
||||
[ext_resource type="CompressedTexture3D" uid="uid://dbfbysid168mx" path="res://godot-volumetric-cloud-demo textures/perlworlnoise.tga" id="5_q6lkc"]
|
||||
[ext_resource type="Texture2D" uid="uid://dfkye0uf4i6w1" path="res://godot-volumetric-cloud-demo textures/weather.bmp" id="6_gs20s"]
|
||||
[ext_resource type="CompressedTexture3D" uid="uid://c4dp6g6gouj2b" path="res://godot-volumetric-cloud-demo textures/worlnoise.bmp" id="7_wkoma"]
|
||||
|
||||
[resource]
|
||||
shader = ExtResource("1_3qhyv")
|
||||
shader_parameter/precomputed_sun_visible = true
|
||||
shader_parameter/precomputed_sun_enabled = true
|
||||
shader_parameter/precomputed_sun_dir = Vector3(0, 0.0132469, -0.999903)
|
||||
shader_parameter/precomputed_sun_visible = 1.0
|
||||
shader_parameter/precomputed_sun_enabled = 1.0
|
||||
shader_parameter/precomputed_moon_dir = Basis(0.793073, -0.0738336, -0.604635, 0.498952, 0.648125, 0.575309, 0.349402, -0.757946, 0.55085)
|
||||
shader_parameter/precomputed_sun_dir = Vector3(0.168147, 0.557873, 0.812679)
|
||||
shader_parameter/precomputed_sun_color = Color(1, 1, 1, 1)
|
||||
shader_parameter/precomputed_Atmosphere_sun = Color(0.994039, 0.390172, 0.20851, 1)
|
||||
shader_parameter/precomputed_Atmosphere_ambient = Color(0.0282629, 0.0132965, 0.00359788, 1)
|
||||
shader_parameter/precomputed_Atmosphere_ground = Color(0.994039, 0.390172, 0.20851, 1)
|
||||
shader_parameter/precomputed_Atmosphere_sun = Color(0.891427, 0.891427, 0.891427, 1)
|
||||
shader_parameter/precomputed_Atmosphere_ambient = Color(0.262109, 0.50014, 0.759034, 1)
|
||||
shader_parameter/precomputed_Atmosphere_ground = Color(0.891427, 0.891427, 0.891427, 1)
|
||||
shader_parameter/precomputed_sun_size = 0.0410152
|
||||
shader_parameter/precomputed_sun_energy = 1.0
|
||||
shader_parameter/precomputed_background_intensity = 100000.0
|
||||
shader_parameter/rayleigh_color = Vector3(0.258929, 0.580357, 1)
|
||||
shader_parameter/rayleigh = 1.0
|
||||
shader_parameter/mie_color = Vector3(1, 1, 1)
|
||||
@ -39,13 +31,18 @@ shader_parameter/atmosphere_samples_horizon_bias = 0.5
|
||||
shader_parameter/atmosphere_sun_samples = 32
|
||||
shader_parameter/atmosphere_light_samples = 8
|
||||
shader_parameter/turbidity = 1.0
|
||||
shader_parameter/ground_color = Color(0.1, 0.07, 0.034, 1)
|
||||
shader_parameter/ground_color = Color(1, 1, 1, 1)
|
||||
shader_parameter/intensity = 10.0
|
||||
shader_parameter/sun_brightness = 100000.0
|
||||
shader_parameter/ground_brightness = 0.5
|
||||
shader_parameter/night_sky_brightness = 1.0
|
||||
shader_parameter/sun_brightness = 10000.0
|
||||
shader_parameter/ground_brightness = 1.0
|
||||
shader_parameter/night_sky_brightness = 100000.0
|
||||
shader_parameter/ground_rotation = Vector3(-0.79, 0, -5.015)
|
||||
shader_parameter/moon_eclipse_color = Color(1, 0.1, 0, 1)
|
||||
shader_parameter/moon_size_mult = 30.0
|
||||
shader_parameter/Height = 1000.0
|
||||
shader_parameter/earthRadius = 6.36e+06
|
||||
shader_parameter/moonRadius = 1.738e+06
|
||||
shader_parameter/moonDistance = 3.844e+08
|
||||
shader_parameter/atmosphereRadius = 6.42e+06
|
||||
shader_parameter/rayleighScaleHeight = 7994.0
|
||||
shader_parameter/mieScaleHeight = 1200.0
|
||||
@ -58,9 +55,10 @@ shader_parameter/_time_scale = 1.0
|
||||
shader_parameter/_time_offset = 0.0
|
||||
shader_parameter/cloud_bottom = 1500.0
|
||||
shader_parameter/cloud_top = 4000.0
|
||||
shader_parameter/cloud_brightness = 1.5
|
||||
shader_parameter/cloud_brightness = 1.0
|
||||
shader_parameter/cloud_ambient_brightness = 0.5
|
||||
shader_parameter/night_sky = SubResource("NoiseTexture2D_q4x3w")
|
||||
shader_parameter/worlnoise = ExtResource("3_5fbd6")
|
||||
shader_parameter/perlworlnoise = ExtResource("1_qd3aw")
|
||||
shader_parameter/weathermap = ExtResource("2_bohio")
|
||||
shader_parameter/ground_texture = ExtResource("2_8dcp8")
|
||||
shader_parameter/moon_texture = ExtResource("3_2bh7o")
|
||||
shader_parameter/worlnoise = ExtResource("7_wkoma")
|
||||
shader_parameter/perlworlnoise = ExtResource("5_q6lkc")
|
||||
shader_parameter/weathermap = ExtResource("6_gs20s")
|
||||
|
@ -12,7 +12,7 @@ config_version=5
|
||||
|
||||
config/name="Nishita Sky With Clouds"
|
||||
run/main_scene="res://main.tscn"
|
||||
config/features=PackedStringArray("4.0", "Forward Plus")
|
||||
config/features=PackedStringArray("4.1", "Forward Plus")
|
||||
config/icon="res://icon.svg"
|
||||
|
||||
[rendering]
|
||||
|
BIN
star map.webp
Normal file
After Width: | Height: | Size: 7.9 MiB |
35
star map.webp.import
Normal file
@ -0,0 +1,35 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://byt2ctyhq5myd"
|
||||
path.bptc="res://.godot/imported/star map.webp-6e0d858a55618062a5b78c84685f41f7.bptc.ctex"
|
||||
metadata={
|
||||
"imported_formats": ["s3tc_bptc"],
|
||||
"vram_texture": true
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://star map.webp"
|
||||
dest_files=["res://.godot/imported/star map.webp-6e0d858a55618062a5b78c84685f41f7.bptc.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=2
|
||||
compress/high_quality=true
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=1
|
||||
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=true
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=0
|