include "pipelines/common.glsl" compute_shader [[ // https://media.contentapi.ea.com/content/dam/eacom/frostbite/files/s2016-pbs-frostbite-sky-clouds-new.pdf layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in; layout(std140, binding = 4) uniform Data { float u_bot; float u_top; float u_distribution_rayleigh; float u_distribution_mie; vec4 u_scatter_rayleigh; vec4 u_scatter_mie; vec4 u_absorb_mie; vec4 u_sunlight; vec4 u_resolution; }; layout (rgba32f, binding = 0) uniform writeonly image2D u_inscatter; layout (binding = 1) uniform sampler2D u_optical_depth; float getOptDepthY(vec3 position) { return saturate((length(position) - u_bot) / (u_top - u_bot)); } vec4 sampleOpticalDepth(vec3 dir, vec3 up, float height) { return texture(u_optical_depth, vec2(saturate(dot(dir, up)), height)); } void main() { const vec3 extinction_rayleigh = u_scatter_rayleigh.rgb; const vec3 extinction_mie = u_scatter_mie.rgb + vec3(4.4e-6); float zenith_angle = gl_GlobalInvocationID.y / u_resolution.y * M_PI * 0.5; vec3 eyedir = vec3(cos(zenith_angle), sin(zenith_angle), 0); vec3 campos = vec3(0, u_bot, 0) + Global.camera_world_pos.xyz; vec2 atmo_isect = raySphereIntersect(campos, eyedir, vec3(0), u_top); if (atmo_isect.y < 0) { imageStore(u_inscatter, ivec2(gl_GlobalInvocationID.xy), vec4(0)); return; } atmo_isect.x = max(0, atmo_isect.x); vec3 rayleigh = vec3(0); vec3 mie = vec3(0); vec3 p = campos;//+ atmo_isect.x * eyedir; const int STEP_COUNT = 50; float dist = atmo_isect.y - atmo_isect.x; dist = gl_GlobalInvocationID.x == uint(u_resolution.x) - 1 ? dist : min(gl_GlobalInvocationID.x / u_resolution.x * 50e3, dist); const float step_len = dist / STEP_COUNT; const vec3 step = step_len * eyedir; float height_b = getOptDepthY(campos); vec4 depth_b = sampleOpticalDepth(eyedir, vec3(0, 1, 0), height_b); const float cos_light_up = saturate(Global.light_dir.y); const float cos_eye_up = saturate(eyedir.y); for (int i = 0; i < STEP_COUNT; ++i) { float height_a = getOptDepthY(p); vec3 up = normalize(p); vec4 depth_a = sampleOpticalDepth(Global.light_dir.xyz, up, height_a); vec4 depth_c = sampleOpticalDepth(eyedir, up, height_a); vec3 total_transmittance = exp((-depth_a.x - depth_b.x + depth_c.x) * extinction_rayleigh) * exp((-depth_a.y - depth_b.y + depth_c.y) * extinction_mie); float h = min(0, u_bot - length(p)); rayleigh += step_len * exp(h / u_distribution_rayleigh) * total_transmittance; mie += step_len * exp(h / u_distribution_mie) * total_transmittance; p += step; } imageStore(u_inscatter, ivec2(gl_GlobalInvocationID.xy), vec4(rayleigh, mie.b)); } ]]