From 084aefd0e03ace27317e0a252ac206f3a461bd96 Mon Sep 17 00:00:00 2001 From: marcopavanello Date: Mon, 15 Sep 2025 18:03:09 +0200 Subject: [PATCH] Render: Add Multiple Scattering Sky Texture This mode is based on the same athmospheric model as the previous one, but now also accounts for multiple scattering and reflections from the ground. This increases the accuracy, especially at low elevations. Also renames some options for consistency: - The previous "Nishita" model is now "Single Scattering" - "Dust" is now "Aerosols" - Default altitude is now 100m. Co-authored-by: Lukas Stockner Pull Request: https://projects.blender.org/blender/blender/pulls/140480 --- intern/cycles/blender/shader.cpp | 2 +- .../kernel/osl/shaders/node_sky_texture.osl | 163 +++--- intern/cycles/kernel/svm/sky.h | 168 +++--- intern/cycles/kernel/svm/types.h | 2 +- intern/cycles/scene/image_sky.cpp | 57 +- intern/cycles/scene/image_sky.h | 10 +- intern/cycles/scene/light.cpp | 14 +- intern/cycles/scene/shader_nodes.cpp | 239 ++++----- intern/cycles/scene/shader_nodes.h | 2 +- intern/sky/CMakeLists.txt | 6 +- intern/sky/include/sky_model.h | 57 +- intern/sky/source/sky_float3.h | 139 ----- intern/sky/source/sky_math.h | 499 ++++++++++++++++++ intern/sky/source/sky_multiple_scattering.cpp | 401 ++++++++++++++ ..._nishita.cpp => sky_single_scattering.cpp} | 300 ++++++----- .../blenloader/intern/versioning_290.cc | 2 +- .../material/gpu_shader_material_tex_sky.glsl | 81 +-- source/blender/makesdna/DNA_color_types.h | 2 +- source/blender/makesdna/DNA_node_types.h | 4 +- .../blender/makesdna/intern/dna_rename_defs.h | 1 + .../blender/makesrna/intern/rna_nodetree.cc | 51 +- .../nodes/shader/nodes/node_shader_tex_sky.cc | 100 ++-- ..._decreased_disc_increased_air_aerosols.png | 3 + .../cycles_renders/sky_multiple_default.png | 3 + .../sky_multiple_increased_disc_ozone.png | 3 + .../sky_multiple_no_disc_high_altitude.png | 3 + .../sky_nishita_increased_disk_ozone.png | 3 - ...decreased_disc_increased_air_aerosols.png} | 0 ...ita_default.png => sky_single_default.png} | 0 .../sky_single_increased_disc_ozone.png | 3 + ...g => sky_single_no_disc_high_altitude.png} | 0 .../eevee_renders/sky_hosek_wilkie.png | 3 - ..._decreased_disc_increased_air_aerosols.png | 3 + .../eevee_renders/sky_multiple_default.png | 3 + .../sky_multiple_increased_disc_ozone.png | 3 + .../sky_multiple_no_disc_high_altitude.png | 3 + .../texture/eevee_renders/sky_preetham.png | 3 - ...decreased_disc_increased_air_aerosols.png} | 0 ...ita_default.png => sky_single_default.png} | 0 ...ng => sky_single_increased_disc_ozone.png} | 0 ...g => sky_single_no_disc_high_altitude.png} | 0 ...ecreased_disc_increased_air_aerosols.blend | 3 + .../render/texture/sky_multiple_default.blend | 3 + .../sky_multiple_increased_disc_ozone.blend | 3 + .../sky_multiple_no_disc_high_altitude.blend | 3 + ...creased_disc_increased_air_aerosols.blend} | 0 ...default.blend => sky_single_default.blend} | 0 ... => sky_single_increased_disc_ozone.blend} | 0 ...=> sky_single_no_disc_high_altitude.blend} | 0 .../storm_hydra_renders/sky_hosek_wilkie.png | 3 - ..._decreased_disc_increased_air_aerosols.png | 3 + .../sky_multiple_default.png | 3 + .../sky_multiple_increased_disc_ozone.png | 3 + .../sky_multiple_no_disc_high_altitude.png | 3 + .../storm_hydra_renders/sky_preetham.png | 3 - ...decreased_disc_increased_air_aerosols.png} | 0 ...ita_default.png => sky_single_default.png} | 0 ...ng => sky_single_increased_disc_ozone.png} | 0 ...g => sky_single_no_disc_high_altitude.png} | 0 .../storm_usd_renders/sky_hosek_wilkie.png | 3 - ..._decreased_disc_increased_air_aerosols.png | 3 + .../sky_multiple_default.png | 3 + .../sky_multiple_increased_disc_ozone.png | 3 + .../sky_multiple_no_disc_high_altitude.png | 3 + .../storm_usd_renders/sky_preetham.png | 3 - ...decreased_disc_increased_air_aerosols.png} | 0 ...ita_default.png => sky_single_default.png} | 0 ...ng => sky_single_increased_disc_ozone.png} | 0 ...g => sky_single_no_disc_high_altitude.png} | 0 .../workbench_renders/sky_hosek_wilkie.png | 3 - ..._decreased_disc_increased_air_aerosols.png | 3 + .../sky_multiple_default.png | 3 + .../sky_multiple_increased_disc_ozone.png | 3 + .../sky_multiple_no_disc_high_altitude.png | 3 + ...hita_decreased_disk_increased_air_dust.png | 3 - .../workbench_renders/sky_nishita_default.png | 3 - .../sky_nishita_increased_disk_ozone.png | 3 - .../sky_nishita_no_disk_high_altitude.png | 3 - .../workbench_renders/sky_preetham.png | 3 - ..._decreased_disc_increased_air_aerosols.png | 3 + .../workbench_renders/sky_single_default.png | 3 + .../sky_single_increased_disc_ozone.png | 3 + .../sky_single_no_disc_high_altitude.png | 3 + .../volume/cycles_renders/implicit_volume.png | 4 +- 84 files changed, 1592 insertions(+), 838 deletions(-) delete mode 100644 intern/sky/source/sky_float3.h create mode 100644 intern/sky/source/sky_math.h create mode 100644 intern/sky/source/sky_multiple_scattering.cpp rename intern/sky/source/{sky_nishita.cpp => sky_single_scattering.cpp} (58%) create mode 100644 tests/files/render/texture/cycles_renders/sky_multiple_decreased_disc_increased_air_aerosols.png create mode 100644 tests/files/render/texture/cycles_renders/sky_multiple_default.png create mode 100644 tests/files/render/texture/cycles_renders/sky_multiple_increased_disc_ozone.png create mode 100644 tests/files/render/texture/cycles_renders/sky_multiple_no_disc_high_altitude.png delete mode 100644 tests/files/render/texture/cycles_renders/sky_nishita_increased_disk_ozone.png rename tests/files/render/texture/cycles_renders/{sky_nishita_decreased_disk_increased_air_dust.png => sky_single_decreased_disc_increased_air_aerosols.png} (100%) rename tests/files/render/texture/cycles_renders/{sky_nishita_default.png => sky_single_default.png} (100%) create mode 100644 tests/files/render/texture/cycles_renders/sky_single_increased_disc_ozone.png rename tests/files/render/texture/cycles_renders/{sky_nishita_no_disk_high_altitude.png => sky_single_no_disc_high_altitude.png} (100%) delete mode 100644 tests/files/render/texture/eevee_renders/sky_hosek_wilkie.png create mode 100644 tests/files/render/texture/eevee_renders/sky_multiple_decreased_disc_increased_air_aerosols.png create mode 100644 tests/files/render/texture/eevee_renders/sky_multiple_default.png create mode 100644 tests/files/render/texture/eevee_renders/sky_multiple_increased_disc_ozone.png create mode 100644 tests/files/render/texture/eevee_renders/sky_multiple_no_disc_high_altitude.png delete mode 100644 tests/files/render/texture/eevee_renders/sky_preetham.png rename tests/files/render/texture/eevee_renders/{sky_nishita_decreased_disk_increased_air_dust.png => sky_single_decreased_disc_increased_air_aerosols.png} (100%) rename tests/files/render/texture/eevee_renders/{sky_nishita_default.png => sky_single_default.png} (100%) rename tests/files/render/texture/eevee_renders/{sky_nishita_increased_disk_ozone.png => sky_single_increased_disc_ozone.png} (100%) rename tests/files/render/texture/eevee_renders/{sky_nishita_no_disk_high_altitude.png => sky_single_no_disc_high_altitude.png} (100%) create mode 100644 tests/files/render/texture/sky_multiple_decreased_disc_increased_air_aerosols.blend create mode 100644 tests/files/render/texture/sky_multiple_default.blend create mode 100644 tests/files/render/texture/sky_multiple_increased_disc_ozone.blend create mode 100644 tests/files/render/texture/sky_multiple_no_disc_high_altitude.blend rename tests/files/render/texture/{sky_nishita_decreased_disk_increased_air_dust.blend => sky_single_decreased_disc_increased_air_aerosols.blend} (100%) mode change 100755 => 100644 rename tests/files/render/texture/{sky_nishita_default.blend => sky_single_default.blend} (100%) rename tests/files/render/texture/{sky_nishita_increased_disk_ozone.blend => sky_single_increased_disc_ozone.blend} (100%) rename tests/files/render/texture/{sky_nishita_no_disk_high_altitude.blend => sky_single_no_disc_high_altitude.blend} (100%) delete mode 100644 tests/files/render/texture/storm_hydra_renders/sky_hosek_wilkie.png create mode 100644 tests/files/render/texture/storm_hydra_renders/sky_multiple_decreased_disc_increased_air_aerosols.png create mode 100644 tests/files/render/texture/storm_hydra_renders/sky_multiple_default.png create mode 100644 tests/files/render/texture/storm_hydra_renders/sky_multiple_increased_disc_ozone.png create mode 100644 tests/files/render/texture/storm_hydra_renders/sky_multiple_no_disc_high_altitude.png delete mode 100644 tests/files/render/texture/storm_hydra_renders/sky_preetham.png rename tests/files/render/texture/storm_hydra_renders/{sky_nishita_decreased_disk_increased_air_dust.png => sky_single_decreased_disc_increased_air_aerosols.png} (100%) rename tests/files/render/texture/storm_hydra_renders/{sky_nishita_default.png => sky_single_default.png} (100%) rename tests/files/render/texture/storm_hydra_renders/{sky_nishita_increased_disk_ozone.png => sky_single_increased_disc_ozone.png} (100%) rename tests/files/render/texture/storm_hydra_renders/{sky_nishita_no_disk_high_altitude.png => sky_single_no_disc_high_altitude.png} (100%) delete mode 100644 tests/files/render/texture/storm_usd_renders/sky_hosek_wilkie.png create mode 100644 tests/files/render/texture/storm_usd_renders/sky_multiple_decreased_disc_increased_air_aerosols.png create mode 100644 tests/files/render/texture/storm_usd_renders/sky_multiple_default.png create mode 100644 tests/files/render/texture/storm_usd_renders/sky_multiple_increased_disc_ozone.png create mode 100644 tests/files/render/texture/storm_usd_renders/sky_multiple_no_disc_high_altitude.png delete mode 100644 tests/files/render/texture/storm_usd_renders/sky_preetham.png rename tests/files/render/texture/storm_usd_renders/{sky_nishita_decreased_disk_increased_air_dust.png => sky_single_decreased_disc_increased_air_aerosols.png} (100%) rename tests/files/render/texture/storm_usd_renders/{sky_nishita_default.png => sky_single_default.png} (100%) rename tests/files/render/texture/storm_usd_renders/{sky_nishita_increased_disk_ozone.png => sky_single_increased_disc_ozone.png} (100%) rename tests/files/render/texture/storm_usd_renders/{sky_nishita_no_disk_high_altitude.png => sky_single_no_disc_high_altitude.png} (100%) delete mode 100644 tests/files/render/texture/workbench_renders/sky_hosek_wilkie.png create mode 100644 tests/files/render/texture/workbench_renders/sky_multiple_decreased_disc_increased_air_aerosols.png create mode 100644 tests/files/render/texture/workbench_renders/sky_multiple_default.png create mode 100644 tests/files/render/texture/workbench_renders/sky_multiple_increased_disc_ozone.png create mode 100644 tests/files/render/texture/workbench_renders/sky_multiple_no_disc_high_altitude.png delete mode 100644 tests/files/render/texture/workbench_renders/sky_nishita_decreased_disk_increased_air_dust.png delete mode 100644 tests/files/render/texture/workbench_renders/sky_nishita_default.png delete mode 100644 tests/files/render/texture/workbench_renders/sky_nishita_increased_disk_ozone.png delete mode 100644 tests/files/render/texture/workbench_renders/sky_nishita_no_disk_high_altitude.png delete mode 100644 tests/files/render/texture/workbench_renders/sky_preetham.png create mode 100644 tests/files/render/texture/workbench_renders/sky_single_decreased_disc_increased_air_aerosols.png create mode 100644 tests/files/render/texture/workbench_renders/sky_single_default.png create mode 100644 tests/files/render/texture/workbench_renders/sky_single_increased_disc_ozone.png create mode 100644 tests/files/render/texture/workbench_renders/sky_single_no_disc_high_altitude.png diff --git a/intern/cycles/blender/shader.cpp b/intern/cycles/blender/shader.cpp index 08a45b9f68b..a35d71e538d 100644 --- a/intern/cycles/blender/shader.cpp +++ b/intern/cycles/blender/shader.cpp @@ -1041,7 +1041,7 @@ static ShaderNode *add_node(Scene *scene, sky->set_sun_rotation(b_sky_node.sun_rotation()); sky->set_altitude(b_sky_node.altitude()); sky->set_air_density(b_sky_node.air_density()); - sky->set_dust_density(b_sky_node.dust_density()); + sky->set_aerosol_density(b_sky_node.aerosol_density()); sky->set_ozone_density(b_sky_node.ozone_density()); BL::TexMapping b_texture_mapping(b_sky_node.texture_mapping()); get_tex_mapping(sky, b_texture_mapping); diff --git a/intern/cycles/kernel/osl/shaders/node_sky_texture.osl b/intern/cycles/kernel/osl/shaders/node_sky_texture.osl index c85121b21f3..b081f288de9 100644 --- a/intern/cycles/kernel/osl/shaders/node_sky_texture.osl +++ b/intern/cycles/kernel/osl/shaders/node_sky_texture.osl @@ -5,25 +5,12 @@ #include "node_color.h" #include "stdcycles.h" -float sky_angle_between(float thetav, float phiv, float theta, float phi) -{ - float cospsi = sin(thetav) * sin(theta) * cos(phi - phiv) + cos(thetav) * cos(theta); - - if (cospsi > 1.0) - return 0.0; - if (cospsi < -1.0) - return M_PI; - - return acos(cospsi); -} - vector sky_spherical_coordinates(vector dir) { return vector(acos(dir[2]), atan2(dir[0], dir[1]), 0); } -/* Nishita improved */ -vector geographical_to_direction(float lat, float lon) +vector spherical_to_direction(float lat, float lon) { return vector(cos(lat) * cos(lon), cos(lat) * sin(lon), sin(lat)); } @@ -33,101 +20,87 @@ float precise_angle(vector a, vector b) return 2.0 * atan2(length(a - b), length(a + b)); } -color sky_radiance_nishita(vector dir, float nishita_data[10], string filename) +float signx(float x) { - /* definitions */ - float sun_elevation = nishita_data[6]; - float sun_rotation = nishita_data[7]; - float angular_diameter = nishita_data[8]; - float sun_intensity = nishita_data[9]; - int sun_disc = angular_diameter > 0; - float alpha = 1.0; - color xyz; - /* convert dir to spherical coordinates */ - vector direction = sky_spherical_coordinates(dir); - - /* render above the horizon */ - if (dir[2] >= 0.0) { - /* definitions */ - vector sun_dir = geographical_to_direction(sun_elevation, sun_rotation + M_PI_2); - float sun_dir_angle = precise_angle(dir, sun_dir); - float half_angular = angular_diameter * 0.5; - float dir_elevation = M_PI_2 - direction[0]; - - /* If the ray is inside the sun disc, render it, otherwise render the sky. - * Alternatively, ignore the sun if we're evaluating the background texture. */ - if (sun_dir_angle < half_angular && sun_disc == 1 && raytype("importance_bake") != 1) { - /* get 2 pixels data */ - color pixel_bottom = color(nishita_data[0], nishita_data[1], nishita_data[2]); - color pixel_top = color(nishita_data[3], nishita_data[4], nishita_data[5]); - float y; - - /* sun interpolation */ - if (sun_elevation - half_angular > 0.0) { - if ((sun_elevation + half_angular) > 0.0) { - y = ((dir_elevation - sun_elevation) / angular_diameter) + 0.5; - xyz = mix(pixel_bottom, pixel_top, y) * sun_intensity; - } - } - else { - if (sun_elevation + half_angular > 0.0) { - y = dir_elevation / (sun_elevation + half_angular); - xyz = mix(pixel_bottom, pixel_top, y) * sun_intensity; - } - } - /* limb darkening, coefficient is 0.6f */ - float angle_fraction = sun_dir_angle / half_angular; - float limb_darkening = (1.0 - 0.6 * (1.0 - sqrt(1.0 - angle_fraction * angle_fraction))); - xyz *= limb_darkening; - } - /* sky */ - else { - /* sky interpolation */ - float x = (direction[1] + M_PI + sun_rotation) / M_2PI; - /* more pixels toward horizon compensation */ - float y = 1.0 - sqrt(dir_elevation / M_PI_2); - if (x > 1.0) { - x = x - 1.0; - } - xyz = (color)texture(filename, x, y, "wrap", "clamp", "interp", "linear", "alpha", alpha); - } + if (x < 0.0) { + return -1.0; + } + else if (x > 0.0) { + return 1.0; } - /* ground */ else { + return 0.0; + } +} + +color sky_radiance(vector dir, float sky_data[11], string filename, int sky_type) +{ + /* Get 2 pixels data */ + color pixel_bottom = color(sky_data[0], sky_data[1], sky_data[2]); + color pixel_top = color(sky_data[3], sky_data[4], sky_data[5]); + float sun_elevation = sky_data[6]; + float sun_rotation = sky_data[7]; + float angular_diameter = sky_data[8]; + float sun_intensity = sky_data[9]; + float earth_intersection_angle = sky_data[10]; + int sun_disc = angular_diameter > 0; + vector sun_dir = spherical_to_direction(sun_elevation, sun_rotation + M_PI_2); + float sun_dir_angle = precise_angle(dir, sun_dir); + float half_angular = angular_diameter * 0.5; + float alpha = 1.0; + color rgb_sun = color(0.0, 0.0, 0.0); + vector direction = sky_spherical_coordinates(dir); + float dir_elevation = M_PI_2 - direction[0]; + + /* If the ray is inside the Sun disc and is not occluded by Earth's surface, render it, otherwise + * render the sky. Alternatively, ignore the Sun if we're evaluating the background texture. */ + if (sun_dir_angle < half_angular && sun_disc == 1 && raytype("importance_bake") != 1 && + dir_elevation > earth_intersection_angle) + { + float y = ((dir_elevation - sun_elevation) / angular_diameter) + 0.5; + color xyz = mix(pixel_bottom, pixel_top, y); + /* Limb darkening, coefficient is 0.6 */ + float angle_fraction = sun_dir_angle / half_angular; + float limb_darkening = (1.0 - 0.6 * (1.0 - sqrt(1.0 - angle_fraction * angle_fraction))); + rgb_sun = xyz_to_rgb(xyz[0], xyz[1], xyz[2]) * limb_darkening; + } + float x = (direction[1] + M_PI + sun_rotation) / M_2PI; + if (x > 1.0) { + x = x - 1.0; + } + color rgb_sky; + if (sky_type == 0 && dir[2] < 0.0) { + /* Fade ground to black for Single Scattering model and disable Sun disc below horizon */ + rgb_sun = color(0.0, 0.0, 0.0); if (dir[2] < -0.4) { - xyz = color(0, 0, 0); + rgb_sky = color(0.0, 0.0, 0.0); } else { - /* black ground fade */ - float mul = pow(1.0 + dir[2] * 2.5, 3.0); - /* interpolation */ - float x = (direction[1] + M_PI + sun_rotation) / M_2PI; - float y = 1.5; - if (x > 1.0) { - x = x - 1.0; - } - xyz = (color)texture( - filename, x, y, "wrap", "periodic", "interp", "linear", "alpha", alpha) * - mul; + float fade = pow(1.0 + dir[2] * 2.5, 3.0); + color xyz = (color)texture( + filename, x, 0.492, "wrap", "periodic", "interp", "linear", "alpha", alpha); + rgb_sky = xyz_to_rgb(xyz[0], xyz[1], xyz[2]) * fade; } } - /* convert to RGB */ - return xyz_to_rgb(xyz[0], xyz[1], xyz[2]); + else { + /* Undo the non-linear transformation from the sky LUT */ + float dir_elevation_abs = (dir_elevation < 0.0) ? -dir_elevation : dir_elevation; + float y = 1.0 - (sqrt(dir_elevation_abs / M_PI_2) * signx(dir_elevation) * 0.5 + 0.5); + color xyz = (color)texture( + filename, x, y, "wrap", "clamp", "interp", "linear", "alpha", alpha); + rgb_sky = xyz_to_rgb(xyz[0], xyz[1], xyz[2]); + } + + return rgb_sun * sun_intensity + rgb_sky; } shader node_sky_texture( int use_mapping = 0, matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), vector Vector = P, - string sky_type = "nishita_improved", - float theta = 0.0, - float phi = 0.0, + int sky_type = 1, string filename = "", - color radiance = color(0.0, 0.0, 0.0), - float config_x[9] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, - float config_y[9] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, - float config_z[9] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, - float nishita_data[10] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + float sky_data[11] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, output color Color = color(0.0, 0.0, 0.0)) { vector p = Vector; @@ -135,5 +108,5 @@ shader node_sky_texture( if (use_mapping) p = transform(mapping, p); - Color = sky_radiance_nishita(p, nishita_data, filename); + Color = sky_radiance(p, sky_data, filename, sky_type); } diff --git a/intern/cycles/kernel/svm/sky.h b/intern/cycles/kernel/svm/sky.h index 6dc274008f6..4eafe75fde8 100644 --- a/intern/cycles/kernel/svm/sky.h +++ b/intern/cycles/kernel/svm/sky.h @@ -10,104 +10,69 @@ #include "kernel/util/colorspace.h" -#include "util/color.h" - CCL_NAMESPACE_BEGIN /* Sky texture */ -ccl_device float sky_angle_between(const float thetav, - const float phiv, - const float theta, - const float phi) +ccl_device float3 sky_radiance(KernelGlobals kg, + const bool multiple_scattering, + const float3 dir, + const uint32_t path_flag, + const ccl_private float *sky_data, + const uint texture_id) { - const float cospsi = sinf(thetav) * sinf(theta) * cosf(phi - phiv) + cosf(thetav) * cosf(theta); - return safe_acosf(cospsi); -} - -/* Nishita improved sky model */ -ccl_device float3 geographical_to_direction(const float lat, const float lon) -{ - return spherical_to_direction(lat - M_PI_2_F, lon - M_PI_2_F); -} - -ccl_device float3 sky_radiance_nishita(KernelGlobals kg, - const float3 dir, - const uint32_t path_flag, - const float3 pixel_bottom, - const float3 pixel_top, - const ccl_private float *nishita_data, - const uint texture_id) -{ - /* definitions */ - const float sun_elevation = nishita_data[0]; - const float sun_rotation = nishita_data[1]; - const float angular_diameter = nishita_data[2]; - const float sun_intensity = nishita_data[3]; + float3 pixel_bottom = make_float3(sky_data[0], sky_data[1], sky_data[2]); + float3 pixel_top = make_float3(sky_data[3], sky_data[4], sky_data[5]); + const float sun_elevation = sky_data[6]; + const float sun_rotation = sky_data[7]; + const float angular_diameter = sky_data[8]; + const float sun_intensity = sky_data[9]; + const float earth_intersection_angle = sky_data[10]; const bool sun_disc = (angular_diameter >= 0.0f); - float3 xyz; - /* convert dir to spherical coordinates */ const float2 direction = direction_to_spherical(dir); - /* render above the horizon */ - if (dir.z >= 0.0f) { - /* definitions */ - const float3 sun_dir = geographical_to_direction(sun_elevation, sun_rotation); - const float sun_dir_angle = precise_angle(dir, sun_dir); - const float half_angular = angular_diameter * 0.5f; - const float dir_elevation = M_PI_2_F - direction.x; + const float3 sun_dir = spherical_to_direction(sun_elevation - M_PI_2_F, sun_rotation - M_PI_2_F); + const float sun_dir_angle = precise_angle(dir, sun_dir); + const float half_angular = angular_diameter * 0.5f; + const float dir_elevation = M_PI_2_F - direction.x; + float3 rgb_sun = make_float3(0.0f, 0.0f, 0.0f); - /* If the ray is inside the sun disc, render it, otherwise render the sky. - * Alternatively, ignore the sun if we're evaluating the background texture. */ - if (sun_disc && sun_dir_angle < half_angular && - !((path_flag & PATH_RAY_IMPORTANCE_BAKE) && kernel_data.background.use_sun_guiding)) - { - /* get 2 pixels data */ - float y; - - /* sun interpolation */ - if (sun_elevation - half_angular > 0.0f) { - if (sun_elevation + half_angular > 0.0f) { - y = ((dir_elevation - sun_elevation) / angular_diameter) + 0.5f; - xyz = interp(pixel_bottom, pixel_top, y) * sun_intensity; - } - } - else { - if (sun_elevation + half_angular > 0.0f) { - y = dir_elevation / (sun_elevation + half_angular); - xyz = interp(pixel_bottom, pixel_top, y) * sun_intensity; - } - } - /* limb darkening, coefficient is 0.6f */ - const float limb_darkening = (1.0f - 0.6f * (1.0f - sqrtf(1.0f - sqr(sun_dir_angle / - half_angular)))); - xyz *= limb_darkening; - } - /* sky */ - else { - /* sky interpolation */ - const float x = fractf((-direction.y - M_PI_2_F + sun_rotation) / M_2PI_F); - /* more pixels toward horizon compensation */ - const float y = safe_sqrtf(dir_elevation / M_PI_2_F); - xyz = make_float3(kernel_tex_image_interp(kg, texture_id, x, y)); - } + /* If the ray is inside the Sun disc and is not occluded by Earth's surface, render it, otherwise + * render the sky. Alternatively, ignore the Sun if we're evaluating the background texture. */ + if (sun_disc && sun_dir_angle < half_angular && + !((path_flag & PATH_RAY_IMPORTANCE_BAKE) && kernel_data.background.use_sun_guiding) && + dir_elevation > earth_intersection_angle) + { + const float y = ((dir_elevation - sun_elevation) / angular_diameter) + 0.5f; + const float3 xyz = interp(pixel_bottom, pixel_top, y); + /* Limb darkening, coefficient is 0.6 */ + const float limb_darkening = (1.0f - + 0.6f * (1.0f - sqrtf(1.0f - sqr(sun_dir_angle / half_angular)))); + rgb_sun = xyz_to_rgb_clamped(kg, xyz) * limb_darkening; } - /* ground */ - else { + const float x = fractf((-direction.y - M_PI_2_F + sun_rotation) / M_2PI_F); + float3 rgb_sky; + if (!multiple_scattering && dir.z < 0.0f) { + /* Fade ground to black for Single Scattering model and disable Sun disc below horizon */ + rgb_sun = make_float3(0.0f, 0.0f, 0.0f); if (dir.z < -0.4f) { - xyz = make_float3(0.0f, 0.0f, 0.0f); + rgb_sky = make_float3(0.0f, 0.0f, 0.0f); } else { - /* black ground fade */ - float fade = 1.0f + dir.z * 2.5f; - fade = sqr(fade) * fade; - /* interpolation */ - const float x = fractf((-direction.y - M_PI_2_F + sun_rotation) / M_2PI_F); - xyz = make_float3(kernel_tex_image_interp(kg, texture_id, x, -0.5)) * fade; + float fade = powf(1.0f + dir.z * 2.5f, 3.0f); + const float3 xyz = make_float3(kernel_tex_image_interp(kg, texture_id, x, 0.508f)); + rgb_sky = xyz_to_rgb_clamped(kg, xyz) * fade; } } + else { + /* Undo the non-linear transformation from the sky LUT */ + const float dir_elevation_abs = (dir_elevation < 0.0f) ? -dir_elevation : dir_elevation; + const float y = sqrtf(dir_elevation_abs / M_PI_2_F) * copysignf(1.0f, dir_elevation) * 0.5f + + 0.5f; + const float3 xyz = make_float3(kernel_tex_image_interp(kg, texture_id, x, y)); + rgb_sky = xyz_to_rgb_clamped(kg, xyz); + } - /* convert to RGB */ - return xyz_to_rgb_clamped(kg, xyz); + return rgb_sun * sun_intensity + rgb_sky; } ccl_device_noinline int svm_node_tex_sky(KernelGlobals kg, @@ -119,34 +84,29 @@ ccl_device_noinline int svm_node_tex_sky(KernelGlobals kg, /* Load data */ const uint dir_offset = node.y; const uint out_offset = node.z; - + const bool multiple_scattering = node.w; + float sky_data[11]; const float3 dir = stack_load_float3(stack, dir_offset); - float3 f; - - /* Nishita */ - /* Define variables */ - float nishita_data[4]; - float4 data = read_node_float(kg, &offset); - const float3 pixel_bottom = make_float3(data.x, data.y, data.z); - float3 pixel_top; - pixel_top.x = data.w; - + sky_data[0] = data.x; + sky_data[1] = data.y; + sky_data[2] = data.z; + sky_data[3] = data.w; data = read_node_float(kg, &offset); - pixel_top.y = data.x; - pixel_top.z = data.y; - nishita_data[0] = data.z; - nishita_data[1] = data.w; - + sky_data[4] = data.x; + sky_data[5] = data.y; + sky_data[6] = data.z; + sky_data[7] = data.w; data = read_node_float(kg, &offset); - nishita_data[2] = data.x; - nishita_data[3] = data.y; - const uint texture_id = __float_as_uint(data.z); + sky_data[8] = data.x; + sky_data[9] = data.y; + sky_data[10] = data.z; + const uint texture_id = __float_as_uint(data.w); /* Compute Sky */ - f = sky_radiance_nishita(kg, dir, path_flag, pixel_bottom, pixel_top, nishita_data, texture_id); + float3 rgb = sky_radiance(kg, multiple_scattering, dir, path_flag, sky_data, texture_id); - stack_store_float3(stack, out_offset, f); + stack_store_float3(stack, out_offset, rgb); return offset; } diff --git a/intern/cycles/kernel/svm/types.h b/intern/cycles/kernel/svm/types.h index 01f21cd7a85..cb63259e89c 100644 --- a/intern/cycles/kernel/svm/types.h +++ b/intern/cycles/kernel/svm/types.h @@ -310,7 +310,7 @@ enum NodeWaveProfile { NODE_WAVE_PROFILE_TRI, }; -enum NodeSkyType { NODE_SKY_NISHITA }; +enum NodeSkyType { NODE_SKY_SINGLE_SCATTERING, NODE_SKY_MULTIPLE_SCATTERING }; enum NodeGradientType { NODE_BLEND_LINEAR, diff --git a/intern/cycles/scene/image_sky.cpp b/intern/cycles/scene/image_sky.cpp index c4fa1ca350b..32acf754fb3 100644 --- a/intern/cycles/scene/image_sky.cpp +++ b/intern/cycles/scene/image_sky.cpp @@ -4,21 +4,21 @@ #include "scene/image_sky.h" -#include "util/tbb.h" - #include "sky_model.h" CCL_NAMESPACE_BEGIN -SkyLoader::SkyLoader(const float sun_elevation, +SkyLoader::SkyLoader(const bool multiple_scattering, + const float sun_elevation, const float altitude, const float air_density, - const float dust_density, + const float aerosol_density, const float ozone_density) - : sun_elevation(sun_elevation), + : multiple_scattering(multiple_scattering), + sun_elevation(sun_elevation), altitude(altitude), air_density(air_density), - dust_density(dust_density), + aerosol_density(aerosol_density), ozone_density(ozone_density) { } @@ -28,7 +28,7 @@ SkyLoader::~SkyLoader() = default; bool SkyLoader::load_metadata(const ImageDeviceFeatures & /*features*/, ImageMetaData &metadata) { metadata.width = 512; - metadata.height = 128; + metadata.height = 256; metadata.channels = 3; metadata.type = IMAGE_DATA_TYPE_FLOAT4; metadata.compress_as_srgb = false; @@ -40,34 +40,39 @@ bool SkyLoader::load_pixels(const ImageMetaData &metadata, const size_t /*pixels_size*/, const bool /*associate_alpha*/) { - /* definitions */ + /* Precompute Sky LUT */ int width = metadata.width; int height = metadata.height; float *pixel_data = (float *)pixels; - - /* precompute sky texture */ - const int rows_per_task = divide_up(1024, width); - parallel_for(blocked_range(0, height, rows_per_task), - [&](const blocked_range &r) { - SKY_nishita_skymodel_precompute_texture(pixel_data, - metadata.channels, - r.begin(), - r.end(), - width, - height, - sun_elevation, - altitude, - air_density, - dust_density, - ozone_density); - }); + if (multiple_scattering) { + SKY_multiple_scattering_precompute_texture(pixel_data, + metadata.channels, + width, + height, + sun_elevation, + altitude, + air_density, + aerosol_density, + ozone_density); + } + else { + SKY_single_scattering_precompute_texture(pixel_data, + metadata.channels, + width, + height, + sun_elevation, + altitude, + air_density, + aerosol_density, + ozone_density); + } return true; } string SkyLoader::name() const { - return "sky_nishita"; + return "sky_multiple_scattering"; } bool SkyLoader::equals(const ImageLoader & /*other*/) const diff --git a/intern/cycles/scene/image_sky.h b/intern/cycles/scene/image_sky.h index 209f843f2d2..539d27a1db9 100644 --- a/intern/cycles/scene/image_sky.h +++ b/intern/cycles/scene/image_sky.h @@ -8,18 +8,20 @@ CCL_NAMESPACE_BEGIN class SkyLoader : public ImageLoader { private: + bool multiple_scattering; float sun_elevation; float altitude; float air_density; - float dust_density; + float aerosol_density; float ozone_density; public: - SkyLoader(const float sun_elevation, + SkyLoader(const bool multiple_scattering, + const float sun_elevation, const float altitude, const float air_density, - const float dust_density, - float ozone_density); + const float aerosol_density, + const float ozone_density); ~SkyLoader() override; bool load_metadata(const ImageDeviceFeatures &features, ImageMetaData &metadata) override; diff --git a/intern/cycles/scene/light.cpp b/intern/cycles/scene/light.cpp index 7095ef5d5e7..694a0bbcea9 100644 --- a/intern/cycles/scene/light.cpp +++ b/intern/cycles/scene/light.cpp @@ -1021,9 +1021,9 @@ void LightManager::device_update_background(Device *device, } if (node->type == SkyTextureNode::get_node_type()) { SkyTextureNode *sky = (SkyTextureNode *)node; - if (sky->get_sky_type() == NODE_SKY_NISHITA && sky->get_sun_disc()) { + if (sky->get_sun_disc()) { /* Ensure that the input coordinates aren't transformed before they reach the node. - * If that is the case, the logic used for sampling the sun's location does not work + * If that is the case, the logic used for sampling the Sun's location does not work * and we have to fall back to map-based sampling. */ const ShaderInput *vec_in = sky->input("Vector"); if (vec_in && vec_in->link && vec_in->link->parent) { @@ -1037,7 +1037,7 @@ void LightManager::device_update_background(Device *device, } } - /* Determine sun direction from lat/long and texture mapping. */ + /* Determine Sun direction from lat/long and texture mapping. */ const float latitude = sky->get_sun_elevation(); const float longitude = sky->get_sun_rotation() + M_PI_2_F; float3 sun_direction = make_float3( @@ -1045,11 +1045,11 @@ void LightManager::device_update_background(Device *device, const Transform sky_transform = transform_inverse(sky->tex_mapping.compute_transform()); sun_direction = transform_direction(&sky_transform, sun_direction); - /* Pack sun direction and size. */ + /* Pack Sun direction and size. */ const float half_angle = sky->get_sun_size() * 0.5f; kbackground->sun = make_float4(sun_direction, half_angle); - /* empirical value */ + /* Empirical value */ kbackground->sun_weight = 4.0f; sun_average_radiance = sky->get_sun_average_radiance(); environment_res.x = max(environment_res.x, 512); @@ -1059,7 +1059,7 @@ void LightManager::device_update_background(Device *device, } } - /* If there's more than one sun, fall back to map sampling instead. */ + /* If there's more than one Sun, fall back to map sampling instead. */ kbackground->use_sun_guiding = (num_suns == 1); if (!kbackground->use_sun_guiding) { kbackground->sun_weight = 0.0f; @@ -1124,7 +1124,7 @@ void LightManager::device_update_background(Device *device, const float map_average_radiance = cdf_total * M_PI_2_F; if (sun_average_radiance > 0.0f) { /* The weighting here is just a heuristic that was empirically determined. - * The sun's average radiance is much higher than the map's average radiance, + * The Sun's average radiance is much higher than the map's average radiance, * but we don't want to weight the background light too much because * visibility is not accounted for anyway. */ background_light->set_average_radiance(0.8f * map_average_radiance + diff --git a/intern/cycles/scene/shader_nodes.cpp b/intern/cycles/scene/shader_nodes.cpp index 40f18ae9b28..acda1cfbfac 100644 --- a/intern/cycles/scene/shader_nodes.cpp +++ b/intern/cycles/scene/shader_nodes.cpp @@ -633,82 +633,88 @@ void EnvironmentTextureNode::compile(OSLCompiler &compiler) /* Sky Texture */ struct SunSky { - /* sun direction in spherical and cartesian */ - float theta, phi; - - /* Parameter */ - float radiance_x, radiance_y, radiance_z; - float config_x[9], config_y[9], config_z[9], nishita_data[10]; + float sky_data[11]; }; -/* Nishita improved */ -static void sky_texture_precompute_nishita(SunSky *sunsky, - bool sun_disc, - const float sun_size, - const float sun_intensity, - const float sun_elevation, - const float sun_rotation, - const float altitude, - const float air_density, - const float dust_density) +static void sky_texture_precompute(SunSky *sunsky, + bool multiple_scattering, + bool sun_disc, + const float sun_size, + const float sun_intensity, + const float sun_elevation, + const float sun_rotation, + const float altitude, + const float air_density, + const float aerosol_density, + const float ozone_density) { - /* sample 2 sun pixels */ + /* Sample 2 Sun pixels */ float pixel_bottom[3]; float pixel_top[3]; - SKY_nishita_skymodel_precompute_sun( - sun_elevation, sun_size, altitude, air_density, dust_density, pixel_bottom, pixel_top); - /* send data to svm_sky */ - sunsky->nishita_data[0] = pixel_bottom[0]; - sunsky->nishita_data[1] = pixel_bottom[1]; - sunsky->nishita_data[2] = pixel_bottom[2]; - sunsky->nishita_data[3] = pixel_top[0]; - sunsky->nishita_data[4] = pixel_top[1]; - sunsky->nishita_data[5] = pixel_top[2]; - sunsky->nishita_data[6] = sun_elevation; - sunsky->nishita_data[7] = sun_rotation; - sunsky->nishita_data[8] = sun_disc ? sun_size : -1.0f; - sunsky->nishita_data[9] = sun_intensity; + if (multiple_scattering) { + SKY_multiple_scattering_precompute_sun(sun_elevation, + sun_size, + altitude, + air_density, + aerosol_density, + ozone_density, + pixel_bottom, + pixel_top); + } + else { + SKY_single_scattering_precompute_sun( + sun_elevation, sun_size, altitude, air_density, aerosol_density, pixel_bottom, pixel_top); + } + + float earth_intersection_angle = SKY_earth_intersection_angle(altitude); + + /* Send data to sky.h */ + sunsky->sky_data[0] = pixel_bottom[0]; + sunsky->sky_data[1] = pixel_bottom[1]; + sunsky->sky_data[2] = pixel_bottom[2]; + sunsky->sky_data[3] = pixel_top[0]; + sunsky->sky_data[4] = pixel_top[1]; + sunsky->sky_data[5] = pixel_top[2]; + sunsky->sky_data[6] = sun_elevation; + sunsky->sky_data[7] = sun_rotation; + sunsky->sky_data[8] = sun_disc ? sun_size : -1.0f; + sunsky->sky_data[9] = sun_intensity; + sunsky->sky_data[10] = -earth_intersection_angle; } float SkyTextureNode::get_sun_average_radiance() { - const float clamped_altitude = clamp(altitude, 1.0f, 59999.0f); const float angular_diameter = get_sun_size(); - float pix_bottom[3]; float pix_top[3]; - SKY_nishita_skymodel_precompute_sun(sun_elevation, - angular_diameter, - clamped_altitude, - air_density, - dust_density, - pix_bottom, - pix_top); - /* Approximate the direction's elevation as the sun's elevation. */ - const float dir_elevation = sun_elevation; - const float half_angular = angular_diameter / 2.0f; - const float3 pixel_bottom = make_float3(pix_bottom[0], pix_bottom[1], pix_bottom[2]); - const float3 pixel_top = make_float3(pix_top[0], pix_top[1], pix_top[2]); - - /* Same code as in the sun evaluation shader. */ - float3 xyz = make_float3(0.0f, 0.0f, 0.0f); - float y = 0.0f; - if (sun_elevation - half_angular > 0.0f) { - if (sun_elevation + half_angular > 0.0f) { - y = ((dir_elevation - sun_elevation) / angular_diameter) + 0.5f; - xyz = interp(pixel_bottom, pixel_top, y) * sun_intensity; - } + if (sky_type == NODE_SKY_SINGLE_SCATTERING) { + SKY_single_scattering_precompute_sun(sun_elevation, + angular_diameter, + altitude, + air_density, + aerosol_density, + pix_bottom, + pix_top); } else { - if (sun_elevation + half_angular > 0.0f) { - y = dir_elevation / (sun_elevation + half_angular); - xyz = interp(pixel_bottom, pixel_top, y) * sun_intensity; - } + SKY_multiple_scattering_precompute_sun(sun_elevation, + angular_diameter, + altitude, + air_density, + aerosol_density, + ozone_density, + pix_bottom, + pix_top); } - /* We first approximate the sun's contribution by + /* Sample center of Sun. */ + const float3 pixel_bottom = make_float3(pix_bottom[0], pix_bottom[1], pix_bottom[2]); + const float3 pixel_top = make_float3(pix_top[0], pix_top[1], pix_top[2]); + float3 xyz = interp(pixel_bottom, pixel_top, 0.5f) * sun_intensity; + + /* We first approximate the Sun's contribution by * multiplying the evaluated point by the square of the angular diameter. * Then we scale the approximation using a piecewise function (determined empirically). */ float sun_contribution = average(xyz) * sqr(angular_diameter); @@ -736,25 +742,21 @@ float SkyTextureNode::get_sun_average_radiance() NODE_DEFINE(SkyTextureNode) { NodeType *type = NodeType::add("sky_texture", create, NodeType::SHADER); - TEXTURE_MAPPING_DEFINE(SkyTextureNode); - static NodeEnum type_enum; - type_enum.insert("nishita_improved", NODE_SKY_NISHITA); - SOCKET_ENUM(sky_type, "Type", type_enum, NODE_SKY_NISHITA); - + type_enum.insert("single_scattering", NODE_SKY_SINGLE_SCATTERING); + type_enum.insert("multiple_scattering", NODE_SKY_MULTIPLE_SCATTERING); + SOCKET_ENUM(sky_type, "Type", type_enum, NODE_SKY_MULTIPLE_SCATTERING); SOCKET_BOOLEAN(sun_disc, "Sun Disc", true); SOCKET_FLOAT(sun_size, "Sun Size", 0.009512f); SOCKET_FLOAT(sun_intensity, "Sun Intensity", 1.0f); SOCKET_FLOAT(sun_elevation, "Sun Elevation", 15.0f * M_PI_F / 180.0f); SOCKET_FLOAT(sun_rotation, "Sun Rotation", 0.0f); - SOCKET_FLOAT(altitude, "Altitude", 1.0f); + SOCKET_FLOAT(altitude, "Altitude", 100.0f); SOCKET_FLOAT(air_density, "Air", 1.0f); - SOCKET_FLOAT(dust_density, "Dust", 1.0f); + SOCKET_FLOAT(aerosol_density, "Aerosol", 1.0f); SOCKET_FLOAT(ozone_density, "Ozone", 1.0f); - SOCKET_IN_POINT(vector, "Vector", zero_float3(), SocketType::LINK_TEXTURE_GENERATED); - SOCKET_OUT_COLOR(color, "Color"); return type; @@ -764,7 +766,7 @@ SkyTextureNode::SkyTextureNode() : TextureNode(get_node_type()) {} void SkyTextureNode::simplify_settings(Scene * /* scene */) { - /* Patch sun position so users are able to animate the daylight cycle while keeping the shading + /* Patch Sun position so users are able to animate the daylight cycle while keeping the shading * code simple. */ float new_sun_elevation = sun_elevation; float new_sun_rotation = sun_rotation; @@ -797,31 +799,29 @@ void SkyTextureNode::compile(SVMCompiler &compiler) { ShaderInput *vector_in = input("Vector"); ShaderOutput *color_out = output("Color"); - SunSky sunsky; - /* Clamp altitude to reasonable values. - * Below 1m causes numerical issues and above 60km is space. */ - const float clamped_altitude = clamp(altitude, 1.0f, 59999.0f); - - sky_texture_precompute_nishita(&sunsky, - sun_disc, - get_sun_size(), - sun_intensity, - sun_elevation, - sun_rotation, - clamped_altitude, - air_density, - dust_density); - /* precomputed texture image parameters */ + bool multiple_scattering = (sky_type == NODE_SKY_SINGLE_SCATTERING) ? false : true; + sky_texture_precompute(&sunsky, + multiple_scattering, + sun_disc, + get_sun_size(), + sun_intensity, + sun_elevation, + sun_rotation, + altitude, + air_density, + aerosol_density, + ozone_density); + /* Sky texture image parameters */ ImageManager *image_manager = compiler.scene->image_manager.get(); ImageParams impar; impar.interpolation = INTERPOLATION_LINEAR; impar.extension = EXTENSION_EXTEND; - /* precompute sky texture */ + /* Precompute sky texture */ if (handle.empty()) { unique_ptr loader = make_unique( - sun_elevation, clamped_altitude, air_density, dust_density, ozone_density); + multiple_scattering, sun_elevation, altitude, air_density, aerosol_density, ozone_density); handle = image_manager->add_image(std::move(loader), impar); } @@ -829,18 +829,18 @@ void SkyTextureNode::compile(SVMCompiler &compiler) compiler.stack_assign(color_out); compiler.add_node(NODE_TEX_SKY, vector_offset, compiler.stack_assign(color_out), sky_type); - compiler.add_node(__float_as_uint(sunsky.nishita_data[0]), - __float_as_uint(sunsky.nishita_data[1]), - __float_as_uint(sunsky.nishita_data[2]), - __float_as_uint(sunsky.nishita_data[3])); - compiler.add_node(__float_as_uint(sunsky.nishita_data[4]), - __float_as_uint(sunsky.nishita_data[5]), - __float_as_uint(sunsky.nishita_data[6]), - __float_as_uint(sunsky.nishita_data[7])); - compiler.add_node(__float_as_uint(sunsky.nishita_data[8]), - __float_as_uint(sunsky.nishita_data[9]), - handle.svm_slot(), - 0); + compiler.add_node(__float_as_uint(sunsky.sky_data[0]), + __float_as_uint(sunsky.sky_data[1]), + __float_as_uint(sunsky.sky_data[2]), + __float_as_uint(sunsky.sky_data[3])); + compiler.add_node(__float_as_uint(sunsky.sky_data[4]), + __float_as_uint(sunsky.sky_data[5]), + __float_as_uint(sunsky.sky_data[6]), + __float_as_uint(sunsky.sky_data[7])); + compiler.add_node(__float_as_uint(sunsky.sky_data[8]), + __float_as_uint(sunsky.sky_data[9]), + __float_as_uint(sunsky.sky_data[10]), + handle.svm_slot()); tex_mapping.compile_end(compiler, vector_in, vector_offset); } @@ -848,43 +848,36 @@ void SkyTextureNode::compile(SVMCompiler &compiler) void SkyTextureNode::compile(OSLCompiler &compiler) { tex_mapping.compile(compiler); - SunSky sunsky; - /* Clamp altitude to reasonable values. - * Below 1m causes numerical issues and above 60km is space. */ - const float clamped_altitude = clamp(altitude, 1.0f, 59999.0f); + int sky_model = (sky_type == NODE_SKY_SINGLE_SCATTERING) ? 0 : 1; + bool multiple_scattering = (sky_type == NODE_SKY_SINGLE_SCATTERING) ? false : true; - sky_texture_precompute_nishita(&sunsky, - sun_disc, - get_sun_size(), - sun_intensity, - sun_elevation, - sun_rotation, - clamped_altitude, - air_density, - dust_density); - /* precomputed texture image parameters */ + sky_texture_precompute(&sunsky, + multiple_scattering, + sun_disc, + get_sun_size(), + sun_intensity, + sun_elevation, + sun_rotation, + altitude, + air_density, + aerosol_density, + ozone_density); + /* Sky texture image parameters */ ImageManager *image_manager = compiler.scene->image_manager.get(); ImageParams impar; impar.interpolation = INTERPOLATION_LINEAR; impar.extension = EXTENSION_EXTEND; - /* precompute sky texture */ - if (handle.empty()) { + /* Precompute sky texture */ + { unique_ptr loader = make_unique( - sun_elevation, clamped_altitude, air_density, dust_density, ozone_density); + multiple_scattering, sun_elevation, altitude, air_density, aerosol_density, ozone_density); handle = image_manager->add_image(std::move(loader), impar); } - compiler.parameter(this, "sky_type"); - compiler.parameter("theta", sunsky.theta); - compiler.parameter("phi", sunsky.phi); - compiler.parameter_color("radiance", - make_float3(sunsky.radiance_x, sunsky.radiance_y, sunsky.radiance_z)); - compiler.parameter_array("config_x", sunsky.config_x, 9); - compiler.parameter_array("config_y", sunsky.config_y, 9); - compiler.parameter_array("config_z", sunsky.config_z, 9); - compiler.parameter_array("nishita_data", sunsky.nishita_data, 10); + compiler.parameter("sky_type", sky_model); + compiler.parameter_array("sky_data", sunsky.sky_data, 11); compiler.parameter_texture("filename", handle); compiler.add(this, "node_sky_texture"); } diff --git a/intern/cycles/scene/shader_nodes.h b/intern/cycles/scene/shader_nodes.h index bb10a288ad1..0e740c568db 100644 --- a/intern/cycles/scene/shader_nodes.h +++ b/intern/cycles/scene/shader_nodes.h @@ -161,7 +161,7 @@ class SkyTextureNode : public TextureNode { NODE_SOCKET_API(float, sun_rotation) NODE_SOCKET_API(float, altitude) NODE_SOCKET_API(float, air_density) - NODE_SOCKET_API(float, dust_density) + NODE_SOCKET_API(float, aerosol_density) NODE_SOCKET_API(float, ozone_density) NODE_SOCKET_API(float3, vector) ImageHandle handle; diff --git a/intern/sky/CMakeLists.txt b/intern/sky/CMakeLists.txt index 6569f3dbde8..9b6a464987b 100644 --- a/intern/sky/CMakeLists.txt +++ b/intern/sky/CMakeLists.txt @@ -11,13 +11,15 @@ set(INC_SYS ) set(SRC - source/sky_nishita.cpp + source/sky_single_scattering.cpp + source/sky_multiple_scattering.cpp include/sky_model.h - source/sky_float3.h + source/sky_math.h ) set(LIB + PRIVATE bf::dependencies::optional::tbb ) blender_add_lib(bf_intern_sky "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/intern/sky/include/sky_model.h b/intern/sky/include/sky_model.h index 64cac693983..b9f041d49b0 100644 --- a/intern/sky/include/sky_model.h +++ b/intern/sky/include/sky_model.h @@ -1,4 +1,4 @@ -/* SPDX-FileCopyrightText: 2020-2022 Blender Authors +/* SPDX-FileCopyrightText: 2020-2025 Blender Authors * * SPDX-License-Identifier: GPL-2.0-or-later */ @@ -13,27 +13,44 @@ extern "C" { #endif -/* Nishita improved sky model */ +void SKY_single_scattering_precompute_texture(float *pixels, + int stride, + int width, + int height, + float sun_elevation, + float altitude, + float air_density, + float aerosol_density, + float ozone_density); -void SKY_nishita_skymodel_precompute_texture(float *pixels, - int stride, - int start_y, - int end_y, - int width, - int height, - float sun_elevation, - float altitude, - float air_density, - float dust_density, - float ozone_density); +void SKY_single_scattering_precompute_sun(float sun_elevation, + float angular_diameter, + float altitude, + float air_density, + float aerosol_density, + float r_pixel_bottom[3], + float r_pixel_top[3]); -void SKY_nishita_skymodel_precompute_sun(float sun_elevation, - float angular_diameter, - float altitude, - float air_density, - float dust_density, - float *r_pixel_bottom, - float *r_pixel_top); +void SKY_multiple_scattering_precompute_texture(float *pixels, + int stride, + int width, + int height, + float sun_elevation, + float altitude, + float air_density, + float aerosol_density, + float ozone_density); + +void SKY_multiple_scattering_precompute_sun(float sun_elevation, + float angular_diameter, + float altitude, + float air_density, + float aerosol_density, + float ozone_density, + float r_pixel_bottom[3], + float r_pixel_top[3]); + +float SKY_earth_intersection_angle(float altitude); #ifdef __cplusplus } diff --git a/intern/sky/source/sky_float3.h b/intern/sky/source/sky_float3.h deleted file mode 100644 index 92bb9ef341f..00000000000 --- a/intern/sky/source/sky_float3.h +++ /dev/null @@ -1,139 +0,0 @@ -/* SPDX-FileCopyrightText: 2020-2022 Blender Authors - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -/** \file - * \ingroup intern_sky_modal - */ - -#ifndef __SKY_FLOAT3_H__ -#define __SKY_FLOAT3_H__ - -// minimal float3 + util_math.h implementation for nishita sky model - -#include - -#ifndef M_PI_F -# define M_PI_F (3.1415926535897932f) /* pi */ -#endif -#ifndef M_PI_2_F -# define M_PI_2_F (1.5707963267948966f) /* pi/2 */ -#endif -#ifndef M_2PI_F -# define M_2PI_F (6.2831853071795864f) /* 2*pi */ -#endif - -struct float3 { - float x, y, z; - - float3() = default; - - float3(const float *ptr) : x{ptr[0]}, y{ptr[1]}, z{ptr[2]} {} - - float3(const float (*ptr)[3]) : float3((const float *)ptr) {} - - explicit float3(float value) : x(value), y(value), z(value) {} - - explicit float3(int value) : x(value), y(value), z(value) {} - - float3(float x, float y, float z) : x{x}, y{y}, z{z} {} - - operator const float *() const - { - return &x; - } - - operator float *() - { - return &x; - } - - friend float3 operator*(const float3 &a, float b) - { - return {a.x * b, a.y * b, a.z * b}; - } - - friend float3 operator*(float b, const float3 &a) - { - return {a.x * b, a.y * b, a.z * b}; - } - - friend float3 operator-(const float3 &a, const float3 &b) - { - return {a.x - b.x, a.y - b.y, a.z - b.z}; - } - - friend float3 operator-(const float3 &a) - { - return {-a.x, -a.y, -a.z}; - } - - float length_squared() const - { - return x * x + y * y + z * z; - } - - float length() const - { - return sqrt(length_squared()); - } - - static float distance(const float3 &a, const float3 &b) - { - return (a - b).length(); - } - - friend float3 operator+(const float3 &a, const float3 &b) - { - return {a.x + b.x, a.y + b.y, a.z + b.z}; - } - - void operator+=(const float3 &b) - { - this->x += b.x; - this->y += b.y; - this->z += b.z; - } - - friend float3 operator*(const float3 &a, const float3 &b) - { - return {a.x * b.x, a.y * b.y, a.z * b.z}; - } -}; - -inline float sqr(float a) -{ - return a * a; -} - -inline float3 make_float3(float x, float y, float z) -{ - return float3(x, y, z); -} - -inline float dot(const float3 &a, const float3 &b) -{ - return a.x * b.x + a.y * b.y + a.z * b.z; -} - -inline float distance(const float3 &a, const float3 &b) -{ - return float3::distance(a, b); -} - -inline float len_squared(float3 f) -{ - return f.length_squared(); -} - -inline float len(float3 f) -{ - return f.length(); -} - -inline float reduce_add(float3 f) -{ - return f.x + f.y + f.z; -} - -#endif /* __SKY_FLOAT3_H__ */ diff --git a/intern/sky/source/sky_math.h b/intern/sky/source/sky_math.h new file mode 100644 index 00000000000..87d846612b9 --- /dev/null +++ b/intern/sky/source/sky_math.h @@ -0,0 +1,499 @@ +/* SPDX-FileCopyrightText: 2020-2022 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup intern_sky_modal + */ + +#ifndef __SKY_MATH_H__ +#define __SKY_MATH_H__ + +#ifdef WITH_TBB +# include +#else +# include +#endif + +/* Minimal math implementation for sky model. */ + +#include + +#ifndef M_PI_F +# define M_PI_F (3.1415926535897932f) /* pi */ +#endif +#ifndef M_PI_2_F +# define M_PI_2_F (1.5707963267948966f) /* pi/2 */ +#endif +#ifndef M_2PI_F +# define M_2PI_F (6.2831853071795864f) /* 2*pi */ +#endif +#ifndef M_1_PI_F +# define M_1_PI_F (0.3183098861837067f) /* 1/pi */ +#endif +#ifndef M_4PI_F +# define M_4PI_F (12.566370614359172f) /* 4*pi */ +#endif +#ifndef M_1_4PI_F +# define M_1_4PI_F (0.0795774715459476f) /* 1/(4*pi) */ +#endif + +/* float2 */ +struct float2 { + float x, y; + + float2() = default; + + float2(const float *ptr) : x{ptr[0]}, y{ptr[1]} {} + + float2(const float (*ptr)[2]) : float2((const float *)ptr) {} + + explicit float2(float value) : x(value), y(value) {} + + explicit float2(int value) : x(value), y(value) {} + + float2(float x, float y) : x{x}, y{y} {} + + operator const float *() const + { + return &x; + } + + operator float *() + { + return &x; + } + + friend float2 operator*(const float2 &a, float b) + { + return {a.x * b, a.y * b}; + } + + friend float2 operator*(float b, const float2 &a) + { + return {a.x * b, a.y * b}; + } + + friend float2 operator/(const float2 &a, float b) + { + return {a.x / b, a.y / b}; + } + + friend float2 operator/(float b, const float2 &a) + { + return {a.x / b, a.y / b}; + } + + friend float2 operator/(const float2 &a, const float2 &b) + { + return {a.x / b.x, a.y / b.y}; + } + + friend float2 operator-(const float2 &a, const float2 &b) + { + return {a.x - b.x, a.y - b.y}; + } + + friend float2 operator-(const float2 &a) + { + return {-a.x, -a.y}; + } + + float length_squared() const + { + return x * x + y * y; + } + + float length() const + { + return sqrt(length_squared()); + } + + static float distance(const float2 &a, const float2 &b) + { + return (a - b).length(); + } + + friend float2 operator+(const float2 &a, const float2 &b) + { + return {a.x + b.x, a.y + b.y}; + } + + void operator+=(const float2 &b) + { + this->x += b.x; + this->y += b.y; + } + + friend float2 operator*(const float2 &a, const float2 &b) + { + return {a.x * b.x, a.y * b.y}; + } +}; + +/* float3 */ +struct float3 { + float x, y, z; + + float3() = default; + + float3(const float *ptr) : x{ptr[0]}, y{ptr[1]}, z{ptr[2]} {} + + float3(const float (*ptr)[3]) : float3((const float *)ptr) {} + + explicit float3(float value) : x(value), y(value), z(value) {} + + explicit float3(int value) : x(value), y(value), z(value) {} + + float3(float x, float y, float z) : x{x}, y{y}, z{z} {} + + operator const float *() const + { + return &x; + } + + operator float *() + { + return &x; + } + + friend float3 operator*(const float3 &a, float b) + { + return {a.x * b, a.y * b, a.z * b}; + } + + friend float3 operator*(float b, const float3 &a) + { + return {a.x * b, a.y * b, a.z * b}; + } + + friend float3 operator/(const float3 &a, float b) + { + return {a.x / b, a.y / b, a.z / b}; + } + + friend float3 operator/(float b, const float3 &a) + { + return {a.x / b, a.y / b, a.z / b}; + } + + friend float3 operator-(const float3 &a, const float3 &b) + { + return {a.x - b.x, a.y - b.y, a.z - b.z}; + } + + friend float3 operator-(const float3 &a) + { + return {-a.x, -a.y, -a.z}; + } + + float length_squared() const + { + return x * x + y * y + z * z; + } + + float length() const + { + return sqrt(length_squared()); + } + + static float distance(const float3 &a, const float3 &b) + { + return (a - b).length(); + } + + friend float3 operator+(const float3 &a, const float3 &b) + { + return {a.x + b.x, a.y + b.y, a.z + b.z}; + } + + void operator+=(const float3 &b) + { + this->x += b.x; + this->y += b.y; + this->z += b.z; + } + + friend float3 operator*(const float3 &a, const float3 &b) + { + return {a.x * b.x, a.y * b.y, a.z * b.z}; + } +}; + +/* float4 */ +struct float4 { + float x, y, z, w; + + float4() = default; + + float4(const float *ptr) : x{ptr[0]}, y{ptr[1]}, z{ptr[2]}, w{ptr[3]} {} + + float4(const float (*ptr)[4]) : float4((const float *)ptr) {} + + explicit float4(float value) : x(value), y(value), z(value), w(value) {} + + explicit float4(int value) : x(value), y(value), z(value), w(value) {} + + float4(float x, float y, float z, float w) : x{x}, y{y}, z{z}, w{w} {} + + operator const float *() const + { + return &x; + } + + operator float *() + { + return &x; + } + + friend float4 operator*(const float4 &a, float b) + { + return {a.x * b, a.y * b, a.z * b, a.w * b}; + } + + friend float4 operator*(float b, const float4 &a) + { + return {a.x * b, a.y * b, a.z * b, a.w * b}; + } + + friend float4 operator/(const float4 &a, float b) + { + return {a.x / b, a.y / b, a.z / b, a.w / b}; + } + + friend float4 operator/(float b, const float4 &a) + { + return {a.x / b, a.y / b, a.z / b, a.w / b}; + } + + friend float4 operator*(const float4 &a, const float4 &b) + { + return {a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w}; + } + + friend float4 operator/(const float4 &a, const float4 &b) + { + return {a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w}; + } + + friend float4 operator-(const float4 &a, const float4 &b) + { + return {a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w}; + } + + friend float4 operator-(const float4 &a) + { + return {-a.x, -a.y, -a.z, -a.w}; + } + + float length_squared() const + { + return x * x + y * y + z * z + w * w; + } + + float length() const + { + return sqrt(length_squared()); + } + + static float distance(const float4 &a, const float4 &b) + { + return (a - b).length(); + } + + friend float4 operator+(const float4 &a, const float4 &b) + { + return {a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w}; + } + + void operator+=(const float4 &b) + { + this->x += b.x; + this->y += b.y; + this->z += b.z; + this->w += b.w; + } + + void operator*=(const float4 &b) + { + this->x *= b.x; + this->y *= b.y; + this->z *= b.z; + this->w *= b.w; + } +}; + +inline float sqr(float a) +{ + return a * a; +} + +inline float safe_sqrtf(const float f) +{ + return sqrt(fmax(f, 0.0f)); +} + +inline float2 make_float2(float x, float y) +{ + return float2(x, y); +} + +inline float dot(const float2 &a, const float2 &b) +{ + return a.x * b.x + a.y * b.y; +} + +inline float distance(const float2 &a, const float2 &b) +{ + return float2::distance(a, b); +} + +inline float len_squared(float2 f) +{ + return f.length_squared(); +} + +inline float len(float2 f) +{ + return f.length(); +} + +inline float reduce_add(float2 f) +{ + return f.x + f.y; +} + +inline float3 make_float3(float x, float y, float z) +{ + return float3(x, y, z); +} + +inline float dot(const float3 &a, const float3 &b) +{ + return a.x * b.x + a.y * b.y + a.z * b.z; +} + +inline float distance(const float3 &a, const float3 &b) +{ + return float3::distance(a, b); +} + +inline float len_squared(float3 f) +{ + return f.length_squared(); +} + +inline float len(float3 f) +{ + return f.length(); +} + +inline float reduce_add(float3 f) +{ + return f.x + f.y + f.z; +} + +inline float4 make_float4(float x, float y, float z, float w) +{ + return float4(x, y, z, w); +} + +inline float dot(const float4 a, const float4 b) +{ + return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w; +} + +inline float distance(const float4 &a, const float4 &b) +{ + return float4::distance(a, b); +} + +inline float len_squared(float4 f) +{ + return f.length_squared(); +} + +inline float len(float4 f) +{ + return f.length(); +} + +inline float reduce_add(float4 f) +{ + return f.x + f.y + f.z + f.w; +} + +inline float4 exp(float4 a) +{ + return make_float4(expf(a.x), expf(a.y), expf(a.z), expf(a.w)); +} + +inline float4 max(float4 a, float b) +{ + return make_float4(fmax(a.x, b), fmax(a.y, b), fmax(a.z, b), fmax(a.w, b)); +} + +inline float clamp(float x, float min, float max) +{ + if (x < min) { + return min; + } + if (x > max) { + return max; + } + return x; +} + +inline float saturate(const float a) +{ + return clamp(a, 0.0f, 1.0f); +} + +template inline T mix(T x, T y, float a) +{ + return x + a * (y - x); +} + +inline float3 sun_direction(float sun_cos_theta) +{ + return make_float3(-sqrtf(1.0f - sun_cos_theta * sun_cos_theta), 0.0f, sun_cos_theta); +} + +inline float ray_sphere_intersection(float3 pos, float3 dir, float radius) +{ + float b = dot(pos, dir); + float c = dot(pos, pos) - radius * radius; + if (c > 0.0f && b > 0.0f) { + return -1.0f; + } + float d = b * b - c; + if (d < 0) { + return -1.0f; + } + if (d >= b * b) { + return -b + sqrtf(d); + } + return -b - sqrtf(d); +} + +/* Minimal parallel for implementation. */ + +template +inline void SKY_parallel_for(const size_t begin, + const size_t end, + const size_t grainsize, + const Function &function) +{ +#ifdef WITH_TBB + tbb::parallel_for( + tbb::blocked_range(begin, end, grainsize), + [function](const tbb::blocked_range &r) { function(r.begin(), r.end()); }); +#else + for (size_t i = begin; i < end; i += grainsize) { + function(i, std::min(i + grainsize, end)); + } + (void)grainsize; +#endif +} + +#endif /* __SKY_MATH_H__ */ diff --git a/intern/sky/source/sky_multiple_scattering.cpp b/intern/sky/source/sky_multiple_scattering.cpp new file mode 100644 index 00000000000..407e5838606 --- /dev/null +++ b/intern/sky/source/sky_multiple_scattering.cpp @@ -0,0 +1,401 @@ +/* SPDX-FileCopyrightText: 2022 Fernando García Liñán + * SPDX-FileCopyrightText: 2011-2025 Blender Authors + * + * SPDX-License-Identifier: MIT */ + +/** \file + * \ingroup intern_sky_modal + */ + +/* + * This code is a converted version of the ShaderToy written by Fernando García Liñán. + * + * This shader is the final result of my Master's Thesis. + * The main contributions are: + * + * 1. A spectral rendering technique that only requires 4 wavelength samples to + * get accurate results. + * 2. A multiple scattering approximation. + * + * Both of these approximations rely on an analytical fit, so they only work for + * Earth's atmosphere. We make up for it by using a very flexible atmosphere + * model that is able to represent a wide variety of atmospheric conditions. + * + * A brief description of this spectral rendering technique can be found in the + * following article: + * https://fgarlin.com/posts/2024-12-06-spectral_sky/ + * + * The path tracer that has been used as a ground truth can be found at: + * https://github.com/fgarlin/skytracer + */ + +#include + +#include "sky_math.h" +#include "sky_model.h" + +using std::min; + +/* Earth's atmosphere parameters. */ +/* Ground reflectance. */ +static const float4 GROUND_ALBEDO = make_float4(0.3f, 0.3f, 0.3f, 0.3f); +static const float PHASE_ISOTROPIC = M_1_4PI_F; +static const float RAYLEIGH_PHASE_SCALE = (3.0f / 16.0f) * M_1_PI_F; +/* Aerosols anisotropy. */ +static const float G = 0.8f; +static const float SQR_G = G * G; +/* Earth radius (km). */ +static const float EARTH_RADIUS = 6371.0f; +/* Atmosphere thickness (km). */ +static const float ATMOSPHERE_THICKNESS = 100.0f; +static const float ATMOSPHERE_RADIUS = EARTH_RADIUS + ATMOSPHERE_THICKNESS; +/* Ray marching steps. Higher steps means increased accuracy but worse performance. */ +static const int TRANSMITTANCE_STEPS = 64; +static const int IN_SCATTERING_STEPS = 64; + +/* LUTs. */ +static const int TRANSMITTANCE_RES_X = 256; +static const int TRANSMITTANCE_RES_Y = 64; + +/* Spectral data sampled at 630, 560, 490, 430 nm for urban area. */ +static const float4 SUN_SPECTRAL_IRRADIANCE = make_float4(1.679f, 1.828f, 1.986f, 1.307f); +static const float4 MOLECULAR_SCATTERING_COEFFICIENT_BASE = make_float4( + 6.605e-3f, 1.067e-2f, 1.842e-2f, 3.156e-2f); +static const float4 OZONE_ABSORPTION_CROSS_SECTION = make_float4( + 3.472e-25f, 3.914e-25f, 1.349e-25f, 11.03e-27f); +/* Average ozone dobson of monthly mean values. */ +static const float OZONE_MEAN_DOBSON = 334.5f; +static const float4 AEROSOL_ABSORPTION_CROSS_SECTION = make_float4( + 2.8722e-24f, 4.6168e-24f, 7.9706e-24f, 1.3578e-23f); +static const float4 AEROSOL_SCATTERING_CROSS_SECTION = make_float4( + 1.5908e-22f, 1.7711e-22f, 2.0942e-22f, 2.4033e-22f); +static const float AEROSOL_BASE_DENSITY = 1.3681e20f; +static const float AEROSOL_BACKGROUND_DENSITY = 2e6f; +static const float AEROSOL_HEIGHT_SCALE = 0.73f; +/* Spectral to XYZ space conversion matrix. */ +static const float3 SPECTRAL_XYZ[4] = { + make_float3(53.386917738564668023f, 22.981337506691024754f, 0.0f), + make_float3(43.904844466369358263f, 71.347795700053393866f, 0.102506867965741307f), + make_float3(1.6137278251608962005f, 18.422960591455485011f, 31.742921188390805758f), + make_float3(20.762668673810577145f, 2.3614213523314368527f, 110.48009643252140334f), +}; + +inline float molecular_phase_function(const float cos_theta) +{ + return RAYLEIGH_PHASE_SCALE * (1.0f + sqr(cos_theta)); +} + +inline float aerosol_phase_function(const float cos_theta) +{ + float den = 1.0f + SQR_G + 2.0f * G * cos_theta; + return M_1_4PI_F * (1.0f - SQR_G) / (den * sqrtf(den)); +} + +inline float4 get_molecular_scattering_coefficient(const float h) +{ + return MOLECULAR_SCATTERING_COEFFICIENT_BASE * expf(-0.07771971f * powf(h, 1.16364243f)); +} + +inline float4 get_molecular_absorption_coefficient(const float h) +{ + const float log_h = logf(fmaxf(h, 1e-4f)); + float density = 3.78547397e20f * expf(-sqr(log_h - 3.22261f) * 5.55555555f - log_h); + return OZONE_ABSORPTION_CROSS_SECTION * OZONE_MEAN_DOBSON * density; +} + +inline float get_aerosol_density(const float h) +{ + float division = AEROSOL_BACKGROUND_DENSITY / AEROSOL_BASE_DENSITY; + return AEROSOL_BASE_DENSITY * (expf(-h / AEROSOL_HEIGHT_SCALE) + division); +} + +inline float3 spectral_to_xyz(const float4 L) +{ + float3 xyz = make_float3(0.0f, 0.0f, 0.0f); + for (int i = 0; i < 4; i++) { + xyz += SPECTRAL_XYZ[i] * L[i]; + } + return xyz; +} + +/* Precomputed data. */ +class SkyMultipleScattering { + public: + SkyMultipleScattering(const float air_density, + const float aerosol_density, + const float ozone_density) + : air_density(air_density), aerosol_density(aerosol_density), ozone_density(ozone_density) + { + } + + /* Compute atmosphere's transmittance from the given altitude to the sun. */ + inline float4 get_transmittance(const float cos_theta, const float normalized_altitude) const + { + const float3 sun_dir = sun_direction(cos_theta); + const float distance_to_earth_center = mix( + EARTH_RADIUS, ATMOSPHERE_RADIUS, normalized_altitude); + const float3 ray_origin = make_float3(0.0f, 0.0f, distance_to_earth_center); + const float t_d = ray_sphere_intersection(ray_origin, sun_dir, ATMOSPHERE_RADIUS); + const float t_step = t_d / TRANSMITTANCE_STEPS; + + float4 result = make_float4(0.0f, 0.0f, 0.0f, 0.0f); + for (int step = 0; step < TRANSMITTANCE_STEPS; step++) { + const float t = (step + 0.5f) * t_step; + const float3 x_t = ray_origin + sun_dir * t; + const float altitude = fmaxf(x_t.length() - EARTH_RADIUS, 0.0f); + float4 aerosol_absorption, aerosol_scattering, molecular_absorption, molecular_scattering; + get_atmosphere_collision_coefficients(altitude, + aerosol_absorption, + aerosol_scattering, + molecular_absorption, + molecular_scattering); + const float4 extinction = aerosol_absorption + aerosol_scattering + molecular_absorption + + molecular_scattering; + result += extinction * t_step; + } + + return exp(-result); + } + + /* Compute in-scattered radiance for the given ray. */ + float4 get_inscattering(const float3 sun_dir, + const float3 ray_origin, + const float3 ray_dir, + const float t_d) const + { + const float cos_theta = dot(-ray_dir, sun_dir); + const float molecular_phase = molecular_phase_function(cos_theta); + const float aerosol_phase = aerosol_phase_function(cos_theta); + const float dt = t_d / IN_SCATTERING_STEPS; + float4 L_inscattering = make_float4(0.0f, 0.0f, 0.0f, 0.0f); + float4 transmittance = make_float4(1.0f, 1.0f, 1.0f, 1.0f); + for (int i = 0; i < IN_SCATTERING_STEPS; i++) { + const float t = (i + 0.5f) * dt; + const float3 x_t = ray_origin + ray_dir * t; + const float distance_to_earth_center = x_t.length(); + const float3 zenith_dir = x_t / distance_to_earth_center; + const float altitude = fmaxf(distance_to_earth_center - EARTH_RADIUS, 0.0f); + const float normalized_altitude = altitude / ATMOSPHERE_THICKNESS; + const float sample_cos_theta = dot(zenith_dir, sun_dir); + float4 aerosol_absorption, aerosol_scattering, molecular_absorption, molecular_scattering; + get_atmosphere_collision_coefficients(altitude, + aerosol_absorption, + aerosol_scattering, + molecular_absorption, + molecular_scattering); + const float4 extinction = aerosol_absorption + aerosol_scattering + molecular_absorption + + molecular_scattering; + const float4 transmittance_to_sun = lookup_transmittance(sample_cos_theta, + normalized_altitude); + const float4 ms = lookup_multiscattering( + sample_cos_theta, normalized_altitude, distance_to_earth_center); + const float4 S = SUN_SPECTRAL_IRRADIANCE * + (molecular_scattering * (molecular_phase * transmittance_to_sun + ms) + + aerosol_scattering * (aerosol_phase * transmittance_to_sun + ms)); + const float4 step_transmittance = exp(-dt * extinction); + /* Energy-conserving analytical integration "Physically Based Sky, Atmosphere and Cloud + * Rendering in Frostbite" by Sébastien Hillaire. */ + const float4 cut_ext = max(extinction, 1e-7f); + const float4 S_int = (S - S * step_transmittance) / cut_ext; + L_inscattering = L_inscattering + transmittance * S_int; + transmittance *= step_transmittance; + } + + return L_inscattering; + } + + /* Precompute the transmittance LUT. Must be called before get_inscattering(). */ + void precompute_lut() + { + SKY_parallel_for(0, TRANSMITTANCE_RES_Y, 4, [&](const size_t begin, const size_t end) { + for (int y = begin; y < end; y++) { + for (int x = 0; x < TRANSMITTANCE_RES_X; x++) { + const float2 uv = make_float2(x / float(TRANSMITTANCE_RES_X - 1), + y / float(TRANSMITTANCE_RES_Y - 1)); + transmittance_lut[y][x] = get_transmittance(uv.x * 2.0f - 1.0f, uv.y); + } + } + }); + } + + protected: + float4 transmittance_lut[TRANSMITTANCE_RES_Y][TRANSMITTANCE_RES_X]; + float air_density; + float aerosol_density; + float ozone_density; + + /* Compute absorption/scattering coeffients at the given altitude. */ + inline void get_atmosphere_collision_coefficients(const float altitude, + float4 &aerosol_absorption, + float4 &aerosol_scattering, + float4 &molecular_absorption, + float4 &molecular_scattering) const + { + const float local_aerosol_density = get_aerosol_density(altitude) * aerosol_density; + aerosol_absorption = AEROSOL_ABSORPTION_CROSS_SECTION * local_aerosol_density; + aerosol_scattering = AEROSOL_SCATTERING_CROSS_SECTION * local_aerosol_density; + molecular_absorption = get_molecular_absorption_coefficient(altitude) * ozone_density; + molecular_scattering = get_molecular_scattering_coefficient(altitude) * air_density; + } + + inline float4 lookup_multiscattering(float cos_theta, float normalized_height, float d) const + { + /* Solid angle subtended by the planet from a point at d distance from the planet center. */ + const float omega = M_2PI_F * (1.0f - sqrtf(1.0f - sqr(EARTH_RADIUS / d))); + const float4 T_to_ground = lookup_transmittance_at_ground(cos_theta); + /* We can split the path into Ground <-> Sample <-> Sun. + * The LUT gives us both T(Sample,Sun) and T(Ground,Sun) = T(Ground,Sample)*T(Sample,Sun), + * so we can easily compute T(Ground,Sample) from those two. */ + const float4 T_ground_to_sample = lookup_transmittance_to_sun(0.0f) / + lookup_transmittance_to_sun(normalized_height); + /* 2nd order scattering from the ground. */ + const float4 L_ground = PHASE_ISOTROPIC * omega * (GROUND_ALBEDO * M_1_PI_F) * T_to_ground * + T_ground_to_sample * cos_theta; + /* Fit of Earth's multiple scattering coming from other points in the atmosphere. */ + const float4 L_ms = 0.02f * make_float4(0.217f, 0.347f, 0.594f, 1.0f) * + (1.0f / (1.0f + 5.0f * expf(-17.92f * cos_theta))); + return L_ms + L_ground; + } + + /* Look up a transmittance from the precomputed LUT. */ + inline float4 lookup_transmittance(const float cos_theta, const float normalized_altitude) const + { + const float u = saturate(cos_theta * 0.5f + 0.5f); + const float v = saturate(normalized_altitude); + const float x = float(TRANSMITTANCE_RES_X - 1) * u; + const float y = float(TRANSMITTANCE_RES_Y - 1) * v; + const int x1 = int(x); + const int y1 = int(y); + const int x2 = min(x1 + 1, TRANSMITTANCE_RES_X - 1); + const int y2 = min(y1 + 1, TRANSMITTANCE_RES_Y - 1); + const float fx = x - x1; + const float fy = y - y1; + const float4 bottom = mix(transmittance_lut[y1][x1], transmittance_lut[y1][x2], fx); + const float4 top = mix(transmittance_lut[y2][x1], transmittance_lut[y2][x2], fx); + return mix(bottom, top, fy); + } + + /* Specialized versions of lookup_transmittance that skip one interpolation. */ + inline float4 lookup_transmittance_at_ground(const float cos_theta) const + { + const float u = saturate(cos_theta * 0.5f + 0.5f); + const float x = float(TRANSMITTANCE_RES_X - 1) * u; + const int x1 = int(x); + const int x2 = min(x1 + 1, TRANSMITTANCE_RES_X - 1); + const int y = 0; + const float fx = x - x1; + return mix(transmittance_lut[y][x1], transmittance_lut[y][x2], fx); + } + + inline float4 lookup_transmittance_to_sun(const float normalized_altitude) const + { + const float v = saturate(normalized_altitude); + const float y = float(TRANSMITTANCE_RES_Y - 1) * v; + const int x = TRANSMITTANCE_RES_X - 1; + const int y1 = int(y); + const int y2 = min(y1 + 1, TRANSMITTANCE_RES_Y - 1); + const float fy = y - y1; + return mix(transmittance_lut[y1][x], transmittance_lut[y2][x], fy); + } +}; + +void SKY_multiple_scattering_precompute_texture(float *pixels, + int stride, + int width, + int height, + float sun_elevation, + float altitude, + float air_density, + float aerosol_density, + float ozone_density) +{ + SkyMultipleScattering sms(air_density, aerosol_density, ozone_density); + sms.precompute_lut(); + + /* Clamp altitude to avoid numerical issues. */ + altitude = clamp(altitude, 1.0f, 99999.0f) / 1000.0f; + const int half_width = width / 2; + const float sun_zenith_cos_angle = cosf(M_PI_2_F - sun_elevation); + const float3 sun_dir = sun_direction(sun_zenith_cos_angle); + const int rows_per_task = std::max(1024 / width, 1); + + SKY_parallel_for(0, height, rows_per_task, [=](const size_t begin, const size_t end) { + for (int y = begin; y < end; y++) { + float *pixel_row = pixels + (y * width * stride); + for (int x = 0; x < half_width; x++) { + float2 uv = make_float2((x + 0.5f) / width, (y + 0.5f) / height); + + const float azimuth = M_2PI_F * uv.x; + /* Apply a non-linear transformation to the elevation to dedicate more texels to the + * horizon, where having more detail matters. */ + const float l = uv.y * 2.0f - 1.0f; + /* [-pi/2, pi/2]. */ + const float elev = copysignf(sqr(l), l) * M_PI_2_F; + const float3 ray_dir = make_float3( + cosf(elev) * cosf(azimuth), cosf(elev) * sinf(azimuth), sinf(elev)); + const float3 ray_origin = make_float3(0.0f, 0.0f, EARTH_RADIUS + altitude); + const float atmos_dist = ray_sphere_intersection(ray_origin, ray_dir, ATMOSPHERE_RADIUS); + const float ground_dist = ray_sphere_intersection(ray_origin, ray_dir, EARTH_RADIUS); + /* If no ground collision then use the distance to the outer atmosphere, else we have a + * collision with the ground so we use the distance to it. */ + const float t_d = (ground_dist < 0.0f) ? atmos_dist : ground_dist; + const float4 L = sms.get_inscattering(sun_dir, ray_origin, ray_dir, t_d); + const float3 sky = spectral_to_xyz(L); + + /* Store pixels. */ + const int pos_x = x * stride; + pixel_row[pos_x] = sky.x; + pixel_row[pos_x + 1] = sky.y; + pixel_row[pos_x + 2] = sky.z; + /* Mirror pixels. */ + const int mirror_x = (width - x - 1) * stride; + pixel_row[mirror_x] = sky.x; + pixel_row[mirror_x + 1] = sky.y; + pixel_row[mirror_x + 2] = sky.z; + } + } + }); +} + +void SKY_multiple_scattering_precompute_sun(float sun_elevation, + float angular_diameter, + float altitude, + float air_density, + float aerosol_density, + float ozone_density, + float r_pixel_bottom[3], + float r_pixel_top[3]) +{ + const SkyMultipleScattering sms(air_density, aerosol_density, ozone_density); + + /* Clamp altitude to avoid numerical issues. */ + altitude = clamp(altitude, 1.0f, 99999.0f) / 1000.0f; + const float half_angular = angular_diameter / 2.0f; + const float solid_angle = M_2PI_F * (1.0f - cosf(half_angular)); + const float normalized_altitude = altitude / ATMOSPHERE_THICKNESS; + + /* Compute 2 pixels for Sun disc: one is the lowest point of the disc, one is the highest. */ + auto get_sun_xyz = [&](const float elevation) { + const float sun_zenith_cos_angle = cosf(M_PI_2_F - elevation); + const float4 transmittance_to_sun = sms.get_transmittance(sun_zenith_cos_angle, + normalized_altitude); + const float4 spectrum = SUN_SPECTRAL_IRRADIANCE * transmittance_to_sun / solid_angle; + return spectral_to_xyz(spectrum); + }; + const float3 bottom = get_sun_xyz(sun_elevation - half_angular); + const float3 top = get_sun_xyz(sun_elevation + half_angular); + + /* Store pixels */ + r_pixel_bottom[0] = bottom.x; + r_pixel_bottom[1] = bottom.y; + r_pixel_bottom[2] = bottom.z; + r_pixel_top[0] = top.x; + r_pixel_top[1] = top.y; + r_pixel_top[2] = top.z; +} + +float SKY_earth_intersection_angle(float altitude) +{ + /* Calculate intersection angle between line passing through viewpoint and Earth surface. */ + return M_PI_2_F - asinf(EARTH_RADIUS / (EARTH_RADIUS + altitude / 1000.0f)); +} diff --git a/intern/sky/source/sky_nishita.cpp b/intern/sky/source/sky_single_scattering.cpp similarity index 58% rename from intern/sky/source/sky_nishita.cpp rename to intern/sky/source/sky_single_scattering.cpp index 9dead7d3f18..c25073984a1 100644 --- a/intern/sky/source/sky_nishita.cpp +++ b/intern/sky/source/sky_single_scattering.cpp @@ -6,25 +6,27 @@ * \ingroup intern_sky_modal */ -#include "sky_float3.h" +#include + +#include "sky_math.h" #include "sky_model.h" -/* Constants */ -static const float rayleigh_scale = 8e3f; /* Rayleigh scale height (m). */ -static const float mie_scale = 1.2e3f; /* Mie scale height (m). */ -static const float mie_coeff = 2e-5f; /* Mie scattering coefficient (m^-1). */ -static const float mie_G = 0.76f; /* aerosols anisotropy. */ -static const float sqr_G = mie_G * mie_G; /* squared aerosols anisotropy. */ -static const float earth_radius = 6360e3f; /* radius of Earth (m). */ -static const float atmosphere_radius = 6420e3f; /* radius of atmosphere (m). */ -static const int steps = 32; /* segments of primary ray. */ -static const int num_wavelengths = 21; /* number of wavelengths. */ -static const int min_wavelength = 380; /* lowest sampled wavelength (nm). */ -static const int max_wavelength = 780; /* highest sampled wavelength (nm). */ +/* Constants. */ +static const float RAYLEIGH_SCALE = 8e3f; /* Rayleigh scale height (m). */ +static const float MIE_SCALE = 1.2e3f; /* Mie scale height (m). */ +static const float MIE_COEFF = 2e-5f; /* Mie scattering coefficient (m^-1). */ +static const float MIE_G = 0.76f; /* Aerosols anisotropy. */ +static const float SQR_G = MIE_G * MIE_G; /* Squared aerosols anisotropy. */ +static const float EARTH_RADIUS = 6360e3f; /* Radius of Earth (m). */ +static const float ATMOSPHERE_RADIUS = 6420e3f; /* Radius of atmosphere (m). */ +static const int STEPS = 32; /* Segments of primary ray. */ +static const int NUM_WAVELENGTHS = 21; /* Number of wavelengths. */ +static const int MIN_WAVELENGTH = 380; /* Lowest sampled wavelength (nm). */ +static const int MAX_WAVELENGTH = 780; /* Highest sampled wavelength (nm). */ /* Step between each sampled wavelength (nm). */ -static const float step_lambda = (max_wavelength - min_wavelength) / (num_wavelengths - 1); -/* Sun irradiance on top of the atmosphere (W*m^-2*nm^-1) */ -static const float irradiance[] = { +static const float STEP_LAMBDA = (MAX_WAVELENGTH - MIN_WAVELENGTH) / (NUM_WAVELENGTHS - 1); +/* Sun irradiance on top of the atmosphere (W*m^-2*nm^-1). */ +static const float IRRADIANCE[] = { 1.45756829855592995315f, 1.56596305559738380175f, 1.65148449067670455293f, 1.71496242737209314555f, 1.75797983805020541226f, 1.78256407885924539336f, 1.79095108475838560302f, 1.78541550133410664714f, 1.76815554864306845317f, @@ -32,8 +34,8 @@ static const float irradiance[] = { 1.61993437242451854274f, 1.57083597368892080581f, 1.51932335059305478886f, 1.46628494965214395407f, 1.41245852740172450623f, 1.35844961970384092709f, 1.30474913844739281998f, 1.25174963272610817455f, 1.19975998755420620867f}; -/* Rayleigh scattering coefficient (m^-1) */ -static const float rayleigh_coeff[] = { +/* Rayleigh scattering coefficient (m^-1). */ +static const float RAYLEIGH_COEFF[] = { 0.00005424820087636473f, 0.00004418549866505454f, 0.00003635151910165377f, 0.00003017929012024763f, 0.00002526320226989157f, 0.00002130859310621843f, 0.00001809838025320633f, 0.00001547057129129042f, 0.00001330284977336850f, @@ -41,8 +43,8 @@ static const float rayleigh_coeff[] = { 0.00000765513700977967f, 0.00000674217203751443f, 0.00000596134125832052f, 0.00000529034598065810f, 0.00000471115687557433f, 0.00000420910481110487f, 0.00000377218381260133f, 0.00000339051255477280f, 0.00000305591531679811f}; -/* Ozone absorption coefficient (m^-1) */ -static const float ozone_coeff[] = { +/* Ozone absorption coefficient (m^-1). */ +static const float OZONE_COEFF[] = { 0.00000000325126849861f, 0.00000000585395365047f, 0.00000001977191155085f, 0.00000007309568762914f, 0.00000020084561514287f, 0.00000040383958096161f, 0.00000063551335912363f, 0.00000096707041180970f, 0.00000154797400424410f, @@ -50,8 +52,8 @@ static const float ozone_coeff[] = { 0.00000215125863128643f, 0.00000159051840791988f, 0.00000112356197979857f, 0.00000073527551487574f, 0.00000046450130357806f, 0.00000033096079921048f, 0.00000022512612292678f, 0.00000014879129266490f, 0.00000016828623364192f}; -/* CIE XYZ color matching functions */ -static const float cmf_xyz[][3] = {{0.00136800000f, 0.00003900000f, 0.00645000100f}, +/* CIE XYZ color matching functions. */ +static const float CMF_XYZ[][3] = {{0.00136800000f, 0.00003900000f, 0.00645000100f}, {0.01431000000f, 0.00039600000f, 0.06785001000f}, {0.13438000000f, 0.00400000000f, 0.64560000000f}, {0.34828000000f, 0.02300000000f, 1.74706000000f}, @@ -83,8 +85,8 @@ static const float cmf_xyz[][3] = {{0.00136800000f, 0.00003900000f, 0.0064500010 * # print([(xi / xend).evalf(10) for xi in x]) * # print([(wi * exp(xi) / xend).evalf(10) for xi, wi in zip(x, w)]) */ -static const int quadrature_steps = 8; -static const float quadrature_nodes[] = {0.006811185292f, +static const int QUADRATURE_STEPS = 8; +static const float QUADRATURE_NODES[] = {0.006811185292f, 0.03614807107f, 0.09004346519f, 0.1706680068f, @@ -92,7 +94,7 @@ static const float quadrature_nodes[] = {0.006811185292f, 0.4303406404f, 0.6296271457f, 0.9145252695f}; -static const float quadrature_weights[] = {0.01750893642f, +static const float QUADRATURE_WEIGHTS[] = {0.01750893642f, 0.04135477391f, 0.06678839063f, 0.09507698807f, @@ -109,56 +111,49 @@ static float3 geographical_to_direction(float lat, float lon) static float3 spec_to_xyz(const float *spectrum) { float3 xyz = make_float3(0.0f, 0.0f, 0.0f); - for (int i = 0; i < num_wavelengths; i++) { - xyz.x += cmf_xyz[i][0] * spectrum[i]; - xyz.y += cmf_xyz[i][1] * spectrum[i]; - xyz.z += cmf_xyz[i][2] * spectrum[i]; + for (int i = 0; i < NUM_WAVELENGTHS; i++) { + xyz.x += CMF_XYZ[i][0] * spectrum[i]; + xyz.y += CMF_XYZ[i][1] * spectrum[i]; + xyz.z += CMF_XYZ[i][2] * spectrum[i]; } - return xyz * step_lambda; + return xyz * STEP_LAMBDA; } /* Atmosphere volume models */ static float density_rayleigh(float height) { - return expf(-height / rayleigh_scale); + return expf(-height / RAYLEIGH_SCALE); } static float density_mie(float height) { - return expf(-height / mie_scale); + return expf(-height / MIE_SCALE); } static float density_ozone(float height) { - float den = 0.0f; - if (height >= 10000.0f && height < 25000.0f) { - den = 1.0f / 15000.0f * height - 2.0f / 3.0f; - } - else if (height >= 25000 && height < 40000) { - den = -(1.0f / 15000.0f * height - 8.0f / 3.0f); - } - return den; + return fmax(0.0, 1.0 - (fabs(height - 25000.0) / 15000.0)); } static float phase_rayleigh(float mu) { - return 3.0f / (16.0f * M_PI_F) * (1.0f + sqr(mu)); + return (0.1875f * M_1_PI_F) * (1.0f + sqr(mu)); } static float phase_mie(float mu) { - return (3.0f * (1.0f - sqr_G) * (1.0f + sqr(mu))) / - (8.0f * M_PI_F * (2.0f + sqr_G) * powf((1.0f + sqr_G - 2.0f * mie_G * mu), 1.5)); + return (3.0f * (1.0f - SQR_G) * (1.0f + sqr(mu))) / + (8.0f * M_PI_F * (2.0f + SQR_G) * powf((1.0f + SQR_G - 2.0f * MIE_G * mu), 1.5)); } -/* Intersection helpers */ +/* Intersection helpers. */ static bool surface_intersection(float3 pos, float3 dir) { if (dir.z >= 0) { return false; } float b = -2.0f * dot(dir, -pos); - float c = len_squared(pos) - sqr(earth_radius); + float c = len_squared(pos) - sqr(EARTH_RADIUS); float t = b * b - 4.0f * c; if (t >= 0.0f) { return true; @@ -169,7 +164,7 @@ static bool surface_intersection(float3 pos, float3 dir) static float3 atmosphere_intersection(float3 pos, float3 dir) { float b = -2.0f * dot(dir, -pos); - float c = len_squared(pos) - sqr(atmosphere_radius); + float c = len_squared(pos) - sqr(ATMOSPHERE_RADIUS); float t = (-b + sqrtf(b * b - 4.0f * c)) / 2.0f; return make_float3(pos.x + dir.x * t, pos.y + dir.y * t, pos.z + dir.z * t); } @@ -190,21 +185,21 @@ static float3 ray_optical_depth(float3 ray_origin, float3 ray_dir) float3 segment = ray_length * ray_dir; - /* instead of tracking the transmission spectrum across all wavelengths directly, + /* Instead of tracking the transmission spectrum across all wavelengths directly, * we use the fact that the density always has the same spectrum for each type of * scattering, so we split the density into a constant spectrum and a factor and - * only track the factors */ + * only track the factors. */ float3 optical_depth = make_float3(0.0f, 0.0f, 0.0f); - for (int i = 0; i < quadrature_steps; i++) { - float3 P = ray_origin + quadrature_nodes[i] * segment; + for (int i = 0; i < QUADRATURE_STEPS; i++) { + float3 P = ray_origin + QUADRATURE_NODES[i] * segment; - /* height above sea level */ - float height = len(P) - earth_radius; + /* Height above sea level. */ + float height = len(P) - EARTH_RADIUS; float3 density = make_float3( density_rayleigh(height), density_mie(height), density_ozone(height)); - optical_depth += density * quadrature_weights[i]; + optical_depth += density * QUADRATURE_WEIGHTS[i]; } return optical_depth * ray_length; @@ -214,63 +209,63 @@ static void single_scattering(float3 ray_dir, float3 sun_dir, float3 ray_origin, float air_density, - float dust_density, + float aerosol_density, float ozone_density, float *r_spectrum) { - /* this code computes single-inscattering along a ray through the atmosphere */ + /* This code computes single-inscattering along a ray through the atmosphere. */ float3 ray_end = atmosphere_intersection(ray_origin, ray_dir); float ray_length = distance(ray_origin, ray_end); - /* to compute the inscattering, we step along the ray in segments and accumulate - * the inscattering as well as the optical depth along each segment */ - float segment_length = ray_length / steps; + /* To compute the inscattering, we step along the ray in segments and accumulate + * the inscattering as well as the optical depth along each segment. */ + float segment_length = ray_length / STEPS; float3 segment = segment_length * ray_dir; - /* instead of tracking the transmission spectrum across all wavelengths directly, + /* Instead of tracking the transmission spectrum across all wavelengths directly, * we use the fact that the density always has the same spectrum for each type of * scattering, so we split the density into a constant spectrum and a factor and - * only track the factors */ + * only track the factors. */ float3 optical_depth = make_float3(0.0f, 0.0f, 0.0f); - /* zero out light accumulation */ - for (int wl = 0; wl < num_wavelengths; wl++) { + /* Zero out light accumulation. */ + for (int wl = 0; wl < NUM_WAVELENGTHS; wl++) { r_spectrum[wl] = 0.0f; } - /* phase function for scattering and the density scale factor */ + /* Phase function for scattering and the density scale factor. */ float mu = dot(ray_dir, sun_dir); float3 phase_function = make_float3(phase_rayleigh(mu), phase_mie(mu), 0.0f); - float3 density_scale = make_float3(air_density, dust_density, ozone_density); + float3 density_scale = make_float3(air_density, aerosol_density, ozone_density); - /* the density and in-scattering of each segment is evaluated at its middle */ + /* The density and in-scattering of each segment is evaluated at its middle. */ float3 P = ray_origin + 0.5f * segment; - for (int i = 0; i < steps; i++) { - /* height above sea level */ - float height = len(P) - earth_radius; + for (int i = 0; i < STEPS; i++) { + /* Height above sea level. */ + float height = len(P) - EARTH_RADIUS; - /* evaluate and accumulate optical depth along the ray */ + /* Evaluate and accumulate optical depth along the ray. */ float3 density = density_scale * make_float3(density_rayleigh(height), density_mie(height), density_ozone(height)); optical_depth += segment_length * density; - /* if the Earth isn't in the way, evaluate inscattering from the sun */ + /* If the Earth isn't in the way, evaluate inscattering from the Sun. */ if (!surface_intersection(P, sun_dir)) { float3 light_optical_depth = density_scale * ray_optical_depth(P, sun_dir); float3 total_optical_depth = optical_depth + light_optical_depth; - /* attenuation of light */ - for (int wl = 0; wl < num_wavelengths; wl++) { - float3 extinction_density = total_optical_depth * make_float3(rayleigh_coeff[wl], - 1.11f * mie_coeff, - ozone_coeff[wl]); + /* Attenuation of light. */ + for (int wl = 0; wl < NUM_WAVELENGTHS; wl++) { + float3 extinction_density = total_optical_depth * make_float3(RAYLEIGH_COEFF[wl], + 1.11f * MIE_COEFF, + OZONE_COEFF[wl]); float attenuation = expf(-reduce_add(extinction_density)); - float3 scattering_density = density * make_float3(rayleigh_coeff[wl], mie_coeff, 0.0f); + float3 scattering_density = density * make_float3(RAYLEIGH_COEFF[wl], MIE_COEFF, 0.0f); - /* the total inscattered radiance from one segment is: + /* The total inscattered radiance from one segment is: * Tr(A<->B) * Tr(B<->C) * sigma_s * phase * L * segment_length * * These terms are: @@ -284,111 +279,126 @@ static void single_scattering(float3 ray_dir, * spectra for the optical depth */ r_spectrum[wl] += attenuation * reduce_add(phase_function * scattering_density) * - irradiance[wl] * segment_length; + IRRADIANCE[wl] * segment_length; } } - /* advance along ray */ + /* Advance along ray. */ P += segment; } } -void SKY_nishita_skymodel_precompute_texture(float *pixels, - int stride, - int start_y, - int end_y, - int width, - int height, - float sun_elevation, - float altitude, - float air_density, - float dust_density, - float ozone_density) +void SKY_single_scattering_precompute_texture(float *pixels, + int stride, + int width, + int height, + float sun_elevation, + float altitude, + float air_density, + float aerosol_density, + float ozone_density) { - /* calculate texture pixels */ - float spectrum[num_wavelengths]; - int half_width = width / 2; - float3 cam_pos = make_float3(0, 0, earth_radius + altitude); - float3 sun_dir = geographical_to_direction(sun_elevation, 0.0f); + /* Clamp altitude to avoid numerical issues. */ + altitude = clamp(altitude, 1.0f, 59999.0f); + /* Calculate texture pixels. */ + const int half_width = width / 2; + const int half_height = height / 2; + const float3 cam_pos = make_float3(0, 0, EARTH_RADIUS + altitude); + const float3 sun_dir = geographical_to_direction(sun_elevation, 0.0f); + const float longitude_step = M_2PI_F / width; + const int rows_per_task = std::max(1024 / width, 1); - float latitude_step = M_PI_2_F / height; - float longitude_step = M_2PI_F / width; - float half_lat_step = latitude_step / 2.0f; + SKY_parallel_for(0, height, rows_per_task, [=](const size_t begin, const size_t end) { + for (int y = begin; y < end; y++) { + /* Sample more pixels toward the horizon. */ + float latitude = M_PI_2_F * sqr(float(y) / half_height - 1.0f); + float *pixel_row = pixels + (y * width * stride); - for (int y = start_y; y < end_y; y++) { - /* sample more pixels toward the horizon */ - float latitude = (M_PI_2_F + half_lat_step) * sqr(float(y) / height); + for (int x = 0; x < half_width; x++) { + float3 xyz; + if (y > half_height) { + float longitude = longitude_step * x - M_PI_F; + float3 dir = geographical_to_direction(latitude, longitude); + float spectrum[NUM_WAVELENGTHS]; + single_scattering( + dir, sun_dir, cam_pos, air_density, aerosol_density, ozone_density, spectrum); + xyz = spec_to_xyz(spectrum); + } + else { + xyz = make_float3(0.0f, 0.0f, 0.0f); + } - float *pixel_row = pixels + (y * width * stride); - for (int x = 0; x < half_width; x++) { - float longitude = longitude_step * x - M_PI_F; - - float3 dir = geographical_to_direction(latitude, longitude); - single_scattering(dir, sun_dir, cam_pos, air_density, dust_density, ozone_density, spectrum); - float3 xyz = spec_to_xyz(spectrum); - - /* store pixels */ - int pos_x = x * stride; - pixel_row[pos_x] = xyz.x; - pixel_row[pos_x + 1] = xyz.y; - pixel_row[pos_x + 2] = xyz.z; - /* mirror sky */ - int mirror_x = (width - x - 1) * stride; - pixel_row[mirror_x] = xyz.x; - pixel_row[mirror_x + 1] = xyz.y; - pixel_row[mirror_x + 2] = xyz.z; + /* Store pixels. */ + int pos_x = x * stride; + pixel_row[pos_x] = xyz.x; + pixel_row[pos_x + 1] = xyz.y; + pixel_row[pos_x + 2] = xyz.z; + /* Mirror sky. */ + int mirror_x = (width - x - 1) * stride; + pixel_row[mirror_x] = xyz.x; + pixel_row[mirror_x + 1] = xyz.y; + pixel_row[mirror_x + 2] = xyz.z; + } } - } + }); } /*********** Sun ***********/ static void sun_radiation(float3 cam_dir, float altitude, float air_density, - float dust_density, + float aerosol_density, float solid_angle, float *r_spectrum) { - float3 cam_pos = make_float3(0, 0, earth_radius + altitude); + float3 cam_pos = make_float3(0, 0, EARTH_RADIUS + altitude); float3 optical_depth = ray_optical_depth(cam_pos, cam_dir); - /* compute final spectrum */ - for (int i = 0; i < num_wavelengths; i++) { - /* combine spectra and the optical depth into transmittance */ - float transmittance = rayleigh_coeff[i] * optical_depth.x * air_density + - 1.11f * mie_coeff * optical_depth.y * dust_density; - r_spectrum[i] = irradiance[i] * expf(-transmittance) / solid_angle; + /* Compute final spectrum. */ + for (int i = 0; i < NUM_WAVELENGTHS; i++) { + /* Combine spectra and the optical depth into transmittance. */ + float transmittance = RAYLEIGH_COEFF[i] * optical_depth.x * air_density + + 1.11f * MIE_COEFF * optical_depth.y * aerosol_density; + r_spectrum[i] = IRRADIANCE[i] * expf(-transmittance) / solid_angle; } } -void SKY_nishita_skymodel_precompute_sun(float sun_elevation, - float angular_diameter, - float altitude, - float air_density, - float dust_density, - float *r_pixel_bottom, - float *r_pixel_top) +void SKY_single_scattering_precompute_sun(float sun_elevation, + float angular_diameter, + float altitude, + float air_density, + float aerosol_density, + float r_pixel_bottom[3], + float r_pixel_top[3]) { - /* definitions */ + /* Clamp altitude to avoid numerical issues. */ + altitude = clamp(altitude, 1.0f, 59999.0f); float half_angular = angular_diameter / 2.0f; float solid_angle = M_2PI_F * (1.0f - cosf(half_angular)); - float spectrum[num_wavelengths]; + float spectrum[NUM_WAVELENGTHS]; float bottom = sun_elevation - half_angular; float top = sun_elevation + half_angular; float elevation_bottom, elevation_top; float3 pix_bottom, pix_top, sun_dir; - /* compute 2 pixels for sun disc */ + /* Compute 2 pixels for Sun disc: one is the lowest point of the disc, one is the highest. + * Return black pixels if Sun is below horizon. */ elevation_bottom = (bottom > 0.0f) ? bottom : 0.0f; elevation_top = (top > 0.0f) ? top : 0.0f; - sun_dir = geographical_to_direction(elevation_bottom, 0.0f); - sun_radiation(sun_dir, altitude, air_density, dust_density, solid_angle, spectrum); - pix_bottom = spec_to_xyz(spectrum); - sun_dir = geographical_to_direction(elevation_top, 0.0f); - sun_radiation(sun_dir, altitude, air_density, dust_density, solid_angle, spectrum); - pix_top = spec_to_xyz(spectrum); + if (elevation_top > 0.0f) { + sun_dir = geographical_to_direction(elevation_bottom, 0.0f); + sun_radiation(sun_dir, altitude, air_density, aerosol_density, solid_angle, spectrum); + pix_bottom = spec_to_xyz(spectrum); + sun_dir = geographical_to_direction(elevation_top, 0.0f); + sun_radiation(sun_dir, altitude, air_density, aerosol_density, solid_angle, spectrum); + pix_top = spec_to_xyz(spectrum); + } + else { + pix_bottom = make_float3(0.0f, 0.0f, 0.0f); + pix_top = make_float3(0.0f, 0.0f, 0.0f); + } - /* store pixels */ + /* Store pixels. */ r_pixel_bottom[0] = pix_bottom.x; r_pixel_bottom[1] = pix_bottom.y; r_pixel_bottom[2] = pix_bottom.z; diff --git a/source/blender/blenloader/intern/versioning_290.cc b/source/blender/blenloader/intern/versioning_290.cc index e921d5f492b..642f5a67224 100644 --- a/source/blender/blenloader/intern/versioning_290.cc +++ b/source/blender/blenloader/intern/versioning_290.cc @@ -913,7 +913,7 @@ void blo_do_versions_290(FileData *fd, Library * /*lib*/, Main *bmain) tex->sun_rotation = 0.0f; tex->altitude = 0.0f; tex->air_density = 1.0f; - tex->dust_density = 1.0f; + tex->aerosol_density = 1.0f; tex->ozone_density = 1.0f; } } diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_sky.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_sky.glsl index eff05a674fb..107fb81072f 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_sky.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_sky.glsl @@ -2,67 +2,44 @@ * * SPDX-License-Identifier: GPL-2.0-or-later */ -float sky_angle_between(float thetav, float phiv, float theta, float phi) -{ - float cospsi = sin(thetav) * sin(theta) * cos(phi - phiv) + cos(thetav) * cos(theta); - - if (cospsi > 1.0f) { - return 0.0f; - } - if (cospsi < -1.0f) { - return M_PI; - } - - return acos(cospsi); -} - float3 sky_spherical_coordinates(float3 dir) { return float3(M_PI_2 - atan(dir.z, length(dir.xy)), atan(dir.x, dir.y), 0.0f); } -void node_tex_sky_nishita(float3 co, - float sun_rotation, - float3 xyz_to_r, - float3 xyz_to_g, - float3 xyz_to_b, - sampler2DArray ima, - float layer, - out float4 color) +void node_tex_sky(float3 co, + float sky_type, + float sun_rotation, + float3 xyz_to_r, + float3 xyz_to_g, + float3 xyz_to_b, + sampler2DArray ima, + float layer, + out float4 color) { float3 spherical = sky_spherical_coordinates(co); - float3 xyz; - if (co.z < -0.4f) { - /* too far below the horizon, just return black */ - color = float4(0, 0, 0, 1); + float dir_elevation = M_PI_2 - spherical.x; + float x = (spherical.y + M_PI + sun_rotation) / (2.0f * M_PI); + float fade = 1.0f; + float y; + + if (sky_type == 0.0f && co.z < -0.4f) { + /* Black ground if Single Scattering model */ + color = float4(0.0f, 0.0f, 0.0f, 1.0f); + return; + } + if (sky_type == 0.0f && co.z < 0.0f) { + /* Ground fade */ + fade = pow(1.0f + co.z * 2.5f, 3.0f); + y = 0.508f; } else { - /* evaluate longitudinal position on the map */ - constexpr float tau = 6.28318530717958647692f; - float x = (spherical.y + M_PI + sun_rotation) / tau; - if (x > 1.0f) { - x -= 1.0f; - } - - float fade; - float y; - if (co.z < 0.0f) { - /* we're below the horizon, so extend the map by blending from values at the horizon - * to zero according to a cubic falloff */ - fade = 1.0f + co.z * 2.5f; - fade = fade * fade * fade; - y = 0.0f; - } - else { - /* we're above the horizon, so compute the lateral position by inverting the remapped - * coordinates that are preserve to have more detail near the horizon. */ - fade = 1.0f; - y = sqrt((M_PI_2 - spherical.x) / M_PI_2); - } - - /* look up color in the precomputed map and convert to RGB */ - xyz = fade * texture(ima, float3(x, y, layer)).rgb; - color = float4(dot(xyz_to_r, xyz), dot(xyz_to_g, xyz), dot(xyz_to_b, xyz), 1); + /* Undo the non-linear transformation from the sky LUT. */ + float dir_elevation_abs = (dir_elevation < 0.0f) ? -dir_elevation : dir_elevation; + y = sqrt(dir_elevation_abs / M_PI_2) * sign(dir_elevation) * 0.5f + 0.5f; } + /* Look up color in the precomputed map and convert to RGB. */ + xyz = fade * texture(ima, float3(x, y, layer)).rgb; + color = float4(dot(xyz_to_r, xyz), dot(xyz_to_g, xyz), dot(xyz_to_b, xyz), 1.0f); } diff --git a/source/blender/makesdna/DNA_color_types.h b/source/blender/makesdna/DNA_color_types.h index 1950c0ddc97..8bf3ea1e1a4 100644 --- a/source/blender/makesdna/DNA_color_types.h +++ b/source/blender/makesdna/DNA_color_types.h @@ -19,7 +19,7 @@ #define CM_TOT 4 #define GPU_SKY_WIDTH 512 -#define GPU_SKY_HEIGHT 128 +#define GPU_SKY_HEIGHT 256 typedef struct CurveMapPoint { float x, y; diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index b03214190f9..f38e578a866 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -1466,7 +1466,7 @@ typedef struct NodeTexSky { float sun_rotation; float altitude; float air_density; - float dust_density; + float aerosol_density; float ozone_density; char sun_disc; char _pad[11]; @@ -2677,7 +2677,7 @@ enum { }; /* sky texture */ -enum { SHD_SKY_NISHITA = 0 }; +enum { SHD_SKY_SINGLE_SCATTERING = 0, SHD_SKY_MULTIPLE_SCATTERING = 1 }; /* environment texture */ enum { diff --git a/source/blender/makesdna/intern/dna_rename_defs.h b/source/blender/makesdna/intern/dna_rename_defs.h index 36adba13c3d..4ce150ff911 100644 --- a/source/blender/makesdna/intern/dna_rename_defs.h +++ b/source/blender/makesdna/intern/dna_rename_defs.h @@ -176,6 +176,7 @@ DNA_STRUCT_RENAME_MEMBER(NodeCryptomatte, num_inputs, inputs_num) DNA_STRUCT_RENAME_MEMBER(NodeCompositorFileOutput, base_path, directory) DNA_STRUCT_RENAME_MEMBER(NodeCompositorFileOutput, active_input, active_item_index) DNA_STRUCT_RENAME_MEMBER(NodeGeometryAttributeCapture, data_type, data_type_legacy) +DNA_STRUCT_RENAME_MEMBER(NodeTexSky, dust_density, aerosol_density) DNA_STRUCT_RENAME_MEMBER(NodesModifierData, simulation_bake_directory, bake_directory) DNA_STRUCT_RENAME_MEMBER(Object, col, color) DNA_STRUCT_RENAME_MEMBER(Object, dup_group, instance_collection) diff --git a/source/blender/makesrna/intern/rna_nodetree.cc b/source/blender/makesrna/intern/rna_nodetree.cc index d6e4fb851d0..91395eb0b15 100644 --- a/source/blender/makesrna/intern/rna_nodetree.cc +++ b/source/blender/makesrna/intern/rna_nodetree.cc @@ -4985,9 +4985,17 @@ static void def_sh_tex(BlenderRNA * /*brna*/, StructRNA *srna) static void def_sh_tex_sky(BlenderRNA *brna, StructRNA *srna) { static const EnumPropertyItem prop_sky_type[] = { - {SHD_SKY_NISHITA, "NISHITA", 0, "Nishita", "Nishita 1993 improved"}, - {0, nullptr, 0, nullptr, nullptr}, - }; + {SHD_SKY_SINGLE_SCATTERING, + "SINGLE_SCATTERING", + 0, + "Single Scattering", + "Single scattering sky model"}, + {SHD_SKY_MULTIPLE_SCATTERING, + "MULTIPLE_SCATTERING", + 0, + "Multiple Scattering", + "Multiple scattering sky model (more accurate)"}, + {0, nullptr, 0, nullptr, nullptr}}; PropertyRNA *prop; @@ -5013,7 +5021,7 @@ static void def_sh_tex_sky(BlenderRNA *brna, StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "sun_intensity", PROP_FLOAT, PROP_NONE); - RNA_def_property_ui_text(prop, "Sun Intensity", "Strength of sun"); + RNA_def_property_ui_text(prop, "Sun Intensity", "Strength of Sun"); RNA_def_property_range(prop, 0.0f, 1000.0f); RNA_def_property_float_default(prop, 1.0f); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); @@ -5030,42 +5038,35 @@ static void def_sh_tex_sky(BlenderRNA *brna, StructRNA *srna) prop = RNA_def_property(srna, "altitude", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_ui_text(prop, "Altitude", "Height from sea level"); - RNA_def_property_range(prop, 0.0f, 60000.0f); - RNA_def_property_ui_range(prop, 0.0f, 60000.0f, 10, 1); - RNA_def_property_float_default(prop, 0.0f); + RNA_def_property_range(prop, 0.0f, 100000.0f); + RNA_def_property_ui_range(prop, 0.0f, 100000.0f, 10, 1); + RNA_def_property_float_default(prop, 100.0f); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); - prop = RNA_def_property(srna, "air_density", PROP_FLOAT, PROP_FACTOR); + prop = RNA_def_property(srna, "air_density", PROP_FLOAT, PROP_NONE); RNA_def_property_ui_text(prop, "Air", "Density of air molecules.\n" - "\u2022 0 - No air.\n" - "\u2022 1 - Clear day atmosphere.\n" - "\u2022 2 - Highly polluted day"); - RNA_def_property_range(prop, 0.0f, 10.0f); + "0 means no air, 1 means urban city air"); + RNA_def_property_range(prop, 0.0f, 1000.0f); RNA_def_property_float_default(prop, 1.0f); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); - prop = RNA_def_property(srna, "dust_density", PROP_FLOAT, PROP_FACTOR); + prop = RNA_def_property(srna, "aerosol_density", PROP_FLOAT, PROP_NONE); RNA_def_property_ui_text(prop, - "Dust", - "Density of dust molecules and water droplets.\n" - "\u2022 0 - No dust.\n" - "\u2022 1 - Clear day atmosphere.\n" - "\u2022 5 - City like atmosphere.\n" - "\u2022 10 - Hazy day"); - RNA_def_property_range(prop, 0.0f, 10.0f); + "Aerosols", + "Density of dust, pollution and water droplets.\n" + "0 means no aerosols, 1 means urban city aerosols"); + RNA_def_property_range(prop, 0.0f, 1000.0f); RNA_def_property_float_default(prop, 1.0f); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); - prop = RNA_def_property(srna, "ozone_density", PROP_FLOAT, PROP_FACTOR); + prop = RNA_def_property(srna, "ozone_density", PROP_FLOAT, PROP_NONE); RNA_def_property_ui_text(prop, "Ozone", "Density of ozone layer.\n" - "\u2022 0 - No ozone.\n" - "\u2022 1 - Clear day atmosphere.\n" - "\u2022 2 - City like atmosphere"); - RNA_def_property_range(prop, 0.0f, 10.0f); + "0 means no ozone, 1 means urban city ozone"); + RNA_def_property_range(prop, 0.0f, 1000.0f); RNA_def_property_float_default(prop, 1.0f); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_sky.cc b/source/blender/nodes/shader/nodes/node_shader_tex_sky.cc index d47fdf4e0f1..0d316340e9b 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_sky.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_sky.cc @@ -32,31 +32,29 @@ static void node_shader_buts_tex_sky(uiLayout *layout, bContext *C, PointerRNA * { layout->prop(ptr, "sky_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE); - if (RNA_enum_get(ptr, "sky_type") == SHD_SKY_NISHITA) { - Scene *scene = CTX_data_scene(C); - if (BKE_scene_uses_blender_eevee(scene)) { - layout->label(RPT_("Sun disc not available in EEVEE"), ICON_ERROR); - } - layout->prop(ptr, "sun_disc", UI_ITEM_R_SPLIT_EMPTY_NAME, std::nullopt, ICON_NONE); - - uiLayout *col; - if (RNA_boolean_get(ptr, "sun_disc")) { - col = &layout->column(true); - col->prop(ptr, "sun_size", UI_ITEM_R_SPLIT_EMPTY_NAME, std::nullopt, ICON_NONE); - col->prop(ptr, "sun_intensity", UI_ITEM_R_SPLIT_EMPTY_NAME, std::nullopt, ICON_NONE); - } - - col = &layout->column(true); - col->prop(ptr, "sun_elevation", UI_ITEM_R_SPLIT_EMPTY_NAME, std::nullopt, ICON_NONE); - col->prop(ptr, "sun_rotation", UI_ITEM_R_SPLIT_EMPTY_NAME, std::nullopt, ICON_NONE); - - layout->prop(ptr, "altitude", UI_ITEM_R_SPLIT_EMPTY_NAME, std::nullopt, ICON_NONE); - - col = &layout->column(true); - col->prop(ptr, "air_density", UI_ITEM_R_SPLIT_EMPTY_NAME, std::nullopt, ICON_NONE); - col->prop(ptr, "dust_density", UI_ITEM_R_SPLIT_EMPTY_NAME, std::nullopt, ICON_NONE); - col->prop(ptr, "ozone_density", UI_ITEM_R_SPLIT_EMPTY_NAME, std::nullopt, ICON_NONE); + Scene *scene = CTX_data_scene(C); + if (BKE_scene_uses_blender_eevee(scene)) { + layout->label(RPT_("Sun disc not available in EEVEE"), ICON_ERROR); } + layout->prop(ptr, "sun_disc", UI_ITEM_R_SPLIT_EMPTY_NAME, std::nullopt, ICON_NONE); + + uiLayout *col; + if (RNA_boolean_get(ptr, "sun_disc")) { + col = &layout->column(true); + col->prop(ptr, "sun_size", UI_ITEM_R_SPLIT_EMPTY_NAME, std::nullopt, ICON_NONE); + col->prop(ptr, "sun_intensity", UI_ITEM_R_SPLIT_EMPTY_NAME, std::nullopt, ICON_NONE); + } + + col = &layout->column(true); + col->prop(ptr, "sun_elevation", UI_ITEM_R_SPLIT_EMPTY_NAME, std::nullopt, ICON_NONE); + col->prop(ptr, "sun_rotation", UI_ITEM_R_SPLIT_EMPTY_NAME, std::nullopt, ICON_NONE); + + layout->prop(ptr, "altitude", UI_ITEM_R_SPLIT_EMPTY_NAME, std::nullopt, ICON_NONE); + + col = &layout->column(true); + col->prop(ptr, "air_density", UI_ITEM_R_SPLIT_EMPTY_NAME, std::nullopt, ICON_NONE); + col->prop(ptr, "aerosol_density", UI_ITEM_R_SPLIT_EMPTY_NAME, std::nullopt, ICON_NONE); + col->prop(ptr, "ozone_density", UI_ITEM_R_SPLIT_EMPTY_NAME, std::nullopt, ICON_NONE); } static void node_shader_init_tex_sky(bNodeTree * /*ntree*/, bNode *node) @@ -69,11 +67,11 @@ static void node_shader_init_tex_sky(bNodeTree * /*ntree*/, bNode *node) tex->sun_intensity = 1.0f; tex->sun_elevation = DEG2RADF(15.0f); tex->sun_rotation = 0.0f; - tex->altitude = 0.0f; + tex->altitude = 100.0f; tex->air_density = 1.0f; - tex->dust_density = 1.0f; + tex->aerosol_density = 1.0f; tex->ozone_density = 1.0f; - tex->sky_model = SHD_SKY_NISHITA; + tex->sky_model = SHD_SKY_MULTIPLE_SCATTERING; node->storage = tex; } @@ -86,24 +84,30 @@ static int node_shader_gpu_tex_sky(GPUMaterial *mat, node_shader_gpu_default_tex_coord(mat, node, &in[0].link); node_shader_gpu_tex_mapping(mat, node, in, out); NodeTexSky *tex = (NodeTexSky *)node->storage; - - /* Nishita */ - Array pixels(4 * GPU_SKY_WIDTH * GPU_SKY_HEIGHT); - threading::parallel_for(IndexRange(GPU_SKY_HEIGHT), 2, [&](IndexRange range) { - SKY_nishita_skymodel_precompute_texture(pixels.data(), - 4, - range.first(), - range.one_after_last(), - GPU_SKY_WIDTH, - GPU_SKY_HEIGHT, - tex->sun_elevation, - tex->altitude, - tex->air_density, - tex->dust_density, - tex->ozone_density); - }); + if (tex->sky_model == SHD_SKY_SINGLE_SCATTERING) { + SKY_single_scattering_precompute_texture(pixels.data(), + 4, + GPU_SKY_WIDTH, + GPU_SKY_HEIGHT, + tex->sun_elevation, + tex->altitude, + tex->air_density, + tex->aerosol_density, + tex->ozone_density); + } + else { + SKY_multiple_scattering_precompute_texture(pixels.data(), + 4, + GPU_SKY_WIDTH, + GPU_SKY_HEIGHT, + tex->sun_elevation, + tex->altitude, + tex->air_density, + tex->aerosol_density, + tex->ozone_density); + } float sun_rotation = fmodf(tex->sun_rotation, 2.0f * M_PI); if (sun_rotation < 0.0f) { @@ -119,13 +123,15 @@ static int node_shader_gpu_tex_sky(GPUMaterial *mat, GPU_SAMPLER_EXTEND_MODE_REPEAT, GPU_SAMPLER_EXTEND_MODE_EXTEND}; float layer; + float sky_type = (tex->sky_model == SHD_SKY_SINGLE_SCATTERING) ? 0.0f : 1.0f; GPUNodeLink *sky_texture = GPU_image_sky( mat, GPU_SKY_WIDTH, GPU_SKY_HEIGHT, pixels.data(), &layer, sampler); return GPU_stack_link(mat, node, - "node_tex_sky_nishita", + "node_tex_sky", in, out, + GPU_constant(&sky_type), GPU_constant(&sun_rotation), GPU_uniform(xyz_to_rgb.r), GPU_uniform(xyz_to_rgb.g), @@ -139,8 +145,7 @@ static void node_shader_update_sky(bNodeTree *ntree, bNode *node) bNodeSocket *sockVector = bke::node_find_socket(*node, SOCK_IN, "Vector"); NodeTexSky *tex = (NodeTexSky *)node->storage; - bke::node_set_socket_availability( - *ntree, *sockVector, !(tex->sky_model == 0 && tex->sun_disc == 1)); + bke::node_set_socket_availability(*ntree, *sockVector, !(tex->sun_disc == 1)); } static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms) @@ -178,12 +183,11 @@ void register_node_type_sh_tex_sky() ntype.nclass = NODE_CLASS_TEXTURE; ntype.declare = file_ns::node_declare; ntype.draw_buttons = file_ns::node_shader_buts_tex_sky; - blender::bke::node_type_size_preset(ntype, blender::bke::eNodeSizePreset::Middle); + blender::bke::node_type_size_preset(ntype, blender::bke::eNodeSizePreset::Default); ntype.initfunc = file_ns::node_shader_init_tex_sky; blender::bke::node_type_storage( ntype, "NodeTexSky", node_free_standard_storage, node_copy_standard_storage); ntype.gpu_fn = file_ns::node_shader_gpu_tex_sky; - /* Remove vector input for Nishita sky model. */ ntype.updatefunc = file_ns::node_shader_update_sky; ntype.gather_link_search_ops = file_ns::node_gather_link_searches; diff --git a/tests/files/render/texture/cycles_renders/sky_multiple_decreased_disc_increased_air_aerosols.png b/tests/files/render/texture/cycles_renders/sky_multiple_decreased_disc_increased_air_aerosols.png new file mode 100644 index 00000000000..99c7955ec64 --- /dev/null +++ b/tests/files/render/texture/cycles_renders/sky_multiple_decreased_disc_increased_air_aerosols.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9b2091f154bf6f0b98c4e4da8cb7356580540fb083a3c556bd3f0637dd3652e6 +size 18572 diff --git a/tests/files/render/texture/cycles_renders/sky_multiple_default.png b/tests/files/render/texture/cycles_renders/sky_multiple_default.png new file mode 100644 index 00000000000..523b3f41737 --- /dev/null +++ b/tests/files/render/texture/cycles_renders/sky_multiple_default.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c7bfb650cfc7a70d4161217f2c04e54aff28ba365e97b2ee77c91945002260db +size 22810 diff --git a/tests/files/render/texture/cycles_renders/sky_multiple_increased_disc_ozone.png b/tests/files/render/texture/cycles_renders/sky_multiple_increased_disc_ozone.png new file mode 100644 index 00000000000..d8bb9245064 --- /dev/null +++ b/tests/files/render/texture/cycles_renders/sky_multiple_increased_disc_ozone.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cf12a1b8bf8a0eed486efad059b688c7c6e071bde7884d31f10a05b98195af3e +size 22593 diff --git a/tests/files/render/texture/cycles_renders/sky_multiple_no_disc_high_altitude.png b/tests/files/render/texture/cycles_renders/sky_multiple_no_disc_high_altitude.png new file mode 100644 index 00000000000..bf4e36ac1f6 --- /dev/null +++ b/tests/files/render/texture/cycles_renders/sky_multiple_no_disc_high_altitude.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1d866a934e36cdb76734c1ad156786397686fcadbc414aa8a173c48303b060c3 +size 21923 diff --git a/tests/files/render/texture/cycles_renders/sky_nishita_increased_disk_ozone.png b/tests/files/render/texture/cycles_renders/sky_nishita_increased_disk_ozone.png deleted file mode 100644 index 9e282cb1e2b..00000000000 --- a/tests/files/render/texture/cycles_renders/sky_nishita_increased_disk_ozone.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:edaebff7cd560446b2418bfab9691c156cab93c2da1c67ed32b2e98969f5169f -size 23516 diff --git a/tests/files/render/texture/cycles_renders/sky_nishita_decreased_disk_increased_air_dust.png b/tests/files/render/texture/cycles_renders/sky_single_decreased_disc_increased_air_aerosols.png similarity index 100% rename from tests/files/render/texture/cycles_renders/sky_nishita_decreased_disk_increased_air_dust.png rename to tests/files/render/texture/cycles_renders/sky_single_decreased_disc_increased_air_aerosols.png diff --git a/tests/files/render/texture/cycles_renders/sky_nishita_default.png b/tests/files/render/texture/cycles_renders/sky_single_default.png similarity index 100% rename from tests/files/render/texture/cycles_renders/sky_nishita_default.png rename to tests/files/render/texture/cycles_renders/sky_single_default.png diff --git a/tests/files/render/texture/cycles_renders/sky_single_increased_disc_ozone.png b/tests/files/render/texture/cycles_renders/sky_single_increased_disc_ozone.png new file mode 100644 index 00000000000..e80198e1a18 --- /dev/null +++ b/tests/files/render/texture/cycles_renders/sky_single_increased_disc_ozone.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:28e2acd64e1d239abd25215ecf824b981b3bf3593df0b2133f7b390844c2f619 +size 23284 diff --git a/tests/files/render/texture/cycles_renders/sky_nishita_no_disk_high_altitude.png b/tests/files/render/texture/cycles_renders/sky_single_no_disc_high_altitude.png similarity index 100% rename from tests/files/render/texture/cycles_renders/sky_nishita_no_disk_high_altitude.png rename to tests/files/render/texture/cycles_renders/sky_single_no_disc_high_altitude.png diff --git a/tests/files/render/texture/eevee_renders/sky_hosek_wilkie.png b/tests/files/render/texture/eevee_renders/sky_hosek_wilkie.png deleted file mode 100644 index dec2681b06e..00000000000 --- a/tests/files/render/texture/eevee_renders/sky_hosek_wilkie.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8b6567d5fbb871b7f8516dd05e0dd9ba6d23c6d55273079fcfdc414b8c8432ce -size 20182 diff --git a/tests/files/render/texture/eevee_renders/sky_multiple_decreased_disc_increased_air_aerosols.png b/tests/files/render/texture/eevee_renders/sky_multiple_decreased_disc_increased_air_aerosols.png new file mode 100644 index 00000000000..9daec4d4a73 --- /dev/null +++ b/tests/files/render/texture/eevee_renders/sky_multiple_decreased_disc_increased_air_aerosols.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af4bcd2c58ab9098939eb28cc26c2cb3ba02118606f5a166d40920adea60fd70 +size 16486 diff --git a/tests/files/render/texture/eevee_renders/sky_multiple_default.png b/tests/files/render/texture/eevee_renders/sky_multiple_default.png new file mode 100644 index 00000000000..1c8dcae0fc7 --- /dev/null +++ b/tests/files/render/texture/eevee_renders/sky_multiple_default.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3234d0cf28988461a720d7a3fdec258b42785b64d59127f793b43aed1f00ffdc +size 18910 diff --git a/tests/files/render/texture/eevee_renders/sky_multiple_increased_disc_ozone.png b/tests/files/render/texture/eevee_renders/sky_multiple_increased_disc_ozone.png new file mode 100644 index 00000000000..5d499856c83 --- /dev/null +++ b/tests/files/render/texture/eevee_renders/sky_multiple_increased_disc_ozone.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c696f845c831c5bde5dea8ae57adc43c984aa48f9509af027a1dc5f4a64c7b2a +size 20016 diff --git a/tests/files/render/texture/eevee_renders/sky_multiple_no_disc_high_altitude.png b/tests/files/render/texture/eevee_renders/sky_multiple_no_disc_high_altitude.png new file mode 100644 index 00000000000..5f41017f0ce --- /dev/null +++ b/tests/files/render/texture/eevee_renders/sky_multiple_no_disc_high_altitude.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b862d5157472a201efa97c7f96a690b784728891d68019b94a590fbf3409c84b +size 18627 diff --git a/tests/files/render/texture/eevee_renders/sky_preetham.png b/tests/files/render/texture/eevee_renders/sky_preetham.png deleted file mode 100644 index 0abe2a72e01..00000000000 --- a/tests/files/render/texture/eevee_renders/sky_preetham.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3ada1a3c32460f6ae28833eaa5a9b727248bb442602f9b3b1269df9162cb0d97 -size 20082 diff --git a/tests/files/render/texture/eevee_renders/sky_nishita_decreased_disk_increased_air_dust.png b/tests/files/render/texture/eevee_renders/sky_single_decreased_disc_increased_air_aerosols.png similarity index 100% rename from tests/files/render/texture/eevee_renders/sky_nishita_decreased_disk_increased_air_dust.png rename to tests/files/render/texture/eevee_renders/sky_single_decreased_disc_increased_air_aerosols.png diff --git a/tests/files/render/texture/eevee_renders/sky_nishita_default.png b/tests/files/render/texture/eevee_renders/sky_single_default.png similarity index 100% rename from tests/files/render/texture/eevee_renders/sky_nishita_default.png rename to tests/files/render/texture/eevee_renders/sky_single_default.png diff --git a/tests/files/render/texture/eevee_renders/sky_nishita_increased_disk_ozone.png b/tests/files/render/texture/eevee_renders/sky_single_increased_disc_ozone.png similarity index 100% rename from tests/files/render/texture/eevee_renders/sky_nishita_increased_disk_ozone.png rename to tests/files/render/texture/eevee_renders/sky_single_increased_disc_ozone.png diff --git a/tests/files/render/texture/eevee_renders/sky_nishita_no_disk_high_altitude.png b/tests/files/render/texture/eevee_renders/sky_single_no_disc_high_altitude.png similarity index 100% rename from tests/files/render/texture/eevee_renders/sky_nishita_no_disk_high_altitude.png rename to tests/files/render/texture/eevee_renders/sky_single_no_disc_high_altitude.png diff --git a/tests/files/render/texture/sky_multiple_decreased_disc_increased_air_aerosols.blend b/tests/files/render/texture/sky_multiple_decreased_disc_increased_air_aerosols.blend new file mode 100644 index 00000000000..8dc0bb83c9d --- /dev/null +++ b/tests/files/render/texture/sky_multiple_decreased_disc_increased_air_aerosols.blend @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7880cb027560fad824a7c7a1a7361589135c498701abf40268fac89abd26d916 +size 117487 diff --git a/tests/files/render/texture/sky_multiple_default.blend b/tests/files/render/texture/sky_multiple_default.blend new file mode 100644 index 00000000000..fec7227a15a --- /dev/null +++ b/tests/files/render/texture/sky_multiple_default.blend @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3c270b57b8a8185d3afb5f12819c29b845c7bc7f659566ddbea2e46e3850fbff +size 117442 diff --git a/tests/files/render/texture/sky_multiple_increased_disc_ozone.blend b/tests/files/render/texture/sky_multiple_increased_disc_ozone.blend new file mode 100644 index 00000000000..11f6d55a2aa --- /dev/null +++ b/tests/files/render/texture/sky_multiple_increased_disc_ozone.blend @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:67fb6c712486a24a826f4216ad36a04aa399044cedbbc30a9f78370256382f8d +size 117435 diff --git a/tests/files/render/texture/sky_multiple_no_disc_high_altitude.blend b/tests/files/render/texture/sky_multiple_no_disc_high_altitude.blend new file mode 100644 index 00000000000..3611d097753 --- /dev/null +++ b/tests/files/render/texture/sky_multiple_no_disc_high_altitude.blend @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:950c4dcf9f344bac16a58eeb5d3df1da36f8b64cfb31456103887fdaf00f7e09 +size 117581 diff --git a/tests/files/render/texture/sky_nishita_decreased_disk_increased_air_dust.blend b/tests/files/render/texture/sky_single_decreased_disc_increased_air_aerosols.blend old mode 100755 new mode 100644 similarity index 100% rename from tests/files/render/texture/sky_nishita_decreased_disk_increased_air_dust.blend rename to tests/files/render/texture/sky_single_decreased_disc_increased_air_aerosols.blend diff --git a/tests/files/render/texture/sky_nishita_default.blend b/tests/files/render/texture/sky_single_default.blend similarity index 100% rename from tests/files/render/texture/sky_nishita_default.blend rename to tests/files/render/texture/sky_single_default.blend diff --git a/tests/files/render/texture/sky_nishita_increased_disk_ozone.blend b/tests/files/render/texture/sky_single_increased_disc_ozone.blend similarity index 100% rename from tests/files/render/texture/sky_nishita_increased_disk_ozone.blend rename to tests/files/render/texture/sky_single_increased_disc_ozone.blend diff --git a/tests/files/render/texture/sky_nishita_no_disk_high_altitude.blend b/tests/files/render/texture/sky_single_no_disc_high_altitude.blend similarity index 100% rename from tests/files/render/texture/sky_nishita_no_disk_high_altitude.blend rename to tests/files/render/texture/sky_single_no_disc_high_altitude.blend diff --git a/tests/files/render/texture/storm_hydra_renders/sky_hosek_wilkie.png b/tests/files/render/texture/storm_hydra_renders/sky_hosek_wilkie.png deleted file mode 100644 index 10350111e17..00000000000 --- a/tests/files/render/texture/storm_hydra_renders/sky_hosek_wilkie.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0e3ac4c648e228fd24599becb05407a62c658d369a441394327f123a24a41614 -size 8974 diff --git a/tests/files/render/texture/storm_hydra_renders/sky_multiple_decreased_disc_increased_air_aerosols.png b/tests/files/render/texture/storm_hydra_renders/sky_multiple_decreased_disc_increased_air_aerosols.png new file mode 100644 index 00000000000..1ec8c398303 --- /dev/null +++ b/tests/files/render/texture/storm_hydra_renders/sky_multiple_decreased_disc_increased_air_aerosols.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:38937749826ae3c6a48cd9e146509e14a6f61caf681c8d0c72cd311832269d5a +size 5326 diff --git a/tests/files/render/texture/storm_hydra_renders/sky_multiple_default.png b/tests/files/render/texture/storm_hydra_renders/sky_multiple_default.png new file mode 100644 index 00000000000..e4427440457 --- /dev/null +++ b/tests/files/render/texture/storm_hydra_renders/sky_multiple_default.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b6cea950925bc119897528f12f54d1b57af596a0b23b442ac84f4d859a6a5de1 +size 5296 diff --git a/tests/files/render/texture/storm_hydra_renders/sky_multiple_increased_disc_ozone.png b/tests/files/render/texture/storm_hydra_renders/sky_multiple_increased_disc_ozone.png new file mode 100644 index 00000000000..d4f66f31ea5 --- /dev/null +++ b/tests/files/render/texture/storm_hydra_renders/sky_multiple_increased_disc_ozone.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ff46131666d671a524806703d4084b61b6ac8d9a5fa95404471250d1ebdab0fe +size 5309 diff --git a/tests/files/render/texture/storm_hydra_renders/sky_multiple_no_disc_high_altitude.png b/tests/files/render/texture/storm_hydra_renders/sky_multiple_no_disc_high_altitude.png new file mode 100644 index 00000000000..1e9c412a064 --- /dev/null +++ b/tests/files/render/texture/storm_hydra_renders/sky_multiple_no_disc_high_altitude.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8c2731999ca86254525077c9916abcce0e5b67d403b7d9107b0b4a7aed468ed6 +size 5310 diff --git a/tests/files/render/texture/storm_hydra_renders/sky_preetham.png b/tests/files/render/texture/storm_hydra_renders/sky_preetham.png deleted file mode 100644 index d94dfc2e74e..00000000000 --- a/tests/files/render/texture/storm_hydra_renders/sky_preetham.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5e1549034fa705e92fd615f72e4b1e44916f82bb7d4c1ca907e973ba2fec15ec -size 8970 diff --git a/tests/files/render/texture/storm_hydra_renders/sky_nishita_decreased_disk_increased_air_dust.png b/tests/files/render/texture/storm_hydra_renders/sky_single_decreased_disc_increased_air_aerosols.png similarity index 100% rename from tests/files/render/texture/storm_hydra_renders/sky_nishita_decreased_disk_increased_air_dust.png rename to tests/files/render/texture/storm_hydra_renders/sky_single_decreased_disc_increased_air_aerosols.png diff --git a/tests/files/render/texture/storm_hydra_renders/sky_nishita_default.png b/tests/files/render/texture/storm_hydra_renders/sky_single_default.png similarity index 100% rename from tests/files/render/texture/storm_hydra_renders/sky_nishita_default.png rename to tests/files/render/texture/storm_hydra_renders/sky_single_default.png diff --git a/tests/files/render/texture/storm_hydra_renders/sky_nishita_increased_disk_ozone.png b/tests/files/render/texture/storm_hydra_renders/sky_single_increased_disc_ozone.png similarity index 100% rename from tests/files/render/texture/storm_hydra_renders/sky_nishita_increased_disk_ozone.png rename to tests/files/render/texture/storm_hydra_renders/sky_single_increased_disc_ozone.png diff --git a/tests/files/render/texture/storm_hydra_renders/sky_nishita_no_disk_high_altitude.png b/tests/files/render/texture/storm_hydra_renders/sky_single_no_disc_high_altitude.png similarity index 100% rename from tests/files/render/texture/storm_hydra_renders/sky_nishita_no_disk_high_altitude.png rename to tests/files/render/texture/storm_hydra_renders/sky_single_no_disc_high_altitude.png diff --git a/tests/files/render/texture/storm_usd_renders/sky_hosek_wilkie.png b/tests/files/render/texture/storm_usd_renders/sky_hosek_wilkie.png deleted file mode 100644 index 58592f9df2f..00000000000 --- a/tests/files/render/texture/storm_usd_renders/sky_hosek_wilkie.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3051a14b6f15f85cac43af51fff5712b5fb744c011c91c8386b6610fbb0b3e6d -size 8974 diff --git a/tests/files/render/texture/storm_usd_renders/sky_multiple_decreased_disc_increased_air_aerosols.png b/tests/files/render/texture/storm_usd_renders/sky_multiple_decreased_disc_increased_air_aerosols.png new file mode 100644 index 00000000000..f877126050d --- /dev/null +++ b/tests/files/render/texture/storm_usd_renders/sky_multiple_decreased_disc_increased_air_aerosols.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ca4d40932979574832c58dfb6d331b7b95eb8f75488fe5f0a385e213bf435c16 +size 5326 diff --git a/tests/files/render/texture/storm_usd_renders/sky_multiple_default.png b/tests/files/render/texture/storm_usd_renders/sky_multiple_default.png new file mode 100644 index 00000000000..7fb21016d0c --- /dev/null +++ b/tests/files/render/texture/storm_usd_renders/sky_multiple_default.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:565e0aee3c0b929c43991810887d2678a646ce2588e71bf9714bf8f55657aed9 +size 5296 diff --git a/tests/files/render/texture/storm_usd_renders/sky_multiple_increased_disc_ozone.png b/tests/files/render/texture/storm_usd_renders/sky_multiple_increased_disc_ozone.png new file mode 100644 index 00000000000..90b42624f24 --- /dev/null +++ b/tests/files/render/texture/storm_usd_renders/sky_multiple_increased_disc_ozone.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:55a48a868f36ace576738fa8d903ff597d8b8f92c443ddcabd04f3a77ae13f79 +size 5309 diff --git a/tests/files/render/texture/storm_usd_renders/sky_multiple_no_disc_high_altitude.png b/tests/files/render/texture/storm_usd_renders/sky_multiple_no_disc_high_altitude.png new file mode 100644 index 00000000000..5939d54e067 --- /dev/null +++ b/tests/files/render/texture/storm_usd_renders/sky_multiple_no_disc_high_altitude.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5f8cc00edf37f00dadadeba187f496f6b2228a65c1280d9c858e9bd1b7eae264 +size 5310 diff --git a/tests/files/render/texture/storm_usd_renders/sky_preetham.png b/tests/files/render/texture/storm_usd_renders/sky_preetham.png deleted file mode 100644 index 6595773a8e3..00000000000 --- a/tests/files/render/texture/storm_usd_renders/sky_preetham.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4a924c66793d63e885185fb8311c5dd195abb24602a885dfbbc73a7ccdddb8ca -size 8970 diff --git a/tests/files/render/texture/storm_usd_renders/sky_nishita_decreased_disk_increased_air_dust.png b/tests/files/render/texture/storm_usd_renders/sky_single_decreased_disc_increased_air_aerosols.png similarity index 100% rename from tests/files/render/texture/storm_usd_renders/sky_nishita_decreased_disk_increased_air_dust.png rename to tests/files/render/texture/storm_usd_renders/sky_single_decreased_disc_increased_air_aerosols.png diff --git a/tests/files/render/texture/storm_usd_renders/sky_nishita_default.png b/tests/files/render/texture/storm_usd_renders/sky_single_default.png similarity index 100% rename from tests/files/render/texture/storm_usd_renders/sky_nishita_default.png rename to tests/files/render/texture/storm_usd_renders/sky_single_default.png diff --git a/tests/files/render/texture/storm_usd_renders/sky_nishita_increased_disk_ozone.png b/tests/files/render/texture/storm_usd_renders/sky_single_increased_disc_ozone.png similarity index 100% rename from tests/files/render/texture/storm_usd_renders/sky_nishita_increased_disk_ozone.png rename to tests/files/render/texture/storm_usd_renders/sky_single_increased_disc_ozone.png diff --git a/tests/files/render/texture/storm_usd_renders/sky_nishita_no_disk_high_altitude.png b/tests/files/render/texture/storm_usd_renders/sky_single_no_disc_high_altitude.png similarity index 100% rename from tests/files/render/texture/storm_usd_renders/sky_nishita_no_disk_high_altitude.png rename to tests/files/render/texture/storm_usd_renders/sky_single_no_disc_high_altitude.png diff --git a/tests/files/render/texture/workbench_renders/sky_hosek_wilkie.png b/tests/files/render/texture/workbench_renders/sky_hosek_wilkie.png deleted file mode 100644 index 3c0c54ba0a7..00000000000 --- a/tests/files/render/texture/workbench_renders/sky_hosek_wilkie.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a40436cdb53e80ff601f32fce9482de030cb4f8359bd6a81bd35652e50ccdd51 -size 16828 diff --git a/tests/files/render/texture/workbench_renders/sky_multiple_decreased_disc_increased_air_aerosols.png b/tests/files/render/texture/workbench_renders/sky_multiple_decreased_disc_increased_air_aerosols.png new file mode 100644 index 00000000000..a432a7edaf3 --- /dev/null +++ b/tests/files/render/texture/workbench_renders/sky_multiple_decreased_disc_increased_air_aerosols.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5ed4f4871b9fa5cc7169894ef1ad7ea06ef9bbc32380f19f32ebc0cf44a65100 +size 14886 diff --git a/tests/files/render/texture/workbench_renders/sky_multiple_default.png b/tests/files/render/texture/workbench_renders/sky_multiple_default.png new file mode 100644 index 00000000000..d470ba2886f --- /dev/null +++ b/tests/files/render/texture/workbench_renders/sky_multiple_default.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a45a6ba45542ab0f6ee945104b3a618352da006da987690e4b67a06e9a8b2acd +size 14856 diff --git a/tests/files/render/texture/workbench_renders/sky_multiple_increased_disc_ozone.png b/tests/files/render/texture/workbench_renders/sky_multiple_increased_disc_ozone.png new file mode 100644 index 00000000000..c5a27446c5f --- /dev/null +++ b/tests/files/render/texture/workbench_renders/sky_multiple_increased_disc_ozone.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ca674472c4fd6235df5986436fb4a26efca2203cd8446f7faddb55e2f47622a4 +size 14869 diff --git a/tests/files/render/texture/workbench_renders/sky_multiple_no_disc_high_altitude.png b/tests/files/render/texture/workbench_renders/sky_multiple_no_disc_high_altitude.png new file mode 100644 index 00000000000..ed11d69da9e --- /dev/null +++ b/tests/files/render/texture/workbench_renders/sky_multiple_no_disc_high_altitude.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1861bb28ef7cae96d616e7e613bef4dcd53ead1cdf921bb65534a3e01657fcab +size 14870 diff --git a/tests/files/render/texture/workbench_renders/sky_nishita_decreased_disk_increased_air_dust.png b/tests/files/render/texture/workbench_renders/sky_nishita_decreased_disk_increased_air_dust.png deleted file mode 100644 index 94d52623765..00000000000 --- a/tests/files/render/texture/workbench_renders/sky_nishita_decreased_disk_increased_air_dust.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:94b829ad76d88e4861bba87f4c5e0a66043039c352fc0524539ccd332f3d0b7e -size 14601 diff --git a/tests/files/render/texture/workbench_renders/sky_nishita_default.png b/tests/files/render/texture/workbench_renders/sky_nishita_default.png deleted file mode 100644 index 9c218296f28..00000000000 --- a/tests/files/render/texture/workbench_renders/sky_nishita_default.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8c7c2e936fcbcbe8d244b39072e6a126efaaa5fd8933b8a22e228d8f96d00f81 -size 14575 diff --git a/tests/files/render/texture/workbench_renders/sky_nishita_increased_disk_ozone.png b/tests/files/render/texture/workbench_renders/sky_nishita_increased_disk_ozone.png deleted file mode 100644 index aa2059bb957..00000000000 --- a/tests/files/render/texture/workbench_renders/sky_nishita_increased_disk_ozone.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4b6effe01e05d721dd4f744aea0927a0cf301e9bdd36c67ad99e506db925f766 -size 14588 diff --git a/tests/files/render/texture/workbench_renders/sky_nishita_no_disk_high_altitude.png b/tests/files/render/texture/workbench_renders/sky_nishita_no_disk_high_altitude.png deleted file mode 100644 index 3c329f63d45..00000000000 --- a/tests/files/render/texture/workbench_renders/sky_nishita_no_disk_high_altitude.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:85120a360d944e64f9ef15e927caea05887f3abcfeffdb30bd8b79c0c4413948 -size 14589 diff --git a/tests/files/render/texture/workbench_renders/sky_preetham.png b/tests/files/render/texture/workbench_renders/sky_preetham.png deleted file mode 100644 index 4738a66f358..00000000000 --- a/tests/files/render/texture/workbench_renders/sky_preetham.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2f20c636516e4c6c7528bc6f8974bde24cc665bd908af428ae7dc2bd5275b577 -size 16824 diff --git a/tests/files/render/texture/workbench_renders/sky_single_decreased_disc_increased_air_aerosols.png b/tests/files/render/texture/workbench_renders/sky_single_decreased_disc_increased_air_aerosols.png new file mode 100644 index 00000000000..cacc3286f98 --- /dev/null +++ b/tests/files/render/texture/workbench_renders/sky_single_decreased_disc_increased_air_aerosols.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:938d2c526b7d077bcd7dde521966a7a35fec3b4b5bcd9fb9afeb7ae1ff81bd27 +size 14884 diff --git a/tests/files/render/texture/workbench_renders/sky_single_default.png b/tests/files/render/texture/workbench_renders/sky_single_default.png new file mode 100644 index 00000000000..0fa1ee6899f --- /dev/null +++ b/tests/files/render/texture/workbench_renders/sky_single_default.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:06c426b6771af5a3237c9906412d3c4e7241ba206e44357dc203ecaba6fc0f33 +size 14854 diff --git a/tests/files/render/texture/workbench_renders/sky_single_increased_disc_ozone.png b/tests/files/render/texture/workbench_renders/sky_single_increased_disc_ozone.png new file mode 100644 index 00000000000..010bc0161e1 --- /dev/null +++ b/tests/files/render/texture/workbench_renders/sky_single_increased_disc_ozone.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:234c4278fb6df1d0f1996e83a1b183fc76660c0c2eb12375389a1b92c0e9bf7d +size 14867 diff --git a/tests/files/render/texture/workbench_renders/sky_single_no_disc_high_altitude.png b/tests/files/render/texture/workbench_renders/sky_single_no_disc_high_altitude.png new file mode 100644 index 00000000000..3bf8180796d --- /dev/null +++ b/tests/files/render/texture/workbench_renders/sky_single_no_disc_high_altitude.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3cefffa69e4440548afe5dca6c68e655f44b3e3b1495c089cd615f68c44cadb6 +size 14868 diff --git a/tests/files/render/volume/cycles_renders/implicit_volume.png b/tests/files/render/volume/cycles_renders/implicit_volume.png index 488f04b9541..9e7f55d4142 100644 --- a/tests/files/render/volume/cycles_renders/implicit_volume.png +++ b/tests/files/render/volume/cycles_renders/implicit_volume.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:25cc6a6365b9cdd4e4e8bb43cc2cc9f43541201ce8ce465cca20c01941f5eb70 -size 45036 +oid sha256:6f70ffb7c3a63684880dcb25accc1b297033eaadd47c77d2ba2b181a2b8babba +size 45159