diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt index b22146eaf83..23131d478d3 100644 --- a/intern/cycles/kernel/CMakeLists.txt +++ b/intern/cycles/kernel/CMakeLists.txt @@ -306,6 +306,7 @@ set(SRC_KERNEL_LIGHT_HEADERS light/spot.h light/tree.h light/triangle.h + light/visibility.h ) set(SRC_KERNEL_SAMPLE_HEADERS diff --git a/intern/cycles/kernel/integrator/shade_background.h b/intern/cycles/kernel/integrator/shade_background.h index 12639715465..39ffbd4b63c 100644 --- a/intern/cycles/kernel/integrator/shade_background.h +++ b/intern/cycles/kernel/integrator/shade_background.h @@ -11,6 +11,7 @@ #include "kernel/light/light.h" #include "kernel/light/sample.h" +#include "kernel/light/visibility.h" CCL_NAMESPACE_BEGIN @@ -22,20 +23,18 @@ ccl_device Spectrum integrator_eval_background_shader(KernelGlobals kg, const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag); /* Use visibility flag to skip lights. */ + Spectrum light_visibility = one_spectrum(); if (shader & SHADER_EXCLUDE_ANY) { - if (((shader & SHADER_EXCLUDE_DIFFUSE) && (path_flag & PATH_RAY_DIFFUSE)) || - ((shader & SHADER_EXCLUDE_GLOSSY) && ((path_flag & (PATH_RAY_GLOSSY | PATH_RAY_REFLECT)) == - (PATH_RAY_GLOSSY | PATH_RAY_REFLECT))) || - ((shader & SHADER_EXCLUDE_TRANSMIT) && (path_flag & PATH_RAY_TRANSMIT)) || - ((shader & SHADER_EXCLUDE_CAMERA) && (path_flag & PATH_RAY_CAMERA)) || + if (((shader & SHADER_EXCLUDE_CAMERA) && (path_flag & PATH_RAY_CAMERA)) || ((shader & SHADER_EXCLUDE_SCATTER) && (path_flag & PATH_RAY_VOLUME_SCATTER))) return zero_spectrum(); + light_visibility_correction(kg, state, shader, &light_visibility); } /* Use fast constant background color if available. */ Spectrum L = zero_spectrum(); if (surface_shader_constant_emission(kg, shader, &L)) { - return L; + return light_visibility * L; } /* Evaluate background shader. */ @@ -57,7 +56,7 @@ ccl_device Spectrum integrator_eval_background_shader(KernelGlobals kg, surface_shader_eval( kg, state, emission_sd, render_buffer, path_flag | PATH_RAY_EMISSION); - return surface_shader_background(emission_sd); + return light_visibility * surface_shader_background(emission_sd); } ccl_device_inline void integrate_background(KernelGlobals kg, @@ -138,18 +137,14 @@ ccl_device_inline void integrate_distant_lights(KernelGlobals kg, for (int lamp = 0; lamp < kernel_data.integrator.num_lights; lamp++) { if (distant_light_sample_from_intersection(kg, ray_D, lamp, &ls)) { /* Use visibility flag to skip lights. */ + Spectrum light_visibility = one_spectrum(); #ifdef __PASSES__ const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag); - if (ls.shader & SHADER_EXCLUDE_ANY) { - if (((ls.shader & SHADER_EXCLUDE_DIFFUSE) && (path_flag & PATH_RAY_DIFFUSE)) || - ((ls.shader & SHADER_EXCLUDE_GLOSSY) && - ((path_flag & (PATH_RAY_GLOSSY | PATH_RAY_REFLECT)) == - (PATH_RAY_GLOSSY | PATH_RAY_REFLECT))) || - ((ls.shader & SHADER_EXCLUDE_TRANSMIT) && (path_flag & PATH_RAY_TRANSMIT)) || - ((ls.shader & SHADER_EXCLUDE_CAMERA) && (path_flag & PATH_RAY_CAMERA)) || + if (((ls.shader & SHADER_EXCLUDE_CAMERA) && (path_flag & PATH_RAY_CAMERA)) || ((ls.shader & SHADER_EXCLUDE_SCATTER) && (path_flag & PATH_RAY_VOLUME_SCATTER))) continue; + light_visibility_correction(kg, state, ls.shader, &light_visibility); } #endif @@ -168,6 +163,7 @@ ccl_device_inline void integrate_distant_lights(KernelGlobals kg, ShaderDataTinyStorage emission_sd_storage; ccl_private ShaderData *emission_sd = AS_SHADER_DATA(&emission_sd_storage); Spectrum light_eval = light_sample_shader_eval(kg, state, emission_sd, &ls, ray_time); + light_eval *= light_visibility; if (is_zero(light_eval)) { continue; } diff --git a/intern/cycles/kernel/integrator/shade_light.h b/intern/cycles/kernel/integrator/shade_light.h index f5017676dd6..b31f1a8d127 100644 --- a/intern/cycles/kernel/integrator/shade_light.h +++ b/intern/cycles/kernel/integrator/shade_light.h @@ -35,17 +35,13 @@ ccl_device_inline void integrate_light(KernelGlobals kg, } /* Use visibility flag to skip lights. */ + Spectrum light_visibility = one_spectrum(); #ifdef __PASSES__ const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag); - if (ls.shader & SHADER_EXCLUDE_ANY) { - if (((ls.shader & SHADER_EXCLUDE_DIFFUSE) && (path_flag & PATH_RAY_DIFFUSE)) || - ((ls.shader & SHADER_EXCLUDE_GLOSSY) && - ((path_flag & (PATH_RAY_GLOSSY | PATH_RAY_REFLECT)) == - (PATH_RAY_GLOSSY | PATH_RAY_REFLECT))) || - ((ls.shader & SHADER_EXCLUDE_TRANSMIT) && (path_flag & PATH_RAY_TRANSMIT)) || - ((ls.shader & SHADER_EXCLUDE_SCATTER) && (path_flag & PATH_RAY_VOLUME_SCATTER))) + if (((ls.shader & SHADER_EXCLUDE_SCATTER) && (path_flag & PATH_RAY_VOLUME_SCATTER))) return; + light_visibility_correction(kg, state, ls.shader, &light_visibility); } #endif @@ -54,6 +50,7 @@ ccl_device_inline void integrate_light(KernelGlobals kg, ShaderDataTinyStorage emission_sd_storage; ccl_private ShaderData *emission_sd = AS_SHADER_DATA(&emission_sd_storage); Spectrum light_eval = light_sample_shader_eval(kg, state, emission_sd, &ls, ray_time); + light_eval *= light_visibility; if (is_zero(light_eval)) { return; } diff --git a/intern/cycles/kernel/integrator/shade_surface.h b/intern/cycles/kernel/integrator/shade_surface.h index ed3ae781095..2315eecd5c3 100644 --- a/intern/cycles/kernel/integrator/shade_surface.h +++ b/intern/cycles/kernel/integrator/shade_surface.h @@ -16,6 +16,7 @@ #include "kernel/integrator/volume_stack.h" #include "kernel/light/sample.h" +#include "kernel/light/visibility.h" CCL_NAMESPACE_BEGIN @@ -429,6 +430,8 @@ ccl_device_forceinline int integrate_surface_bsdf_bssrdf_bounce( /* Update throughput. */ const Spectrum bsdf_weight = bsdf_eval_sum(&bsdf_eval) / bsdf_pdf; INTEGRATOR_STATE_WRITE(state, path, throughput) *= bsdf_weight; + const BsdfEvalRGBE bsdf_eval_RGBE = BsdfEvalToBsdfEvalRGBE(&bsdf_eval); + INTEGRATOR_STATE_WRITE(state, path, scatter_eval) = bsdf_eval_RGBE; if (kernel_data.kernel_features & KERNEL_FEATURE_LIGHT_PASSES) { if (INTEGRATOR_STATE(state, path, bounce) == 0) { diff --git a/intern/cycles/kernel/integrator/state_template.h b/intern/cycles/kernel/integrator/state_template.h index e60f2fa4c31..54887f7a42e 100644 --- a/intern/cycles/kernel/integrator/state_template.h +++ b/intern/cycles/kernel/integrator/state_template.h @@ -48,6 +48,7 @@ KERNEL_STRUCT_MEMBER(path, float, min_ray_pdf, KERNEL_FEATURE_PATH_TRACING) KERNEL_STRUCT_MEMBER(path, float, continuation_probability, KERNEL_FEATURE_PATH_TRACING) /* Throughput. */ KERNEL_STRUCT_MEMBER(path, PackedSpectrum, throughput, KERNEL_FEATURE_PATH_TRACING) +KERNEL_STRUCT_MEMBER(path, BsdfEvalRGBE, scatter_eval, KERNEL_FEATURE_PATH_TRACING) /* Factor to multiple with throughput to get remove any guiding PDFS. * Such throughput without guiding PDFS is used for Russian roulette termination. */ KERNEL_STRUCT_MEMBER(path, float, unguided_throughput, KERNEL_FEATURE_PATH_GUIDING) diff --git a/intern/cycles/kernel/integrator/surface_shader.h b/intern/cycles/kernel/integrator/surface_shader.h index a0fa9255628..ecd68ea9465 100644 --- a/intern/cycles/kernel/integrator/surface_shader.h +++ b/intern/cycles/kernel/integrator/surface_shader.h @@ -240,12 +240,14 @@ ccl_device_inline float _surface_shader_bsdf_eval_mis(KernelGlobals kg, } if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) { - if (CLOSURE_IS_BSDF(sc->type) && !_surface_shader_exclude(sc->type, light_shader_flags)) { + if (CLOSURE_IS_BSDF(sc->type)) { float bsdf_pdf = 0.0f; Spectrum eval = bsdf_eval(kg, sd, sc, wo, &bsdf_pdf); if (bsdf_pdf != 0.0f) { - bsdf_eval_accum(result_eval, sc->type, eval * sc->weight); + if (!_surface_shader_exclude(sc->type, light_shader_flags)) { + bsdf_eval_accum(result_eval, sc->type, eval * sc->weight); + } sum_pdf += bsdf_pdf * sc->sample_weight; } } diff --git a/intern/cycles/kernel/light/visibility.h b/intern/cycles/kernel/light/visibility.h new file mode 100644 index 00000000000..10d38c119c0 --- /dev/null +++ b/intern/cycles/kernel/light/visibility.h @@ -0,0 +1,93 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2011-2023 Blender Foundation */ + +#pragma once + +CCL_NAMESPACE_BEGIN + +// float EGB to RGBE conversion as described by Greg Ward +// http://www.graphics.cornell.edu/online/formats/rgbe/ + +ccl_device_inline SpectrumRGBE SpectrumToSpectrumRGBE(ccl_private const Spectrum *spec) +{ + SpectrumRGBE specRGBE; + + float v; + int e; + v = max(spec->x, max(spec->y, spec->z)); + if (v < 1e-32f) { + specRGBE.r = specRGBE.g = specRGBE.b = specRGBE.e = 0; + } + else { +#if defined(__KERNEL_METAL__) + v = frexp(v, e) * 256.0f / v; +#else + v = frexp(v, &e) * 256.0f / v; +#endif + specRGBE.r = (uint8_t)(spec->x * v); + specRGBE.g = (uint8_t)(spec->y * v); + specRGBE.b = (uint8_t)(spec->z * v); + specRGBE.e = (uint8_t)(e + 128); + } + return specRGBE; +} + +ccl_device_inline Spectrum SpectrumRGBEToSpectrum(ccl_private const SpectrumRGBE *specRGBE) +{ + Spectrum spec; + + if (specRGBE->e) { + const float f = ldexp(1.0f, specRGBE->e - (int)(128 + 8)); + spec.x = specRGBE->r * f; + spec.y = specRGBE->g * f; + spec.z = specRGBE->b * f; + } + else { + spec.x = spec.y = spec.z = 0.0f; + } + return spec; +} + +ccl_device_inline BsdfEvalRGBE BsdfEvalToBsdfEvalRGBE(ccl_private const BsdfEval *bsdfEval) +{ + BsdfEvalRGBE bsdfEvalRGBE; + bsdfEvalRGBE.diffuse = SpectrumToSpectrumRGBE(&bsdfEval->diffuse); + bsdfEvalRGBE.glossy = SpectrumToSpectrumRGBE(&bsdfEval->glossy); + bsdfEvalRGBE.sum = SpectrumToSpectrumRGBE(&bsdfEval->sum); + return bsdfEvalRGBE; +} + +ccl_device_inline BsdfEval BsdfEvalRGBEToBsdfEval(ccl_private const BsdfEvalRGBE *bsdfEvalRGBE) +{ + BsdfEval bsdfEval; + bsdfEval.diffuse = SpectrumRGBEToSpectrum(&bsdfEvalRGBE->diffuse); + bsdfEval.glossy = SpectrumRGBEToSpectrum(&bsdfEvalRGBE->glossy); + bsdfEval.sum = SpectrumRGBEToSpectrum(&bsdfEvalRGBE->sum); + return bsdfEval; +} + +ccl_device_inline void light_visibility_correction(KernelGlobals kg, + IntegratorState state, + ccl_private const int shader, + ccl_private Spectrum *light_visibility) +{ + Spectrum visible_components = zero_spectrum(); + const BsdfEvalRGBE scatter_eval_rgbe = INTEGRATOR_STATE(state, path, scatter_eval); + const BsdfEval scatter_eval = BsdfEvalRGBEToBsdfEval(&scatter_eval_rgbe); + Spectrum transmission = scatter_eval.sum - (scatter_eval.glossy + scatter_eval.diffuse); + if (!(shader & SHADER_EXCLUDE_DIFFUSE)) { + visible_components += scatter_eval.diffuse; + } + + if (!(shader & SHADER_EXCLUDE_GLOSSY)) { + visible_components += scatter_eval.glossy; + } + + if (!(shader & SHADER_EXCLUDE_TRANSMIT)) { + visible_components += transmission; + } + + *light_visibility = safe_divide(visible_components, scatter_eval.sum); +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/types.h b/intern/cycles/kernel/types.h index 165ec03d4b6..fef721d6e9f 100644 --- a/intern/cycles/kernel/types.h +++ b/intern/cycles/kernel/types.h @@ -443,6 +443,12 @@ typedef struct BsdfEval { Spectrum sum; } BsdfEval; +typedef struct BsdfEvalRGBE { + SpectrumRGBE diffuse; + SpectrumRGBE glossy; + SpectrumRGBE sum; +} BsdfEvalRGBE; + /* Closure Filter */ typedef enum FilterClosures { diff --git a/intern/cycles/util/types_spectrum.h b/intern/cycles/util/types_spectrum.h index c59230b83ae..2cbe69ca09d 100644 --- a/intern/cycles/util/types_spectrum.h +++ b/intern/cycles/util/types_spectrum.h @@ -17,6 +17,10 @@ CCL_NAMESPACE_BEGIN using Spectrum = SPECTRUM_DATA_TYPE; using PackedSpectrum = PACKED_SPECTRUM_DATA_TYPE; +struct SpectrumRGBE { + uint8_t r, g, b, e; +}; + #define make_spectrum(f) CONCAT(make_, SPECTRUM_DATA_TYPE(f)) #define load_spectrum(f) CONCAT(load_, SPECTRUM_DATA_TYPE(f)) #define store_spectrum(s, f) CONCAT(store_, SPECTRUM_DATA_TYPE((s), (f)))