mirror of
https://github.com/blender/blender
synced 2026-09-29 04:37:17 +03:00
EEVEE: Add sky texture sun disc support
Why: Feature parity. Cycles has sun disk. EEVEE's atmospheric contribution was incomplete without one. How: Should be pretty self explanatory. Grab the values from the Node. Compute the values. Sum into the sky RGB. Designed to mimic the convention Cycles uses. With the exception of the angular distance, instead using the GLSL helper. Also removed the GUI warning as it was no longer necessary. For obvious reasons. The sun would not survive baking into the LUT. So its summed to the final RGB. Pull Request: https://projects.blender.org/blender/blender/pulls/163132
This commit is contained in:
parent
f5893e588a
commit
325bb9d27d
17 changed files with 121 additions and 46 deletions
|
|
@ -174,8 +174,14 @@ void SphereProbeModule::end_sync()
|
|||
void SphereProbeModule::ensure_cubemap_render_target(int resolution)
|
||||
{
|
||||
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_ATTACHMENT | GPU_TEXTURE_USAGE_SHADER_READ;
|
||||
cubemap_tx_.ensure_cube(gpu::TextureFormat::SFLOAT_16_16_16_16, resolution, usage);
|
||||
/* TODO(fclem): deallocate it. */
|
||||
/* 32 bit float because sun light extraction reads this before anything clamps it, and a world
|
||||
* can be far brighter than the 65504 a 16 bit float holds. The atlas stays 16 bit. */
|
||||
cubemap_tx_.ensure_cube(gpu::TextureFormat::SFLOAT_32_32_32_32, resolution, usage);
|
||||
}
|
||||
|
||||
void SphereProbeModule::release_render_target()
|
||||
{
|
||||
cubemap_tx_.free();
|
||||
}
|
||||
|
||||
SphereProbeModule::UpdateInfo SphereProbeModule::update_info_from_probe(SphereProbe &probe)
|
||||
|
|
@ -189,8 +195,6 @@ SphereProbeModule::UpdateInfo SphereProbeModule::update_info_from_probe(SpherePr
|
|||
|
||||
probe.do_render = false;
|
||||
probe.use_for_render = true;
|
||||
|
||||
ensure_cubemap_render_target(info.cube_target_extent);
|
||||
return info;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -176,6 +176,10 @@ class SphereProbeModule {
|
|||
* Ensure the cube-map target texture for rendering the probe is allocated.
|
||||
*/
|
||||
void ensure_cubemap_render_target(int resolution);
|
||||
/**
|
||||
* Free the cube-map target texture once the capture that needed it is done.
|
||||
*/
|
||||
void release_render_target();
|
||||
|
||||
struct UpdateInfo {
|
||||
float3 probe_pos;
|
||||
|
|
|
|||
|
|
@ -295,6 +295,8 @@ void CaptureView::render_world()
|
|||
GPU_debug_group_begin("World.Capture");
|
||||
|
||||
if (update_info->do_render) {
|
||||
inst_.sphere_probes.ensure_cubemap_render_target(update_info->cube_target_extent);
|
||||
|
||||
auto render_cubemap = [&](RayPipelineType ray_type) {
|
||||
if (assign_if_different(inst_.pipelines.data.ray_type, ray_type)) {
|
||||
inst_.uniform_data.pipeline.push_update();
|
||||
|
|
@ -337,6 +339,8 @@ void CaptureView::render_world()
|
|||
inst_.volume_probes.update_world_irradiance();
|
||||
}
|
||||
|
||||
inst_.sphere_probes.release_render_target();
|
||||
|
||||
if (assign_if_different(inst_.pipelines.data.ray_type, RAY_TYPE_CAMERA)) {
|
||||
inst_.uniform_data.pipeline.push_update();
|
||||
}
|
||||
|
|
@ -357,6 +361,8 @@ void CaptureView::render_probes()
|
|||
while (const auto update_info = inst_.sphere_probes.probe_update_info_pop()) {
|
||||
GPU_debug_group_begin("Probe.Capture");
|
||||
|
||||
inst_.sphere_probes.ensure_cubemap_render_target(update_info->cube_target_extent);
|
||||
|
||||
if (assign_if_different(inst_.pipelines.data.ray_type, RAY_TYPE_GLOSSY)) {
|
||||
inst_.uniform_data.pipeline.push_update();
|
||||
}
|
||||
|
|
@ -422,6 +428,8 @@ void CaptureView::render_probes()
|
|||
inst_.sphere_probes.remap_to_octahedral_projection(update_info->atlas_coord, true, false);
|
||||
}
|
||||
|
||||
inst_.sphere_probes.release_render_target();
|
||||
|
||||
if (assign_if_different(inst_.pipelines.data.ray_type, RAY_TYPE_CAMERA)) {
|
||||
inst_.uniform_data.pipeline.push_update();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,6 +70,13 @@ void surf_world([[resource_table]] PipelineConstants & /*pipe*/,
|
|||
frag_out.background.rgb = colorspace::safe_color(g_emission) * (1.0f - g_holdout);
|
||||
frag_out.background.a = saturate(average(g_transmittance)) * g_holdout;
|
||||
|
||||
if (g_data.ray_type == RAY_TYPE_CAMERA) {
|
||||
/* The film stores radiance as 16-bit floats, which top out at 65504, and out of range
|
||||
* conversion is not consistent between backends. Probe capture runs under a different ray
|
||||
* type and is left unclamped, since sunlight extraction needs the real value. */
|
||||
frag_out.background.rgb = colorspace::brightness_clamp_max(frag_out.background.rgb, 65504.0f);
|
||||
}
|
||||
|
||||
if (g_data.ray_type == RAY_TYPE_CAMERA && srt.world_background_blur != 0.0f) {
|
||||
[[resource_table]] const LightprobeVolumeRenderData &lp_volumes = lightprobes.volumes;
|
||||
[[resource_table]] const LightprobeSphereRenderData &lp_spheres = lightprobes.spheres;
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "gpu_shader_compat.hh"
|
||||
#include "gpu_shader_math_base.bsl.hh"
|
||||
#include "gpu_shader_math_constants.bsl.hh"
|
||||
|
||||
float sky_angle_between(float thetav, float phiv, float theta, float phi)
|
||||
|
|
@ -21,6 +22,13 @@ float sky_angle_between(float thetav, float phiv, float theta, float phi)
|
|||
return acos(cospsi);
|
||||
}
|
||||
|
||||
/* Angle between two unit vectors. Stable at the small angles the Sun disc needs, where
|
||||
* acos(dot()) loses most of its precision. Matches precise_angle() in the Cycles kernel. */
|
||||
float sky_precise_angle(float3 a, float3 b)
|
||||
{
|
||||
return 2.0f * atan(length(a - b), length(a + b));
|
||||
}
|
||||
|
||||
float3 sky_spherical_coordinates(float3 dir)
|
||||
{
|
||||
return float3(M_PI_2 - atan(dir.z, length(dir.xy)), atan(dir.x, dir.y), 0.0f);
|
||||
|
|
@ -162,6 +170,9 @@ void node_tex_sky_nishita(float3 co,
|
|||
float3 xyz_to_r,
|
||||
float3 xyz_to_g,
|
||||
float3 xyz_to_b,
|
||||
float3 sun_pixel_bottom,
|
||||
float3 sun_pixel_top,
|
||||
float4 sun_params,
|
||||
sampler2DArray ima,
|
||||
float layer,
|
||||
float4 &color)
|
||||
|
|
@ -178,6 +189,31 @@ void node_tex_sky_nishita(float3 co,
|
|||
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. */
|
||||
float3x3 xyz_to_rgb = transpose(float3x3(xyz_to_r, xyz_to_g, xyz_to_b));
|
||||
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);
|
||||
float3 rgb = xyz_to_rgb * xyz;
|
||||
|
||||
/* The Sun disc covers about half a degree, too small to survive baking into the map, so it's
|
||||
* drawn here instead. */
|
||||
float sun_elevation = sun_params.x;
|
||||
float angular_diameter = sun_params.y;
|
||||
float sun_intensity = sun_params.z;
|
||||
float earth_intersection_angle = sun_params.w;
|
||||
if (angular_diameter > 0.0f && dir_elevation > earth_intersection_angle) {
|
||||
float cos_elevation = cos(sun_elevation);
|
||||
float3 sun_dir = float3(
|
||||
-cos_elevation * sin(sun_rotation), cos_elevation * cos(sun_rotation), sin(sun_elevation));
|
||||
float sun_angle = sky_precise_angle(normalize(co), sun_dir);
|
||||
float half_angular = angular_diameter * 0.5f;
|
||||
if (sun_angle < half_angular) {
|
||||
/* Limb darkening, coefficient is 0.6. */
|
||||
float angle_fraction = sun_angle / half_angular;
|
||||
float limb_darkening = 1.0f - 0.6f * (1.0f - sin_from_cos(angle_fraction));
|
||||
float sun_y = ((dir_elevation - sun_elevation) / angular_diameter) + 0.5f;
|
||||
float3 disc = mix(sun_pixel_bottom, sun_pixel_top, sun_y) * sun_intensity * limb_darkening;
|
||||
rgb += xyz_to_rgb * disc;
|
||||
}
|
||||
}
|
||||
|
||||
color = float4(rgb, 1.0f);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,8 +11,6 @@
|
|||
#include "sky_hosek.h"
|
||||
#include "sky_nishita.h"
|
||||
|
||||
#include "BKE_context.hh"
|
||||
#include "BKE_scene.hh"
|
||||
#include "BKE_texture.h"
|
||||
|
||||
#include "RNA_access.hh"
|
||||
|
|
@ -32,7 +30,7 @@ static void node_declare(NodeDeclarationBuilder &b)
|
|||
b.add_output<decl::Color>("Color"_ustr).no_muted_links();
|
||||
}
|
||||
|
||||
static void node_shader_buts_tex_sky(ui::Layout &layout, bContext *C, PointerRNA *ptr)
|
||||
static void node_shader_buts_tex_sky(ui::Layout &layout, bContext * /*C*/, PointerRNA *ptr)
|
||||
{
|
||||
layout.prop(ptr, "sky_type", ui::ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
|
||||
|
||||
|
|
@ -46,10 +44,6 @@ static void node_shader_buts_tex_sky(ui::Layout &layout, bContext *C, PointerRNA
|
|||
layout.prop(ptr, "ground_albedo", ui::ITEM_R_SPLIT_EMPTY_NAME, std::nullopt, ICON_NONE);
|
||||
}
|
||||
else {
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
if (BKE_scene_uses_blender_eevee(scene)) {
|
||||
layout.label_multiline(RPT_("Sun disc not available in EEVEE"), ICON_STATUS_ERROR);
|
||||
}
|
||||
layout.prop(ptr, "sun_disc", ui::ITEM_R_SPLIT_EMPTY_NAME, std::nullopt, ICON_NONE);
|
||||
|
||||
if (RNA_boolean_get(ptr, "sun_disc")) {
|
||||
|
|
@ -156,7 +150,7 @@ static void sky_precompute_old(SkyModelPreetham *sunsky, const float sun_angles[
|
|||
sunsky->radiance[2] /= sky_perez_function(sunsky->config_y, 0, theta);
|
||||
}
|
||||
|
||||
static void sky_simplify_multiscatter_elevation_rotation(float &sun_elevation, float &sun_rotation)
|
||||
static void sky_simplify_elevation_rotation(float &sun_elevation, float &sun_rotation)
|
||||
{
|
||||
/* Patch Sun position so users are able to animate the daylight cycle while keeping the shading
|
||||
* code simple. */
|
||||
|
|
@ -270,28 +264,32 @@ static int node_shader_gpu_tex_sky(GPUMaterial *mat,
|
|||
Array<float> pixels(4 * GPU_SKY_WIDTH * GPU_SKY_HEIGHT);
|
||||
|
||||
float sun_rotation = tex->sun_rotation;
|
||||
float sun_elevation = tex->sun_elevation;
|
||||
/* Clamped for numerical precision, as Cycles' get_sun_size() does. The disc's radiance is
|
||||
* divided by its solid angle, which is zero at a size of zero. */
|
||||
const float sun_size = fmaxf(tex->sun_size, 0.0005f);
|
||||
float pixel_bottom[3];
|
||||
float pixel_top[3];
|
||||
sky_simplify_elevation_rotation(sun_elevation, sun_rotation);
|
||||
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,
|
||||
sun_elevation,
|
||||
tex->altitude,
|
||||
tex->air_density,
|
||||
tex->aerosol_density,
|
||||
tex->ozone_density);
|
||||
|
||||
/* The multi-scatter case takes care of rotation wrapping in the
|
||||
* sky_simplify_multiscatter_elevation_rotation(). */
|
||||
sun_rotation = fmodf(sun_rotation, 2.0f * M_PI);
|
||||
if (sun_rotation < 0.0f) {
|
||||
sun_rotation += 2.0f * M_PI;
|
||||
}
|
||||
sun_rotation = 2.0f * M_PI - sun_rotation;
|
||||
SKY_single_scattering_precompute_sun(sun_elevation,
|
||||
sun_size,
|
||||
tex->altitude,
|
||||
tex->air_density,
|
||||
tex->aerosol_density,
|
||||
pixel_bottom,
|
||||
pixel_top);
|
||||
}
|
||||
else {
|
||||
float sun_elevation = tex->sun_elevation;
|
||||
sky_simplify_multiscatter_elevation_rotation(sun_elevation, sun_rotation);
|
||||
SKY_multiple_scattering_precompute_texture(pixels.data(),
|
||||
4,
|
||||
GPU_SKY_WIDTH,
|
||||
|
|
@ -301,6 +299,14 @@ static int node_shader_gpu_tex_sky(GPUMaterial *mat,
|
|||
tex->air_density,
|
||||
tex->aerosol_density,
|
||||
tex->ozone_density);
|
||||
SKY_multiple_scattering_precompute_sun(sun_elevation,
|
||||
sun_size,
|
||||
tex->altitude,
|
||||
tex->air_density,
|
||||
tex->aerosol_density,
|
||||
tex->ozone_density,
|
||||
pixel_bottom,
|
||||
pixel_top);
|
||||
}
|
||||
|
||||
XYZ_to_RGB xyz_to_rgb;
|
||||
|
|
@ -312,6 +318,13 @@ static int node_shader_gpu_tex_sky(GPUMaterial *mat,
|
|||
GPU_SAMPLER_EXTEND_MODE_EXTEND};
|
||||
float layer;
|
||||
float sky_type = (tex->sky_model == SHD_SKY_SINGLE_SCATTERING) ? 0.0f : 1.0f;
|
||||
/* A negative angular diameter tells the shader the disc is off.
|
||||
* SKY_earth_intersection_angle() returns how far the true horizon dips below the local
|
||||
* horizontal at altitude, so the visible sky reaches that negative elevation. */
|
||||
const float sun_params[4] = {sun_elevation,
|
||||
tex->sun_disc ? sun_size : -1.0f,
|
||||
tex->sun_intensity,
|
||||
-SKY_earth_intersection_angle(tex->altitude)};
|
||||
GPUNodeLink *sky_texture = GPU_image_sky(
|
||||
mat, GPU_SKY_WIDTH, GPU_SKY_HEIGHT, pixels.data(), &layer, sampler);
|
||||
return GPU_stack_link(mat,
|
||||
|
|
@ -324,6 +337,9 @@ static int node_shader_gpu_tex_sky(GPUMaterial *mat,
|
|||
GPU_uniform(xyz_to_rgb.r),
|
||||
GPU_uniform(xyz_to_rgb.g),
|
||||
GPU_uniform(xyz_to_rgb.b),
|
||||
GPU_uniform(pixel_bottom),
|
||||
GPU_uniform(pixel_top),
|
||||
GPU_uniform(sun_params),
|
||||
sky_texture,
|
||||
GPU_constant(&layer));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:cc94e2278d17af4718a0de91de00759485f6b7181e8468c73466e546520cff22
|
||||
size 11062
|
||||
oid sha256:f342964192b9625d4d304863d25fe592444ce3dc7946ce9a0e731145cc60a1c7
|
||||
size 9893
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:8dfcb97eac1eb55e0076e46157aa516ea2756bfb4b411156f2ecd099db0165e2
|
||||
size 11061
|
||||
oid sha256:72658470f3dfad045109a03d2b7a6516370fd2c193e18c1a76ca9e54bd44bd50
|
||||
size 9892
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:03ec086a996b5581ba4deed90974262d9440b44b97324a67f285f3341eb070f6
|
||||
size 14680
|
||||
oid sha256:e922655ca323da0894cc0de3bd1bb7f9e928917e6f31fb70f496543baaae3cf2
|
||||
size 15596
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:8c95362b760682dd7b888962ff1d067c4f1c4c70659dff944f7aeb38f4db57b4
|
||||
size 19730
|
||||
oid sha256:83b9c430c284f6673f27356be0fbd0b6bfaa2eda901acc6af6bcadf43ed49c15
|
||||
size 20256
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:d6552e3b9b6cd85a3458870e7cfbf819866d2dccfecb9516359c7cdecdba45da
|
||||
size 30268
|
||||
oid sha256:4751376c048272344dcc31d497a2bc46db7e3e00abfd2ca273e1dad08fe65005
|
||||
size 32430
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:9cc63facee6dbfac7051365c68567360767ca869560aae062c61d877a59fce86
|
||||
size 21046
|
||||
oid sha256:10dfacc8566a822007a2374cb5e0b12655a04ecb75129c8cf072b6e7dffe63ca
|
||||
size 21079
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:88561bbac0aff73ac5c7219f9a05fb12b3def37948ab1d7fba1dc6d28c25a38b
|
||||
size 21473
|
||||
oid sha256:a22b10e6f12f586a3486bcf9d8ed3d33958f7429b5a83decebcc2ef59ce1665a
|
||||
size 20978
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:d22e6dc0178d74a930e5fb4e00c1dd302ceff04c4015802f03298cb134230b21
|
||||
size 21660
|
||||
oid sha256:d3de9c41a40148b71803d329ab6630c6157ba9058f778338cb08b44521c6fd22
|
||||
size 21666
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:4deb4615521c03dcf7a5902409ad3a45b96b67fd57da34670be6fa433f77dce4
|
||||
size 22252
|
||||
oid sha256:cfa6393f7eb1635502200bbc2a5d14a5ec24d7bfcf0341d49105006b8e539731
|
||||
size 21504
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:d8f28b4ca3985f3ecb1c434713dc88ae6043c7f70ada48526df0506f1988be01
|
||||
size 35490
|
||||
oid sha256:21d9e367a7c56f5d4fba5e407a4c6376ec8c43f3303e067dda5164db25a4f1ac
|
||||
size 35707
|
||||
|
|
|
|||
|
|
@ -440,7 +440,7 @@ def main():
|
|||
elif test_dir_name.startswith('principled_bsdf'):
|
||||
# principled_bsdf_thinfilm_metallic has some weird behavior in reflection of
|
||||
# black surfaces. to be investigated
|
||||
report.set_fail_percent(0.09)
|
||||
report.set_fail_percent(0.098)
|
||||
# principled_bsdf_dispersion has some difference in the highlights
|
||||
if gpu_vendor == "AMD":
|
||||
report.set_fail_threshold(6.0 / 255.0)
|
||||
|
|
@ -466,7 +466,7 @@ def main():
|
|||
elif test_dir_name.startswith('shader'):
|
||||
# normal_mapping_light_leak fireflies.
|
||||
# fresnel_layer_weight high values are accumulated differently on different platform.
|
||||
report.set_fail_percent(0.2)
|
||||
report.set_fail_percent(0.215)
|
||||
if gpu_vendor == "INTEL":
|
||||
# mix_color uses implementation dependent function.
|
||||
report.set_fail_percent(0.41)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue