Fix #146630: Single Scattering Sky has darker pixels near horizon

Store the ground fading of Single Scattering sky directly in the LUT.

Co-authored-by: Lukas Stockner <lukas@lukasstockner.de>
Pull Request: https://projects.blender.org/blender/blender/pulls/146659
This commit is contained in:
marcopavanello
2025-09-23 17:16:00 +02:00
committed by Lukas Stockner
parent 0f3c6da272
commit 390f053e32
8 changed files with 56 additions and 88 deletions

View File

@@ -163,28 +163,11 @@ color sky_radiance_nishita(vector dir, float sky_data[11], string filename, stri
if (x > 1.0) {
x = x - 1.0;
}
color rgb_sky;
if (sky_type == "single_scattering" && 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) {
rgb_sky = color(0.0, 0.0, 0.0);
}
else {
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;
}
}
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]);
}
/* 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);
color rgb_sky = xyz_to_rgb(xyz[0], xyz[1], xyz[2]);
return rgb_sun * sun_intensity + rgb_sky;
}

View File

@@ -134,7 +134,6 @@ ccl_device float3 geographical_to_direction(const float lat, const float lon)
}
ccl_device float3 sky_radiance_nishita(KernelGlobals kg,
const NodeSkyType type,
const float3 dir,
const uint32_t path_flag,
const float3 pixel_bottom,
@@ -142,7 +141,7 @@ ccl_device float3 sky_radiance_nishita(KernelGlobals kg,
const ccl_private float *sky_data,
const uint texture_id)
{
/* definitions */
/* Definitions */
const float sun_elevation = sky_data[0];
const float sun_rotation = sky_data[1];
const float angular_diameter = sky_data[2];
@@ -150,49 +149,32 @@ ccl_device float3 sky_radiance_nishita(KernelGlobals kg,
const float earth_intersection_angle = sky_data[4];
const bool sun_disc = (angular_diameter >= 0.0f);
float3 xyz = zero_float3();
/* convert dir to spherical coordinates */
const float2 direction = direction_to_spherical(dir);
/* definitions */
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;
/* 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 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 && dir_elevation > earth_intersection_angle &&
!((path_flag & PATH_RAY_IMPORTANCE_BAKE) && kernel_data.background.use_sun_guiding))
{
/* sun interpolation */
/* Sun interpolation */
const float y = ((dir_elevation - sun_elevation) / angular_diameter) + 0.5f;
/* limb darkening, coefficient is 0.6f */
/* 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 = mix(pixel_bottom, pixel_top, y) * sun_intensity * limb_darkening;
}
/* sky */
/* Sky */
const float x = fractf((-direction.y - M_PI_2_F + sun_rotation) * M_1_2PI_F);
if (dir.z > 0.0f) {
/* sky interpolation */
/* more pixels toward horizon compensation */
const float y = safe_sqrtf(dir_elevation * M_2_PI_F) * 0.5f + 0.5f;
xyz += make_float3(kernel_tex_image_interp(kg, texture_id, x, y));
}
/* ground */
else if (type == NODE_SKY_MULTIPLE_SCATTERING) {
const float y = -safe_sqrtf(-dir_elevation * M_2_PI_F) * 0.5f + 0.5f;
xyz += make_float3(kernel_tex_image_interp(kg, texture_id, x, y));
}
else if (dir.z >= -0.4f) {
/* black ground fade */
float fade = 1.0f + dir.z * 2.5f;
fade = sqr(fade) * fade;
/* interpolation */
xyz += make_float3(kernel_tex_image_interp(kg, texture_id, x, 0.508f)) * fade;
}
/* Undo the non-linear transformation from the sky LUT */
const float y = copysignf(sqrtf(fabsf(dir_elevation) * M_2_PI_F), dir_elevation) * 0.5f + 0.5f;
xyz += make_float3(kernel_tex_image_interp(kg, texture_id, x, y));
/* convert to RGB */
/* Convert to RGB */
return xyz_to_rgb_clamped(kg, xyz);
}
@@ -317,8 +299,7 @@ ccl_device_noinline int svm_node_tex_sky(KernelGlobals kg,
const uint texture_id = __float_as_uint(data.w);
/* Compute Sky */
rgb = sky_radiance_nishita(
kg, sky_type, dir, path_flag, pixel_bottom, pixel_top, sky_data, texture_id);
rgb = sky_radiance_nishita(kg, dir, path_flag, pixel_bottom, pixel_top, sky_data, texture_id);
}
stack_store_float3(stack, out_offset, rgb);

View File

@@ -308,25 +308,20 @@ void SKY_single_scattering_precompute_texture(float *pixels,
const float longitude_step = M_2PI_F / width;
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) {
/* Compute Sky in the upper hemisphere. */
SKY_parallel_for(half_height, 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 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 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);
const float3 xyz = spec_to_xyz(spectrum);
/* Store pixels. */
int pos_x = x * stride;
@@ -341,6 +336,26 @@ void SKY_single_scattering_precompute_texture(float *pixels,
}
}
});
/* Fill in the lower hemisphere by fading out the horizon. */
for (int y = 0; y < half_height; y++) {
/* Sample more pixels toward the horizon. */
float latitude = M_PI_2_F * sqr(float(y) / half_height - 1.0f);
float3 dir = geographical_to_direction(latitude, 0.0f);
float fade = 0.0f;
if (dir.z < 0.4f) {
fade = 1.0f - dir.z * 2.5f;
fade = sqr(fade) * fade;
}
float *pixel_row = pixels + (y * width * stride);
float *horizon_row = pixels + (half_height * width * stride);
for (int x = 0, offset = 0; x < width; x++, offset += stride) {
pixel_row[offset + 0] = horizon_row[offset + 0] * fade;
pixel_row[offset + 1] = horizon_row[offset + 1] * fade;
pixel_row[offset + 2] = horizon_row[offset + 2] * fade;
}
}
}
/*********** Sun ***********/

View File

@@ -165,21 +165,10 @@ void node_tex_sky_nishita(float3 co,
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 {
/* 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;
}
/* 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);

Binary file not shown.