Fix #103977: Cycles handling ray visibility inconsistent for forward and nee #107747
|
@ -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
|
||||
|
|
|
@ -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<KERNEL_FEATURE_NODE_MASK_SURFACE_BACKGROUND>(
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
Sergey Sharybin
commented
Can we define
and avoid such memory casts, and casts between signed/unsigned This also seems to a bit arbitrary place to have such utility functions. Within the current file structure it seems Can we define `SpectrumRGBE ` as
```
struct SpectrumRGBE {
uint8_t r, g, b, e;
};
```
and avoid such memory casts, and casts between signed/unsigned `char`?
This also seems to a bit arbitrary place to have such utility functions. Within the current file structure it seems `types_spectrum.h` is the most fitted place for it.
Sebastian Herholz
commented
sure no problem. sure no problem.
Sebastian Herholz
commented
@Sergey done. @Sergey done.
I am not sure if you can compress the data even more.
The positive side on this approach is that we can realize handling scalar ray types light interactions straight forward instead of only binary ones.
Sebastian Herholz
commented
Another thing worth considering is moving the conversion methods to a different place (not into Another thing worth considering is moving the conversion methods to a different place (not into `visibility.h`).
Do you have a good suggestion for it?
Sergey Sharybin
commented
The immediate thought is The immediate thought is `kernel/util/color.h`. There is already `spectrum_to_rgb` so intuitively feels like `spectrum_to_spectrum_rgbe` could fit there as well.
|
||||
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
|
|
@ -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 {
|
||||
|
|
|
@ -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)))
|
||||
|
|
I wonder, shouldn't the function
surface_shader_bsdf_eval_pdfs()
just below it follow the same logic and be corrected too?