UNPKG

@takram/three-atmosphere

Version:
539 lines (506 loc) 18.2 kB
"use strict";const n=`// Based on the following work and adapted to Three.js. // This file includes runtime functions only. Please refer to Bruneton's source // code for the whole picture. It has detailed comments. // https://github.com/ebruneton/precomputed_atmospheric_scattering/blob/master/atmosphere/functions.glsl /** * Copyright (c) 2017 Eric Bruneton * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Precomputed Atmospheric Scattering * Copyright (c) 2008 INRIA * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ float ClampCosine(float mu) { return clamp(mu, float(-1.0), float(1.0)); } float ClampDistance(float d) { return max(d, 0.0); } float ClampRadius(float r) { return clamp(r, u_bottom_radius, u_top_radius); } float SafeSqrt(float a) { return sqrt(max(a, 0.0)); } float DistanceToTopAtmosphereBoundary(float r, float mu) { float discriminant = r * r * (mu * mu - 1.0) + u_top_radius * u_top_radius; return ClampDistance(-r * mu + SafeSqrt(discriminant)); } bool RayIntersectsGround(float r, float mu) { return mu < 0.0 && r * r * (mu * mu - 1.0) + u_bottom_radius * u_bottom_radius >= 0.0; } float GetTextureCoordFromUnitRange(float x, int texture_size) { return 0.5 / float(texture_size) + x * (1.0 - 1.0 / float(texture_size)); } vec2 GetTransmittanceTextureUvFromRMu(float r, float mu) { float H = sqrt(u_top_radius * u_top_radius - u_bottom_radius * u_bottom_radius); float rho = SafeSqrt(r * r - u_bottom_radius * u_bottom_radius); float d = DistanceToTopAtmosphereBoundary(r, mu); float d_min = u_top_radius - r; float d_max = rho + H; float x_mu = (d - d_min) / (d_max - d_min); float x_r = rho / H; return vec2( GetTextureCoordFromUnitRange(x_mu, TRANSMITTANCE_TEXTURE_WIDTH), GetTextureCoordFromUnitRange(x_r, TRANSMITTANCE_TEXTURE_HEIGHT) ); } vec3 GetTransmittanceToTopAtmosphereBoundary( const sampler2D u_transmittance_texture, float r, float mu ) { vec2 uv = GetTransmittanceTextureUvFromRMu(r, mu); return vec3(texture(u_transmittance_texture, uv)); } vec3 GetTransmittance( const sampler2D u_transmittance_texture, float r, float mu, float d, bool ray_r_mu_intersects_ground ) { float r_d = ClampRadius(sqrt(d * d + 2.0 * r * mu * d + r * r)); float mu_d = ClampCosine((r * mu + d) / r_d); if (ray_r_mu_intersects_ground) { return min( GetTransmittanceToTopAtmosphereBoundary(u_transmittance_texture, r_d, -mu_d) / GetTransmittanceToTopAtmosphereBoundary(u_transmittance_texture, r, -mu), vec3(1.0) ); } else { return min( GetTransmittanceToTopAtmosphereBoundary(u_transmittance_texture, r, mu) / GetTransmittanceToTopAtmosphereBoundary(u_transmittance_texture, r_d, mu_d), vec3(1.0) ); } } vec3 GetTransmittanceToSun(const sampler2D u_transmittance_texture, float r, float mu_s) { float sin_theta_h = u_bottom_radius / r; float cos_theta_h = -sqrt(max(1.0 - sin_theta_h * sin_theta_h, 0.0)); return GetTransmittanceToTopAtmosphereBoundary(u_transmittance_texture, r, mu_s) * smoothstep( -sin_theta_h * u_sun_angular_radius, sin_theta_h * u_sun_angular_radius, mu_s - cos_theta_h ); } float RayleighPhaseFunction(float nu) { float k = 3.0 / (16.0 * PI); return k * (1.0 + nu * nu); } float MiePhaseFunction(float g, float nu) { float k = 3.0 / (8.0 * PI) * (1.0 - g * g) / (2.0 + g * g); return k * (1.0 + nu * nu) / pow(1.0 + g * g - 2.0 * g * nu, 1.5); } vec4 GetScatteringTextureUvwzFromRMuMuSNu( float r, float mu, float mu_s, float nu, bool ray_r_mu_intersects_ground ) { float H = sqrt(u_top_radius * u_top_radius - u_bottom_radius * u_bottom_radius); float rho = SafeSqrt(r * r - u_bottom_radius * u_bottom_radius); float u_r = GetTextureCoordFromUnitRange(rho / H, SCATTERING_TEXTURE_R_SIZE); float r_mu = r * mu; float discriminant = r_mu * r_mu - r * r + u_bottom_radius * u_bottom_radius; float u_mu; if (ray_r_mu_intersects_ground) { float d = -r_mu - SafeSqrt(discriminant); float d_min = r - u_bottom_radius; float d_max = rho; u_mu = 0.5 - 0.5 * GetTextureCoordFromUnitRange( d_max == d_min ? 0.0 : (d - d_min) / (d_max - d_min), SCATTERING_TEXTURE_MU_SIZE / 2 ); } else { float d = -r_mu + SafeSqrt(discriminant + H * H); float d_min = u_top_radius - r; float d_max = rho + H; u_mu = 0.5 + 0.5 * GetTextureCoordFromUnitRange((d - d_min) / (d_max - d_min), SCATTERING_TEXTURE_MU_SIZE / 2); } float d = DistanceToTopAtmosphereBoundary(u_bottom_radius, mu_s); float d_min = u_top_radius - u_bottom_radius; float d_max = H; float a = (d - d_min) / (d_max - d_min); float D = DistanceToTopAtmosphereBoundary(u_bottom_radius, u_mu_s_min); float A = (D - d_min) / (d_max - d_min); float u_mu_s = GetTextureCoordFromUnitRange( max(1.0 - a / A, 0.0) / (1.0 + a), SCATTERING_TEXTURE_MU_S_SIZE ); float u_nu = (nu + 1.0) / 2.0; return vec4(u_nu, u_mu_s, u_mu, u_r); } vec2 GetIrradianceTextureUvFromRMuS(float r, float mu_s) { float x_r = (r - u_bottom_radius) / (u_top_radius - u_bottom_radius); float x_mu_s = mu_s * 0.5 + 0.5; return vec2( GetTextureCoordFromUnitRange(x_mu_s, IRRADIANCE_TEXTURE_WIDTH), GetTextureCoordFromUnitRange(x_r, IRRADIANCE_TEXTURE_HEIGHT) ); } vec3 GetIrradiance(const sampler2D u_irradiance_texture, float r, float mu_s) { vec2 uv = GetIrradianceTextureUvFromRMuS(r, mu_s); return vec3(texture(u_irradiance_texture, uv)); } vec3 GetExtrapolatedSingleMieScattering(const vec4 scattering) { if (scattering.r <= 0.0) { return vec3(0.0); } return scattering.rgb * scattering.a / scattering.r * (u_rayleigh_scattering.r / u_mie_scattering.r) * (u_mie_scattering / u_rayleigh_scattering); } vec3 GetCombinedScattering( const sampler3D u_scattering_texture, const sampler3D u_single_mie_scattering_texture, float r, float mu, float mu_s, float nu, bool ray_r_mu_intersects_ground, out vec3 single_mie_scattering ) { vec4 uvwz = GetScatteringTextureUvwzFromRMuMuSNu(r, mu, mu_s, nu, ray_r_mu_intersects_ground); float tex_coord_x = uvwz.x * float(SCATTERING_TEXTURE_NU_SIZE - 1); float tex_x = floor(tex_coord_x); float lerp = tex_coord_x - tex_x; vec3 uvw0 = vec3((tex_x + uvwz.y) / float(SCATTERING_TEXTURE_NU_SIZE), uvwz.z, uvwz.w); vec3 uvw1 = vec3((tex_x + 1.0 + uvwz.y) / float(SCATTERING_TEXTURE_NU_SIZE), uvwz.z, uvwz.w); vec4 combined_scattering = texture(u_scattering_texture, uvw0) * (1.0 - lerp) + texture(u_scattering_texture, uvw1) * lerp; vec3 scattering = vec3(combined_scattering); single_mie_scattering = GetExtrapolatedSingleMieScattering(combined_scattering); return scattering; } vec3 GetSkyRadiance( const sampler2D u_transmittance_texture, const sampler3D u_scattering_texture, const sampler3D u_single_mie_scattering_texture, vec3 camera, const vec3 view_ray, float shadow_length, const vec3 sun_direction, out vec3 transmittance ) { float r = length(camera); float rmu = dot(camera, view_ray); float distance_to_top_atmosphere_boundary = -rmu - SafeSqrt(rmu * rmu - r * r + u_top_radius * u_top_radius); if (distance_to_top_atmosphere_boundary > 0.0) { camera = camera + view_ray * distance_to_top_atmosphere_boundary; r = u_top_radius; rmu += distance_to_top_atmosphere_boundary; } else if (r > u_top_radius) { transmittance = vec3(1.0); return vec3(0.0); } float mu = rmu / r; float mu_s = dot(camera, sun_direction) / r; float nu = dot(view_ray, sun_direction); bool ray_r_mu_intersects_ground = RayIntersectsGround(r, mu); transmittance = ray_r_mu_intersects_ground ? vec3(0.0) : GetTransmittanceToTopAtmosphereBoundary(u_transmittance_texture, r, mu); vec3 single_mie_scattering; vec3 scattering; if (shadow_length == 0.0) { scattering = GetCombinedScattering( u_scattering_texture, u_single_mie_scattering_texture, r, mu, mu_s, nu, ray_r_mu_intersects_ground, single_mie_scattering ); } else { float d = shadow_length; float r_p = ClampRadius(sqrt(d * d + 2.0 * r * mu * d + r * r)); float mu_p = (r * mu + d) / r_p; float mu_s_p = (r * mu_s + d * nu) / r_p; scattering = GetCombinedScattering( u_scattering_texture, u_single_mie_scattering_texture, r_p, mu_p, mu_s_p, nu, ray_r_mu_intersects_ground, single_mie_scattering ); vec3 shadow_transmittance = GetTransmittance( u_transmittance_texture, r, mu, shadow_length, ray_r_mu_intersects_ground ); scattering = scattering * shadow_transmittance; single_mie_scattering = single_mie_scattering * shadow_transmittance; } return scattering * RayleighPhaseFunction(nu) + single_mie_scattering * MiePhaseFunction(u_mie_phase_function_g, nu); } vec3 GetSkyRadianceToPoint( const sampler2D u_transmittance_texture, const sampler3D u_scattering_texture, const sampler3D u_single_mie_scattering_texture, vec3 camera, const vec3 point, float shadow_length, const vec3 sun_direction, out vec3 transmittance ) { vec3 view_ray = normalize(point - camera); float r = length(camera); float rmu = dot(camera, view_ray); float distance_to_top_atmosphere_boundary = -rmu - sqrt(rmu * rmu - r * r + u_top_radius * u_top_radius); if (distance_to_top_atmosphere_boundary > 0.0) { camera = camera + view_ray * distance_to_top_atmosphere_boundary; r = u_top_radius; rmu += distance_to_top_atmosphere_boundary; } float mu = rmu / r; float mu_s = dot(camera, sun_direction) / r; float nu = dot(view_ray, sun_direction); float d = length(point - camera); bool ray_r_mu_intersects_ground = RayIntersectsGround(r, mu); // Hack to avoid rendering artifacts near the horizon, due to finite // atmosphere texture resolution and finite floating point precision. // See: https://github.com/ebruneton/precomputed_atmospheric_scattering/pull/32 if (!ray_r_mu_intersects_ground) { float mu_horiz = -SafeSqrt(1.0 - u_bottom_radius / r * (u_bottom_radius / r)); mu = max(mu, mu_horiz + 0.004); } transmittance = GetTransmittance(u_transmittance_texture, r, mu, d, ray_r_mu_intersects_ground); vec3 single_mie_scattering; vec3 scattering = GetCombinedScattering( u_scattering_texture, u_single_mie_scattering_texture, r, mu, mu_s, nu, ray_r_mu_intersects_ground, single_mie_scattering ); d = max(d - shadow_length, 0.0); float r_p = ClampRadius(sqrt(d * d + 2.0 * r * mu * d + r * r)); float mu_p = (r * mu + d) / r_p; float mu_s_p = (r * mu_s + d * nu) / r_p; vec3 single_mie_scattering_p; vec3 scattering_p = GetCombinedScattering( u_scattering_texture, u_single_mie_scattering_texture, r_p, mu_p, mu_s_p, nu, ray_r_mu_intersects_ground, single_mie_scattering_p ); vec3 shadow_transmittance = transmittance; if (shadow_length > 0.0) { shadow_transmittance = GetTransmittance( u_transmittance_texture, r, mu, d, ray_r_mu_intersects_ground ); } scattering = scattering - shadow_transmittance * scattering_p; single_mie_scattering = single_mie_scattering - shadow_transmittance * single_mie_scattering_p; single_mie_scattering = GetExtrapolatedSingleMieScattering( vec4(scattering, single_mie_scattering.r) ); single_mie_scattering = single_mie_scattering * smoothstep(float(0.0), float(0.01), mu_s); return scattering * RayleighPhaseFunction(nu) + single_mie_scattering * MiePhaseFunction(u_mie_phase_function_g, nu); } vec3 GetSunAndSkyIrradiance( const sampler2D u_transmittance_texture, const sampler2D u_irradiance_texture, const vec3 point, const vec3 sun_direction, out vec3 sky_irradiance ) { float r = length(point); float mu_s = dot(point, sun_direction) / r; sky_irradiance = GetIrradiance(u_irradiance_texture, r, mu_s); return u_solar_irradiance * GetTransmittanceToSun(u_transmittance_texture, r, mu_s); } vec3 GetSunAndSkyIrradiance( const sampler2D u_transmittance_texture, const sampler2D u_irradiance_texture, const vec3 point, const vec3 normal, const vec3 sun_direction, out vec3 sky_irradiance ) { float r = length(point); float mu_s = dot(point, sun_direction) / r; sky_irradiance = GetIrradiance(u_irradiance_texture, r, mu_s) * (1.0 + dot(normal, point) / r) * 0.5; return u_solar_irradiance * GetTransmittanceToSun(u_transmittance_texture, r, mu_s) * max(dot(normal, sun_direction), 0.0); } vec3 GetSolarRadiance() { vec3 radiance = u_solar_irradiance / (PI * u_sun_angular_radius * u_sun_angular_radius); #ifdef PHOTOMETRIC radiance *= SUN_SPECTRAL_RADIANCE_TO_LUMINANCE; #endif // PHOTOMETRIC return radiance; } vec3 GetSkyRadiance( vec3 camera, vec3 view_ray, float shadow_length, vec3 sun_direction, out vec3 transmittance ) { vec3 radiance = GetSkyRadiance( u_transmittance_texture, u_scattering_texture, u_single_mie_scattering_texture, camera, view_ray, shadow_length, sun_direction, transmittance ); #ifdef PHOTOMETRIC radiance *= SKY_SPECTRAL_RADIANCE_TO_LUMINANCE; #endif // PHOTOMETRIC return radiance; } vec3 GetSkyRadianceToPoint( vec3 camera, vec3 point, float shadow_length, vec3 sun_direction, out vec3 transmittance ) { vec3 inscatter = GetSkyRadianceToPoint( u_transmittance_texture, u_scattering_texture, u_single_mie_scattering_texture, camera, point, shadow_length, sun_direction, transmittance ); #ifdef PHOTOMETRIC inscatter *= SKY_SPECTRAL_RADIANCE_TO_LUMINANCE; #endif // PHOTOMETRIC return inscatter; } vec3 GetSunAndSkyIrradiance(vec3 point, vec3 sun_direction, out vec3 sky_irradiance) { vec3 sun_irradiance = GetSunAndSkyIrradiance( u_transmittance_texture, u_irradiance_texture, point, sun_direction, sky_irradiance ); #ifdef PHOTOMETRIC sun_irradiance *= SUN_SPECTRAL_RADIANCE_TO_LUMINANCE; sky_irradiance *= SKY_SPECTRAL_RADIANCE_TO_LUMINANCE; #endif // PHOTOMETRIC return sun_irradiance; } vec3 GetSunAndSkyIrradiance(vec3 point, vec3 normal, vec3 sun_direction, out vec3 sky_irradiance) { vec3 sun_irradiance = GetSunAndSkyIrradiance( u_transmittance_texture, u_irradiance_texture, point, normal, sun_direction, sky_irradiance ); #ifdef PHOTOMETRIC sun_irradiance *= SUN_SPECTRAL_RADIANCE_TO_LUMINANCE; sky_irradiance *= SKY_SPECTRAL_RADIANCE_TO_LUMINANCE; #endif // PHOTOMETRIC return sun_irradiance; } `,t=`uniform vec3 u_solar_irradiance; uniform float u_sun_angular_radius; uniform float u_bottom_radius; uniform float u_top_radius; uniform vec3 u_rayleigh_scattering; uniform vec3 u_mie_scattering; uniform float u_mie_phase_function_g; uniform float u_mu_s_min; uniform sampler2D u_transmittance_texture; uniform sampler3D u_scattering_texture; uniform sampler3D u_single_mie_scattering_texture; uniform sampler2D u_irradiance_texture; `;exports._functions=n;exports._parameters=t; //# sourceMappingURL=shared2.cjs.map