[gd_resource type="ShaderMaterial" load_steps=2 format=2] [sub_resource type="Shader" id=1] code = "shader_type spatial; // Written by GLtracy, ported to Godot by SolarLiner render_mode blend_add, depth_test_disable; // math const uniform float PI = 3.14159265359; uniform float MAX = 100000.0; uniform vec3 position = vec3(0.0); // scatter const uniform float length_scale = 1000.0; uniform float ground_radius = 128.0; uniform float atmosphere_radius = 128.05; uniform vec4 scattering_cf: hint_color = vec4(0.105707, 0.375536, 0.92076, 1.0); uniform float scattering_power = 35.92; uniform float rayleight_cf: hint_range(0.001, 1.0) = 0.07; uniform float mie_cf: hint_range(0.001, 1.0) = 0.04; uniform int scatter_passes: hint_range(0, 10) = 1; // ray intersects sphere // e = -b +/- sqrt( b^2 - c ) vec2 ray_vs_sphere( vec3 p, vec3 dir, float r ) { float b = dot( p, dir ); float c = dot( p, p ) - r * r; float d = b * b - c; if ( d < 0.0 ) { return vec2( MAX, -MAX ); } d = sqrt( d ); return vec2( -b - d, -b + d ); } // Mie // g : ( -0.75, -0.999 ) // 3 * ( 1 - g^2 ) 1 + c^2 // F = ----------------- * ------------------------------- // 8pi * ( 2 + g^2 ) ( 1 + g^2 - 2 * g * c )^(3/2) float phase_mie( float g, float c, float cc ) { float gg = g * g; float a = ( 1.0 - gg ) * ( 1.0 + cc ); float b = 1.0 + gg - 2.0 * (-g) * c; b *= sqrt( b ); b *= 2.0 + gg; return ( 3.0 / 8.0 * PI ) * a / b; } // Rayleigh // g : 0 // F = 3/16PI * ( 1 + c^2 ) float phase_ray( float cc ) { return ( 3.0 / 16.0 * PI ) * ( 1.0 + cc ); } float density( vec3 p, float ph ) { float scale_height = (atmosphere_radius - ground_radius); return exp( -max( (length( p ) - ground_radius)/scale_height, 0.0 ) / ph ); } float optic( vec3 p, vec3 q, float ph ) { vec3 s = ( q - p ) / float( scatter_passes ); vec3 v = p + s * 0.5; float sum = 0.0; for ( int i = 0; i < scatter_passes; i++ ) { sum += density( v, ph ); v += s; } sum *= length( s ); return sum; } vec3 in_scatter(vec3 o, vec3 dir, vec2 e, vec3 l) { float ph_ray = rayleight_cf; float ph_mie = mie_cf; vec3 k_ray = scattering_cf.rgb * scattering_power; //(0.105707, 0.375536, 0.92076)*35.9486 vec3 k_mie = vec3( 1. * scattering_power ); float k_mie_ex = 1.1; vec3 sum_ray = vec3( 0.0 ); vec3 sum_mie = vec3( 0.0 ); float n_ray0 = 0.0; float n_mie0 = 0.0; float len = ( e.y - e.x ) / float( scatter_passes*100 ); vec3 s = dir * len; vec3 v = o + dir * ( e.x + len * 0.5 ); for ( int i = 0; i < scatter_passes*100; i++) { float d_ray = density( v, ph_ray ) * len; float d_mie = density( v, ph_mie ) * len; n_ray0 += d_ray; n_mie0 += d_mie; v += s; /*vec2 e = ray_vs_sphere( v, l, R_INNER ); e.x = max( e.x, 0.0 ); if ( e.x < e.y ) { continue; }*/ vec2 f = ray_vs_sphere( v, l, atmosphere_radius ); vec3 u = v + l * f.y; float n_ray1 = optic( v, u, ph_ray ); float n_mie1 = optic( v, u, ph_mie ); vec3 att = exp( - ( n_ray0 + n_ray1 ) * k_ray - ( n_mie0 + n_mie1 ) * k_mie * k_mie_ex ); sum_ray += d_ray * att; sum_mie += d_mie * att; } float c = dot( dir, -l ); float cc = c * c; vec3 scatter = sum_ray * k_ray * phase_ray( cc ) + sum_mie * k_mie * phase_mie( -0.78, c, cc ); return scatter; } // ray direction vec3 ray_dir( float fov, vec2 size, vec2 pos ) { vec2 xy = pos - size * 0.5; float cot_half_fov = tan( radians( 90.0 - fov * 0.5 ) ); float z = size.y * 0.5 * cot_half_fov; return normalize( vec3( xy, -z ) ); } void vertex() { VERTEX += NORMAL * (atmosphere_radius - ground_radius)/1.; } void light() { // default ray dir vec3 dir = VIEW; // default ray origin vec3 eye = INV_CAMERA_MATRIX[3].xyz + (CAMERA_MATRIX*vec4(position, 0.0)).xyz; // sun light dir vec3 l = -LIGHT; vec2 e = ray_vs_sphere( eye, dir, atmosphere_radius ); if ( e.x > e.y ) { DIFFUSE_LIGHT = vec3(0.0); return; } vec2 f = ray_vs_sphere( eye, dir, ground_radius ); e.y = min( e.y, f.x ); vec3 I = in_scatter(eye, dir, e, l); //DIFFUSE_LIGHT = vec3( pow( I, vec3( 1.0 / 2.2 ) )); DIFFUSE_LIGHT = I*LIGHT_COLOR; }" [resource] shader = SubResource( 1 ) shader_param/PI = 3.14159 shader_param/MAX = 100000.0 shader_param/position = Vector3( 0, 0, 0 ) shader_param/length_scale = 1000.0 shader_param/ground_radius = 6.371 shader_param/atmosphere_radius = 6.471 shader_param/scattering_cf = Color( 0.14902, 0.4, 0.909804, 1 ) shader_param/scattering_power = 36.0 shader_param/rayleight_cf = 0.07 shader_param/mie_cf = 0.04 shader_param/scatter_passes = 2