Path Guiding: Adding guiding on glossy surfaces via RIS #107782
|
@ -209,6 +209,21 @@ enum_guiding_distribution = (
|
|||
('VMM', "VMM", "Use von Mises-Fisher models as directional distribution", 2),
|
||||
)
|
||||
|
||||
enum_guiding_directional_sampling_types = (
|
||||
('MIS',
|
||||
"Diffuse Product MIS",
|
||||
"Guided diffuse BSDF component based on the incoming light distribution and the cosine product (closed form product)",
|
||||
0),
|
||||
('RIS',
|
||||
"Re-sampled Importance Sampling",
|
||||
"Perform RIS sampling to guided based on the product of the incoming light distribution and the BSDF",
|
||||
1),
|
||||
('ROUGHNESS',
|
||||
"Roughness-based",
|
||||
"Adjust the guiding probability based on the roughness of the material components",
|
||||
2),
|
||||
)
|
||||
|
||||
|
||||
def enum_openimagedenoise_denoiser(self, context):
|
||||
import _cycles
|
||||
|
@ -568,6 +583,13 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
|
|||
default='PARALLAX_AWARE_VMM',
|
||||
)
|
||||
|
||||
guiding_directional_sampling_type: EnumProperty(
|
||||
name="Directional Sampling Type",
|
||||
description="Type of the directional sampling used for guiding",
|
||||
items=enum_guiding_directional_sampling_types,
|
||||
default='RIS',
|
||||
)
|
||||
|
||||
use_surface_guiding: BoolProperty(
|
||||
name="Surface Guiding",
|
||||
description="Use guiding when sampling directions on a surface",
|
||||
|
@ -617,6 +639,13 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
|
|||
default=True,
|
||||
)
|
||||
|
||||
guiding_roughness_threshold: FloatProperty(
|
||||
name="Guiding Roughness Threshold",
|
||||
description="The minimal roughness value of a material to apply guiding",
|
||||
min=0.0, max=1.0,
|
||||
default=0.05,
|
||||
)
|
||||
|
||||
max_bounces: IntProperty(
|
||||
name="Max Bounces",
|
||||
description="Total maximum number of bounces",
|
||||
|
|
|
@ -337,6 +337,8 @@ class CYCLES_RENDER_PT_sampling_path_guiding_debug(CyclesDebugButtonsPanel, Pane
|
|||
layout.active = cscene.use_guiding
|
||||
|
||||
layout.prop(cscene, "guiding_distribution_type", text="Distribution Type")
|
||||
layout.prop(cscene, "guiding_roughness_threshold")
|
||||
layout.prop(cscene, "guiding_directional_sampling_type", text="Directional Sampling Type")
|
||||
|
||||
col = layout.column(align=True)
|
||||
col.prop(cscene, "surface_guiding_probability")
|
||||
|
|
|
@ -440,6 +440,13 @@ void BlenderSync::sync_integrator(BL::ViewLayer &b_view_layer, bool background)
|
|||
GuidingDistributionType guiding_distribution_type = (GuidingDistributionType)get_enum(
|
||||
cscene, "guiding_distribution_type", GUIDING_NUM_TYPES, GUIDING_TYPE_PARALLAX_AWARE_VMM);
|
||||
integrator->set_guiding_distribution_type(guiding_distribution_type);
|
||||
GuidingDirectionalSamplingType guiding_directional_sampling_type =
|
||||
(GuidingDirectionalSamplingType)get_enum(cscene,
|
||||
"guiding_directional_sampling_type",
|
||||
GUIDING_DIRECTIONAL_SAMPLING_NUM_TYPES,
|
||||
GUIDING_DIRECTIONAL_SAMPLING_TYPE_RIS);
|
||||
integrator->set_guiding_directional_sampling_type(guiding_directional_sampling_type);
|
||||
integrator->set_guiding_roughness_threshold(get_float(cscene, "guiding_roughness_threshold"));
|
||||
}
|
||||
|
||||
DenoiseParams denoise_params = get_denoise_params(b_scene, b_view_layer, background);
|
||||
|
|
|
@ -15,6 +15,8 @@ struct GuidingParams {
|
|||
bool use_volume_guiding = false;
|
||||
|
||||
GuidingDistributionType type = GUIDING_TYPE_PARALLAX_AWARE_VMM;
|
||||
GuidingDirectionalSamplingType sampling_type = GUIDING_DIRECTIONAL_SAMPLING_TYPE_PRODUCT_MIS;
|
||||
float roughness_threshold = 0.05f;
|
||||
int training_samples = 128;
|
||||
bool deterministic = false;
|
||||
|
||||
|
@ -24,7 +26,9 @@ struct GuidingParams {
|
|||
{
|
||||
return !((use == other.use) && (use_surface_guiding == other.use_surface_guiding) &&
|
||||
(use_volume_guiding == other.use_volume_guiding) && (type == other.type) &&
|
||||
(sampling_type == other.sampling_type) &&
|
||||
(training_samples == other.training_samples) &&
|
||||
(roughness_threshold == other.roughness_threshold) &&
|
||||
(deterministic == other.deterministic));
|
||||
}
|
||||
};
|
||||
|
|
|
@ -207,6 +207,8 @@ KERNEL_STRUCT_MEMBER(integrator, int, direct_light_sampling_type)
|
|||
KERNEL_STRUCT_MEMBER(integrator, float, surface_guiding_probability)
|
||||
KERNEL_STRUCT_MEMBER(integrator, float, volume_guiding_probability)
|
||||
KERNEL_STRUCT_MEMBER(integrator, int, guiding_distribution_type)
|
||||
KERNEL_STRUCT_MEMBER(integrator, int, guiding_directional_sampling_type)
|
||||
KERNEL_STRUCT_MEMBER(integrator, float, guiding_roughness_threshold)
|
||||
KERNEL_STRUCT_MEMBER(integrator, int, use_guiding)
|
||||
KERNEL_STRUCT_MEMBER(integrator, int, train_guiding)
|
||||
KERNEL_STRUCT_MEMBER(integrator, int, use_surface_guiding)
|
||||
|
@ -216,6 +218,8 @@ KERNEL_STRUCT_MEMBER(integrator, int, use_guiding_mis_weights)
|
|||
|
||||
/* Padding. */
|
||||
KERNEL_STRUCT_MEMBER(integrator, int, pad1)
|
||||
KERNEL_STRUCT_MEMBER(integrator, int, pad2)
|
||||
KERNEL_STRUCT_MEMBER(integrator, int, pad3)
|
||||
KERNEL_STRUCT_END(KernelIntegrator)
|
||||
|
||||
/* SVM. For shader specialization. */
|
||||
|
|
|
@ -7,10 +7,66 @@
|
|||
#include "kernel/closure/bsdf.h"
|
||||
#include "kernel/film/write.h"
|
||||
|
||||
#if OPENPGL_VERSION_MINOR >= 5
|
||||
# define RIS_INCOMING_RADIANCE
|
||||
#endif
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Utilities. */
|
||||
|
||||
struct GuidingRISSample {
|
||||
float3 rand;
|
||||
float2 sampled_roughness;
|
||||
float eta{1.0f};
|
||||
int label;
|
||||
float3 wo;
|
||||
float bsdf_pdf{0.0f};
|
||||
float guide_pdf{0.0f};
|
||||
float ris_target{0.0f};
|
||||
float ris_pdf{0.0f};
|
||||
float ris_weight{0.0f};
|
||||
|
||||
#ifdef RIS_INCOMING_RADIANCE
|
||||
float incoming_radiance_pdf{0.0f};
|
||||
#else
|
||||
float cosine{0.0f};
|
||||
#endif
|
||||
BsdfEval bsdf_eval;
|
||||
float avg_bsdf_eval{0.0f};
|
||||
Spectrum eval{zero_spectrum()};
|
||||
};
|
||||
|
||||
ccl_device_forceinline bool calculate_ris_target(ccl_private GuidingRISSample *ris_sample,
|
||||
brecht marked this conversation as resolved
Outdated
|
||||
ccl_private const float guiding_sampling_prob)
|
||||
{
|
||||
#if defined(__PATH_GUIDING__)
|
||||
const float pi_factor = 2.0f;
|
||||
if (ris_sample->avg_bsdf_eval > 0.0f && ris_sample->bsdf_pdf > 1e-10f &&
|
||||
ris_sample->guide_pdf > 0.0f)
|
||||
{
|
||||
|
||||
# ifdef RIS_INCOMING_RADIANCE
|
||||
ris_sample->ris_target = (ris_sample->avg_bsdf_eval *
|
||||
((((1.0f - guiding_sampling_prob) * (1.0f / (pi_factor * M_PI_F))) +
|
||||
(guiding_sampling_prob * ris_sample->incoming_radiance_pdf))));
|
||||
# else
|
||||
ris_sample->ris_target = (ris_sample->avg_bsdf_eval / ris_sample->cosine *
|
||||
((((1.0f - guiding_sampling_prob) * (1.0f / (pi_factor * M_PI_F))) +
|
||||
(guiding_sampling_prob * ris_sample->guide_pdf))));
|
||||
# endif
|
||||
ris_sample->ris_pdf = (0.5f * (ris_sample->bsdf_pdf + ris_sample->guide_pdf));
|
||||
ris_sample->ris_weight = ris_sample->ris_target / ris_sample->ris_pdf;
|
||||
return true;
|
||||
}
|
||||
ris_sample->ris_target = 0.0f;
|
||||
ris_sample->ris_pdf = 0.0f;
|
||||
return false;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(__PATH_GUIDING__)
|
||||
static pgl_vec3f guiding_vec3f(const float3 v)
|
||||
{
|
||||
|
@ -241,7 +297,7 @@ ccl_device_forceinline void guiding_record_volume_bounce(KernelGlobals kg,
|
|||
openpgl::cpp::SetPDFDirectionIn(state->guiding.path_segment, pdf);
|
||||
openpgl::cpp::SetScatteringWeight(state->guiding.path_segment, guiding_vec3f(weight_rgb));
|
||||
openpgl::cpp::SetIsDelta(state->guiding.path_segment, false);
|
||||
openpgl::cpp::SetEta(state->guiding.path_segment, 1.f);
|
||||
openpgl::cpp::SetEta(state->guiding.path_segment, 1.0f);
|
||||
openpgl::cpp::SetRoughness(state->guiding.path_segment, roughness);
|
||||
#endif
|
||||
}
|
||||
|
@ -259,11 +315,11 @@ ccl_device_forceinline void guiding_record_volume_transmission(KernelGlobals kg,
|
|||
|
||||
if (state->guiding.path_segment) {
|
||||
// TODO (sherholz): need to find a better way to avoid this check
|
||||
if ((transmittance_weight[0] < 0.f || !std::isfinite(transmittance_weight[0]) ||
|
||||
if ((transmittance_weight[0] < 0.0f || !std::isfinite(transmittance_weight[0]) ||
|
||||
std::isnan(transmittance_weight[0])) ||
|
||||
(transmittance_weight[1] < 0.f || !std::isfinite(transmittance_weight[1]) ||
|
||||
(transmittance_weight[1] < 0.0f || !std::isfinite(transmittance_weight[1]) ||
|
||||
std::isnan(transmittance_weight[1])) ||
|
||||
(transmittance_weight[2] < 0.f || !std::isfinite(transmittance_weight[2]) ||
|
||||
(transmittance_weight[2] < 0.0f || !std::isfinite(transmittance_weight[2]) ||
|
||||
std::isnan(transmittance_weight[2])))
|
||||
{
|
||||
}
|
||||
|
@ -438,7 +494,7 @@ ccl_device_forceinline void guiding_write_debug_passes(KernelGlobals kg,
|
|||
sum_sample_weight += sc->sample_weight;
|
||||
}
|
||||
|
||||
avg_roughness = avg_roughness > 0.f ? avg_roughness / sum_sample_weight : 0.f;
|
||||
avg_roughness = avg_roughness > 0.0f ? avg_roughness / sum_sample_weight : 0.0f;
|
||||
|
||||
film_write_pass_float(buffer + kernel_data.film.pass_guiding_avg_roughness, avg_roughness);
|
||||
}
|
||||
|
@ -498,6 +554,17 @@ ccl_device_forceinline float guiding_bsdf_pdf(KernelGlobals kg,
|
|||
#endif
|
||||
}
|
||||
|
||||
ccl_device_forceinline float guiding_surface_incoming_radiance_pdf(KernelGlobals kg,
|
||||
IntegratorState state,
|
||||
const float3 wo)
|
||||
{
|
||||
#if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 4 && OPENPGL_VERSION_MINOR >= 5
|
||||
return kg->opgl_surface_sampling_distribution->IncomingRadiancePDF(guiding_vec3f(wo));
|
||||
#else
|
||||
return 0.0f;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Guided Volume Phases */
|
||||
|
||||
ccl_device_forceinline bool guiding_phase_init(KernelGlobals kg,
|
||||
|
|
|
@ -372,6 +372,7 @@ ccl_device_forceinline int integrate_surface_bsdf_bssrdf_bounce(
|
|||
|
||||
float2 bsdf_sampled_roughness = make_float2(1.0f, 1.0f);
|
||||
float bsdf_eta = 1.0f;
|
||||
float mis_pdf = 1.0f;
|
||||
|
||||
#if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 4
|
||||
if (kernel_data.integrator.use_surface_guiding) {
|
||||
|
@ -383,9 +384,11 @@ ccl_device_forceinline int integrate_surface_bsdf_bssrdf_bounce(
|
|||
&bsdf_eval,
|
||||
&bsdf_wo,
|
||||
&bsdf_pdf,
|
||||
&mis_pdf,
|
||||
&unguided_bsdf_pdf,
|
||||
&bsdf_sampled_roughness,
|
||||
&bsdf_eta);
|
||||
&bsdf_eta,
|
||||
rng_state);
|
||||
|
||||
if (bsdf_pdf == 0.0f || bsdf_eval_is_zero(&bsdf_eval)) {
|
||||
return LABEL_NONE;
|
||||
|
@ -410,7 +413,7 @@ ccl_device_forceinline int integrate_surface_bsdf_bssrdf_bounce(
|
|||
if (bsdf_pdf == 0.0f || bsdf_eval_is_zero(&bsdf_eval)) {
|
||||
return LABEL_NONE;
|
||||
}
|
||||
|
||||
mis_pdf = bsdf_pdf;
|
||||
unguided_bsdf_pdf = bsdf_pdf;
|
||||
}
|
||||
|
||||
|
@ -445,7 +448,7 @@ ccl_device_forceinline int integrate_surface_bsdf_bssrdf_bounce(
|
|||
|
||||
/* Update path state */
|
||||
if (!(label & LABEL_TRANSPARENT)) {
|
||||
INTEGRATOR_STATE_WRITE(state, path, mis_ray_pdf) = bsdf_pdf;
|
||||
INTEGRATOR_STATE_WRITE(state, path, mis_ray_pdf) = mis_pdf;
|
||||
INTEGRATOR_STATE_WRITE(state, path, mis_origin_n) = sd->N;
|
||||
INTEGRATOR_STATE_WRITE(state, path, min_ray_pdf) = fminf(
|
||||
unguided_bsdf_pdf, INTEGRATOR_STATE(state, path, min_ray_pdf));
|
||||
|
|
|
@ -24,6 +24,28 @@ CCL_NAMESPACE_BEGIN
|
|||
/* Guiding */
|
||||
brecht marked this conversation as resolved
Outdated
Sergey Sharybin
commented
Is it possible to remove the permutation of the Is it possible to remove the permutation of the `RIS_COSINE` and `RIS_INCOMMING_RADIANCE`?
Sebastian Herholz
commented
Done, Done,
The other define `# define RIS_INCOMING_RADIANCE` will be gone after we bumped the Open PGL to 0.5.0
|
||||
|
||||
Sergey Sharybin
commented
I think we can make the 0.5 version required. Other than that, I am not a fan of such implicit assumption that the I think we can make the 0.5 version required.
Other than that, I am not a fan of such implicit assumption that the `OPENPGL_VERSION_MAJOR` is 0. We really need to have an utility macro like I've shown in the comment in the #106861.
Sebastian Herholz
commented
I already talked with Ray. As soon as every dependency package updated to Open PGL 0.5 I would like to bump the minimal required version to 0.5 and get rid of all these defines. I already talked with Ray. As soon as every dependency package updated to Open PGL 0.5 I would like to bump the minimal required version to 0.5 and get rid of all these defines.
Brecht Van Lommel
commented
OpenPGL was updated to 0.5 for all platforms, so this can be simplified. OpenPGL was updated to 0.5 for all platforms, so this can be simplified.
|
||||
#ifdef __PATH_GUIDING__
|
||||
|
||||
ccl_device float surface_shader_average_sample_weight_squared_roughness(
|
||||
ccl_private const ShaderData *sd)
|
||||
{
|
||||
float avg_squared_roughness = 0.0f;
|
||||
float sum_sample_weight = 0.0f;
|
||||
for (int i = 0; i < sd->num_closure; i++) {
|
||||
ccl_private const ShaderClosure *sc = &sd->closure[i];
|
||||
|
||||
if (!CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) {
|
||||
continue;
|
||||
}
|
||||
avg_squared_roughness += sc->sample_weight * bsdf_get_specular_roughness_squared(sc);
|
||||
sum_sample_weight += sc->sample_weight;
|
||||
}
|
||||
|
||||
avg_squared_roughness = avg_squared_roughness > 0.0f ?
|
||||
avg_squared_roughness / sum_sample_weight :
|
||||
0.0f;
|
||||
return avg_squared_roughness;
|
||||
}
|
||||
|
||||
ccl_device_inline void surface_shader_prepare_guiding(KernelGlobals kg,
|
||||
IntegratorState state,
|
||||
ccl_private ShaderData *sd,
|
||||
|
@ -36,6 +58,9 @@ ccl_device_inline void surface_shader_prepare_guiding(KernelGlobals kg,
|
|||
}
|
||||
|
||||
const float surface_guiding_probability = kernel_data.integrator.surface_guiding_probability;
|
||||
const int guiding_directional_sampling_type =
|
||||
kernel_data.integrator.guiding_directional_sampling_type;
|
||||
const float guiding_roughness_threshold = kernel_data.integrator.guiding_roughness_threshold;
|
||||
float rand_bsdf_guiding = path_state_rng_1D(kg, rng_state, PRNG_SURFACE_BSDF_GUIDING);
|
||||
|
||||
/* Compute proportion of diffuse BSDF and BSSRDFs. */
|
||||
|
@ -43,6 +68,8 @@ ccl_device_inline void surface_shader_prepare_guiding(KernelGlobals kg,
|
|||
float bssrdf_sampling_fraction = 0.0f;
|
||||
float bsdf_bssrdf_sampling_sum = 0.0f;
|
||||
|
||||
bool fully_opaque = true;
|
||||
|
||||
for (int i = 0; i < sd->num_closure; i++) {
|
||||
ShaderClosure *sc = &sd->closure[i];
|
||||
if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) {
|
||||
|
@ -56,6 +83,10 @@ ccl_device_inline void surface_shader_prepare_guiding(KernelGlobals kg,
|
|||
if (CLOSURE_IS_BSSRDF(sc->type)) {
|
||||
bssrdf_sampling_fraction += sweight;
|
||||
}
|
||||
|
||||
if (CLOSURE_IS_BSDF_TRANSPARENT(sc->type) || CLOSURE_IS_BSDF_TRANSMISSION(sc->type)) {
|
||||
fully_opaque = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,17 +95,36 @@ ccl_device_inline void surface_shader_prepare_guiding(KernelGlobals kg,
|
|||
bssrdf_sampling_fraction /= bsdf_bssrdf_sampling_sum;
|
||||
}
|
||||
|
||||
/* Init guiding (diffuse BSDFs only for now). */
|
||||
if (!(diffuse_sampling_fraction > 0.0f &&
|
||||
guiding_bsdf_init(kg, state, sd->P, sd->N, rand_bsdf_guiding)))
|
||||
/* Init guiding */
|
||||
/* The the roughness because the function returns alpha.x * alpha.y. In addition alpha is squared
|
||||
brecht marked this conversation as resolved
Outdated
Sergey Sharybin
commented
Units seems a bit odd: comparison of toughness with roughness^2. Is this expected? Units seems a bit odd: comparison of toughness with roughness^2. Is this expected?
Sebastian Herholz
commented
This is due to the fact that Blender/Cycles uses This is due to the fact that Blender/Cycles uses `roughness^2` internally and squared roughness returns `alpha.x * alpha.y` so it is actually `(roughness^2)^2` compared to the user input.
I refactored everything to make this more clear and convert the `guiding_roughness_threshold` to be `guiding_roughness_threshold^2`.
|
||||
* again */
|
||||
float avg_roughness = surface_shader_average_sample_weight_squared_roughness(sd);
|
||||
avg_roughness = safe_sqrtf(avg_roughness);
|
||||
if (!fully_opaque || avg_roughness < guiding_roughness_threshold ||
|
||||
((guiding_directional_sampling_type == GUIDING_DIRECTIONAL_SAMPLING_TYPE_PRODUCT_MIS) &&
|
||||
(diffuse_sampling_fraction <= 0.0f)) ||
|
||||
!guiding_bsdf_init(kg, state, sd->P, sd->N, rand_bsdf_guiding))
|
||||
{
|
||||
state->guiding.use_surface_guiding = false;
|
||||
state->guiding.surface_guiding_sampling_prob = 0.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
state->guiding.use_surface_guiding = true;
|
||||
state->guiding.surface_guiding_sampling_prob = surface_guiding_probability *
|
||||
diffuse_sampling_fraction;
|
||||
if (kernel_data.integrator.guiding_directional_sampling_type ==
|
||||
GUIDING_DIRECTIONAL_SAMPLING_TYPE_PRODUCT_MIS)
|
||||
{
|
||||
state->guiding.surface_guiding_sampling_prob = surface_guiding_probability *
|
||||
diffuse_sampling_fraction;
|
||||
}
|
||||
else if (kernel_data.integrator.guiding_directional_sampling_type ==
|
||||
GUIDING_DIRECTIONAL_SAMPLING_TYPE_RIS)
|
||||
{
|
||||
state->guiding.surface_guiding_sampling_prob = surface_guiding_probability;
|
||||
}
|
||||
else { // GUIDING_DIRECTIONAL_SAMPLING_TYPE_ROUGHNESS
|
||||
state->guiding.surface_guiding_sampling_prob = surface_guiding_probability * avg_roughness;
|
||||
}
|
||||
state->guiding.bssrdf_sampling_prob = bssrdf_sampling_fraction;
|
||||
state->guiding.sample_surface_guiding_rand = rand_bsdf_guiding;
|
||||
|
||||
|
@ -325,12 +375,20 @@ ccl_device_inline
|
|||
kg, sd, wo, NULL, bsdf_eval, 0.0f, 0.0f, light_shader_flags);
|
||||
|
||||
#if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 4
|
||||
if (state->guiding.use_surface_guiding) {
|
||||
if (pdf > 0.0f && state->guiding.use_surface_guiding) {
|
||||
const float guiding_sampling_prob = state->guiding.surface_guiding_sampling_prob;
|
||||
const float bssrdf_sampling_prob = state->guiding.bssrdf_sampling_prob;
|
||||
const float guide_pdf = guiding_bsdf_pdf(kg, state, wo);
|
||||
pdf = (guiding_sampling_prob * guide_pdf * (1.0f - bssrdf_sampling_prob)) +
|
||||
(1.0f - guiding_sampling_prob) * pdf;
|
||||
|
||||
if (kernel_data.integrator.guiding_directional_sampling_type ==
|
||||
GUIDING_DIRECTIONAL_SAMPLING_TYPE_RIS)
|
||||
{
|
||||
pdf = (0.5f * guide_pdf * (1.0f - bssrdf_sampling_prob)) + 0.5f * pdf;
|
||||
}
|
||||
else {
|
||||
pdf = (guiding_sampling_prob * guide_pdf * (1.0f - bssrdf_sampling_prob)) +
|
||||
(1.0f - guiding_sampling_prob) * pdf;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -406,17 +464,17 @@ surface_shader_bssrdf_sample_weight(ccl_private const ShaderData *ccl_restrict s
|
|||
/* Sample direction for picked BSDF, and return evaluation and pdf for all
|
||||
* BSDFs combined using MIS. */
|
||||
|
||||
ccl_device int surface_shader_bsdf_guided_sample_closure(KernelGlobals kg,
|
||||
IntegratorState state,
|
||||
ccl_private ShaderData *sd,
|
||||
ccl_private const ShaderClosure *sc,
|
||||
const float3 rand_bsdf,
|
||||
ccl_private BsdfEval *bsdf_eval,
|
||||
ccl_private float3 *wo,
|
||||
ccl_private float *bsdf_pdf,
|
||||
ccl_private float *unguided_bsdf_pdf,
|
||||
ccl_private float2 *sampled_rougness,
|
||||
ccl_private float *eta)
|
||||
ccl_device int surface_shader_bsdf_guided_sample_closure_mis(KernelGlobals kg,
|
||||
IntegratorState state,
|
||||
ccl_private ShaderData *sd,
|
||||
ccl_private const ShaderClosure *sc,
|
||||
const float3 rand_bsdf,
|
||||
ccl_private BsdfEval *bsdf_eval,
|
||||
ccl_private float3 *wo,
|
||||
ccl_private float *bsdf_pdf,
|
||||
ccl_private float *unguided_bsdf_pdf,
|
||||
ccl_private float2 *sampled_rougness,
|
||||
ccl_private float *eta)
|
||||
{
|
||||
/* BSSRDF should already have been handled elsewhere. */
|
||||
kernel_assert(CLOSURE_IS_BSDF(sc->type));
|
||||
|
@ -478,6 +536,10 @@ ccl_device int surface_shader_bsdf_guided_sample_closure(KernelGlobals kg,
|
|||
|
||||
label = bsdf_label(kg, &sd->closure[idx], *wo);
|
||||
}
|
||||
else {
|
||||
*bsdf_pdf = 0.0f;
|
||||
*unguided_bsdf_pdf = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
kernel_assert(reduce_min(bsdf_eval_sum(bsdf_eval)) >= 0.0f);
|
||||
|
@ -499,6 +561,9 @@ ccl_device int surface_shader_bsdf_guided_sample_closure(KernelGlobals kg,
|
|||
sampled_rougness,
|
||||
eta);
|
||||
# if 0
|
||||
// Code path to validate the estimation of the label, sampled roughness and eta
|
||||
// This should be activated from time to time when the BSDFs change to check if everything
|
||||
// is still working correctly.
|
||||
if (*unguided_bsdf_pdf > 0.0f) {
|
||||
surface_shader_validate_bsdf_sample(kg, sc, *wo, label, sampled_roughness, eta);
|
||||
}
|
||||
|
@ -529,6 +594,309 @@ ccl_device int surface_shader_bsdf_guided_sample_closure(KernelGlobals kg,
|
|||
|
||||
return label;
|
||||
}
|
||||
|
||||
Sergey Sharybin
commented
Is there a link to a paper we can add here to help understanding all the math which is going on in the function? Is there a link to a paper we can add here to help understanding all the math which is going on in the function?
Sebastian Herholz
commented
This is an extension/variant of the standard RIS where I added some stuff. This is an extension/variant of the standard RIS where I added some stuff.
A detailed description of the method with all the insides will be part of the Siggraph2023 Course on path guiding, I can add a link as soon as the course notes are online.
|
||||
ccl_device int surface_shader_bsdf_guided_sample_closure_ris(KernelGlobals kg,
|
||||
IntegratorState state,
|
||||
ccl_private ShaderData *sd,
|
||||
ccl_private const ShaderClosure *sc,
|
||||
const float3 rand_bsdf,
|
||||
ccl_private const RNGState *rng_state,
|
||||
ccl_private BsdfEval *bsdf_eval,
|
||||
ccl_private float3 *wo,
|
||||
ccl_private float *bsdf_pdf,
|
||||
ccl_private float *mis_pdf,
|
||||
ccl_private float *unguided_bsdf_pdf,
|
||||
ccl_private float2 *sampled_roughness,
|
||||
ccl_private float *eta)
|
||||
{
|
||||
/* BSSRDF should already have been handled elsewhere. */
|
||||
kernel_assert(CLOSURE_IS_BSDF(sc->type));
|
||||
|
||||
const bool use_surface_guiding = state->guiding.use_surface_guiding;
|
||||
const float guiding_sampling_prob = state->guiding.surface_guiding_sampling_prob;
|
||||
const float bssrdf_sampling_prob = state->guiding.bssrdf_sampling_prob;
|
||||
|
||||
/* Decide between sampling guiding distribution and BSDF. */
|
||||
float rand_bsdf_guiding = state->guiding.sample_surface_guiding_rand;
|
||||
|
||||
/* Initialize to zero. */
|
||||
int label = LABEL_NONE;
|
||||
Spectrum eval = zero_spectrum();
|
||||
bsdf_eval_init(bsdf_eval, CLOSURE_NONE_ID, eval);
|
||||
|
||||
*unguided_bsdf_pdf = 0.0f;
|
||||
float guide_pdf = 0.0f;
|
||||
|
||||
if (use_surface_guiding && guiding_sampling_prob > 0.0f) {
|
||||
/* Performing guided sampling using RIS */
|
||||
|
||||
// selected RIS candidate
|
||||
int ris_idx = 0;
|
||||
|
||||
// meta data for the two RIS candidates
|
||||
GuidingRISSample ris_samples[2];
|
||||
ris_samples[0].rand = rand_bsdf;
|
||||
ris_samples[1].rand = path_state_rng_3D(kg, rng_state, PRNG_SURFACE_RIS_GUIDING_0);
|
||||
|
||||
// ----------------------------------------------------
|
||||
// generate the first RIS candidate using a BSDF sample
|
||||
brecht marked this conversation as resolved
Outdated
Sergey Sharybin
commented
Here and everywhere else in the patch: do not omit the 0 suffix (0.0f, not 0.f). This is per the style guide: https://wiki.blender.org/wiki/Style_Guide/C_Cpp#Value_Literals Here and everywhere else in the patch: do not omit the 0 suffix (0.0f, not 0.f).
This is per the style guide: https://wiki.blender.org/wiki/Style_Guide/C_Cpp#Value_Literals
Sebastian Herholz
commented
Done Done
|
||||
// ----------------------------------------------------
|
||||
ris_samples[0].label = bsdf_sample(kg,
|
||||
sd,
|
||||
sc,
|
||||
INTEGRATOR_STATE(state, path, flag),
|
||||
ris_samples[0].rand,
|
||||
&ris_samples[0].eval,
|
||||
&ris_samples[0].wo,
|
||||
&ris_samples[0].bsdf_pdf,
|
||||
&ris_samples[0].sampled_roughness,
|
||||
&ris_samples[0].eta);
|
||||
|
||||
bsdf_eval_init(&ris_samples[0].bsdf_eval, sc->type, ris_samples[0].eval * sc->weight);
|
||||
if (ris_samples[0].bsdf_pdf > 0.0f) {
|
||||
if (sd->num_closure > 1) {
|
||||
float sweight = sc->sample_weight;
|
||||
ris_samples[0].bsdf_pdf = _surface_shader_bsdf_eval_mis(kg,
|
||||
sd,
|
||||
ris_samples[0].wo,
|
||||
sc,
|
||||
&ris_samples[0].bsdf_eval,
|
||||
(ris_samples[0].bsdf_pdf) *
|
||||
sweight,
|
||||
sweight,
|
||||
0);
|
||||
kernel_assert(reduce_min(bsdf_eval_sum(&ris_samples[0].bsdf_eval)) >= 0.0f);
|
||||
}
|
||||
ris_samples[0].avg_bsdf_eval = average(ris_samples[0].bsdf_eval.sum);
|
||||
ris_samples[0].guide_pdf = guiding_bsdf_pdf(kg, state, ris_samples[0].wo);
|
||||
ris_samples[0].guide_pdf *= (1.0f - bssrdf_sampling_prob);
|
||||
# ifdef RIS_INCOMING_RADIANCE
|
||||
ris_samples[0].incoming_radiance_pdf = guiding_surface_incoming_radiance_pdf(
|
||||
kg, state, ris_samples[0].wo);
|
||||
# else
|
||||
ris_samples[0].cosine = max(0.01f, fabsf(dot(sd->N, ris_samples[0].wo)));
|
||||
# endif
|
||||
ris_samples[0].bsdf_pdf = max(0.0f, ris_samples[0].bsdf_pdf);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// generate the second RIS candidate using a sample from the guiding distribution
|
||||
// ------------------------------------------------------------------------------
|
||||
float unguided_bsdf_pdfs[MAX_CLOSURE];
|
||||
bsdf_eval_init(&ris_samples[1].bsdf_eval, CLOSURE_NONE_ID, eval);
|
||||
ris_samples[1].guide_pdf = guiding_bsdf_sample(
|
||||
kg, state, float3_to_float2(ris_samples[1].rand), &ris_samples[1].wo);
|
||||
ris_samples[1].guide_pdf *= (1.0f - bssrdf_sampling_prob);
|
||||
# ifdef RIS_INCOMING_RADIANCE
|
||||
ris_samples[1].incoming_radiance_pdf = guiding_surface_incoming_radiance_pdf(
|
||||
kg, state, ris_samples[1].wo);
|
||||
# else
|
||||
ris_samples[1].cosine = max(0.01f, fabsf(dot(sd->N, ris_samples[1].wo)));
|
||||
sherholz marked this conversation as resolved
Outdated
Brecht Van Lommel
commented
Use Use `average()`
Sebastian Herholz
commented
Done Done
|
||||
# endif
|
||||
ris_samples[1].bsdf_pdf = surface_shader_bsdf_eval_pdfs(
|
||||
kg, sd, ris_samples[1].wo, &ris_samples[1].bsdf_eval, unguided_bsdf_pdfs, 0);
|
||||
ris_samples[1].label = ris_samples[0].label;
|
||||
ris_samples[1].avg_bsdf_eval = average(ris_samples[1].bsdf_eval.sum);
|
||||
ris_samples[1].bsdf_pdf = max(0.0f, ris_samples[1].bsdf_pdf);
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// calculate the RIS target functions for each RIS candidate
|
||||
// ------------------------------------------------------------------------------
|
||||
int num_ris_candidates = 0;
|
||||
float sum_ris_weights = 0.0f;
|
||||
if (calculate_ris_target(&ris_samples[0], guiding_sampling_prob)) {
|
||||
sum_ris_weights += ris_samples[0].ris_weight;
|
||||
num_ris_candidates++;
|
||||
}
|
||||
kernel_assert(ris_samples[0].ris_weight >= 0.0f);
|
||||
kernel_assert(sum_ris_weights >= 0.0f);
|
||||
|
||||
if (calculate_ris_target(&ris_samples[1], guiding_sampling_prob)) {
|
||||
sum_ris_weights += ris_samples[1].ris_weight;
|
||||
brecht marked this conversation as resolved
Outdated
Sergey Sharybin
commented
Should this be instead Should this be instead `kernel_assert(risSamples[1].ris_weight >= 0.0f)` ?
Otherwise if the first RIS sample weight is 0.5, and the second RIS sample is -0.1 we will not catch the issue with this assert.
Sebastian Herholz
commented
I agree, I changed it to test in both cases for the I agree, I changed it to test in both cases for the `ris_weight` as well
|
||||
num_ris_candidates++;
|
||||
}
|
||||
kernel_assert(ris_samples[1].ris_weight >= 0.0f);
|
||||
kernel_assert(sum_ris_weights >= 0.0f);
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Sample/Select a sample from the RIS candidates proportional to the target
|
||||
// ------------------------------------------------------------------------------
|
||||
if (num_ris_candidates == 0 || !(sum_ris_weights > 1e-10f)) {
|
||||
*bsdf_pdf = 0.0f;
|
||||
*mis_pdf = 0.0f;
|
||||
return label;
|
||||
}
|
||||
|
||||
float rand_ris_select = rand_bsdf_guiding * sum_ris_weights;
|
||||
|
||||
float sum_ris = 0.0f;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
sum_ris += ris_samples[i].ris_weight;
|
||||
if (rand_ris_select <= sum_ris) {
|
||||
ris_idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
kernel_assert(sum_ris >= 0.0f);
|
||||
kernel_assert(ris_idx < 2);
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// Fill in the sample data for the selected RIS candidate
|
||||
// ------------------------------------------------------------------------------
|
||||
guide_pdf = ris_samples[ris_idx].ris_target * (2.0f / sum_ris_weights);
|
||||
*unguided_bsdf_pdf = ris_samples[ris_idx].bsdf_pdf;
|
||||
*mis_pdf = 0.5f * (ris_samples[ris_idx].bsdf_pdf + ris_samples[ris_idx].guide_pdf);
|
||||
*bsdf_pdf = guide_pdf;
|
||||
|
||||
*wo = ris_samples[ris_idx].wo;
|
||||
label = ris_samples[ris_idx].label;
|
||||
|
||||
*sampled_roughness = ris_samples[ris_idx].sampled_roughness;
|
||||
*eta = ris_samples[ris_idx].eta;
|
||||
*bsdf_eval = ris_samples[ris_idx].bsdf_eval;
|
||||
|
||||
kernel_assert(isfinite_safe(guide_pdf));
|
||||
kernel_assert(isfinite_safe(*bsdf_pdf));
|
||||
|
||||
if (!(*bsdf_pdf > 1e-10f)) {
|
||||
*bsdf_pdf = 0.0f;
|
||||
*mis_pdf = 0.0f;
|
||||
return label;
|
||||
}
|
||||
|
||||
kernel_assert(*bsdf_pdf > 0.0f);
|
||||
kernel_assert(*bsdf_pdf >= 1e-20f);
|
||||
kernel_assert(guide_pdf >= 0.0f);
|
||||
|
||||
/// select label sampled_roughness and eta
|
||||
if (ris_idx == 1 && ris_samples[1].bsdf_pdf > 0.0f) {
|
||||
|
||||
float rnd = path_state_rng_1D(kg, rng_state, PRNG_SURFACE_RIS_GUIDING_1);
|
||||
|
||||
float sum_pdfs = 0.0f;
|
||||
int idx = -1;
|
||||
for (int i = 0; i < sd->num_closure; i++) {
|
||||
sum_pdfs += unguided_bsdf_pdfs[i];
|
||||
if (rnd <= sum_pdfs) {
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// kernel_assert(idx >= 0);
|
||||
/* Set the default idx to the last in the list.
|
||||
* in case of numerical problems and rand_bsdf_guiding is just >=1.0f and
|
||||
* the sum of all unguided_bsdf_pdfs is just < 1.0f. */
|
||||
idx = (rnd > sum_pdfs) ? sd->num_closure - 1 : idx;
|
||||
|
||||
label = bsdf_label(kg, &sd->closure[idx], *wo);
|
||||
bsdf_roughness_eta(kg, &sd->closure[idx], sampled_roughness, eta);
|
||||
}
|
||||
|
||||
kernel_assert(isfinite_safe(*bsdf_pdf));
|
||||
kernel_assert(*bsdf_pdf >= 0.0f);
|
||||
kernel_assert(reduce_min(bsdf_eval_sum(bsdf_eval)) >= 0.0f);
|
||||
}
|
||||
else {
|
||||
/* Sample BSDF. */
|
||||
*bsdf_pdf = 0.0f;
|
||||
label = bsdf_sample(kg,
|
||||
sd,
|
||||
sc,
|
||||
INTEGRATOR_STATE(state, path, flag),
|
||||
rand_bsdf,
|
||||
&eval,
|
||||
wo,
|
||||
Sergey Sharybin
commented
Is it intended for the merge? Is it intended for the merge?
Sebastian Herholz
commented
It is mainly there to be able to validate the label, roughness and eta estimation. Do you have a better idea or suggestion? It is mainly there to be able to validate the label, roughness and eta estimation.
this will be useful when the BSDF models change (e.g., after Principle_v2).
Do you have a better idea or suggestion?
Sergey Sharybin
commented
Not really, was just curious if it is something left over from earlier development, or still intended to be useful for debugging. One idea could be to use Not really, was just curious if it is something left over from earlier development, or still intended to be useful for debugging.
One idea could be to use `#ifdef WITH_CYCLES_DEBUG`, but not really sure.
Brecht Van Lommel
commented
I think it's fine as is, but could use a comment. I think it's fine as is, but could use a comment.
Sebastian Herholz
commented
done done
Sebastian Herholz
commented
done done
|
||||
unguided_bsdf_pdf,
|
||||
sampled_roughness,
|
||||
eta);
|
||||
# if 0
|
||||
// Code path to validate the estimation of the label, sampled roughness and eta
|
||||
// This should be activated from time to time when the BSDFs change to check if everything
|
||||
// is still working correctly.
|
||||
if (*unguided_bsdf_pdf > 0.0f) {
|
||||
surface_shader_validate_bsdf_sample(kg, sc, *wo, label, sampled_roughness, eta);
|
||||
}
|
||||
# endif
|
||||
|
||||
if (*unguided_bsdf_pdf != 0.0f) {
|
||||
bsdf_eval_init(bsdf_eval, sc->type, eval * sc->weight);
|
||||
|
||||
kernel_assert(reduce_min(bsdf_eval_sum(bsdf_eval)) >= 0.0f);
|
||||
|
||||
if (sd->num_closure > 1) {
|
||||
float sweight = sc->sample_weight;
|
||||
*unguided_bsdf_pdf = _surface_shader_bsdf_eval_mis(
|
||||
kg, sd, *wo, sc, bsdf_eval, (*unguided_bsdf_pdf) * sweight, sweight, 0);
|
||||
kernel_assert(reduce_min(bsdf_eval_sum(bsdf_eval)) >= 0.0f);
|
||||
}
|
||||
*bsdf_pdf = *unguided_bsdf_pdf;
|
||||
*mis_pdf = *bsdf_pdf;
|
||||
}
|
||||
|
||||
kernel_assert(reduce_min(bsdf_eval_sum(bsdf_eval)) >= 0.0f);
|
||||
}
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
ccl_device int surface_shader_bsdf_guided_sample_closure(KernelGlobals kg,
|
||||
IntegratorState state,
|
||||
ccl_private ShaderData *sd,
|
||||
ccl_private const ShaderClosure *sc,
|
||||
const float3 rand_bsdf,
|
||||
ccl_private BsdfEval *bsdf_eval,
|
||||
ccl_private float3 *wo,
|
||||
ccl_private float *bsdf_pdf,
|
||||
ccl_private float *mis_pdf,
|
||||
ccl_private float *unguided_bsdf_pdf,
|
||||
ccl_private float2 *sampled_roughness,
|
||||
ccl_private float *eta,
|
||||
ccl_private const RNGState *rng_state)
|
||||
{
|
||||
int label;
|
||||
if (kernel_data.integrator.guiding_directional_sampling_type ==
|
||||
GUIDING_DIRECTIONAL_SAMPLING_TYPE_PRODUCT_MIS ||
|
||||
kernel_data.integrator.guiding_directional_sampling_type ==
|
||||
GUIDING_DIRECTIONAL_SAMPLING_TYPE_ROUGHNESS)
|
||||
{
|
||||
label = surface_shader_bsdf_guided_sample_closure_mis(kg,
|
||||
state,
|
||||
sd,
|
||||
sc,
|
||||
rand_bsdf,
|
||||
bsdf_eval,
|
||||
wo,
|
||||
bsdf_pdf,
|
||||
unguided_bsdf_pdf,
|
||||
sampled_roughness,
|
||||
eta);
|
||||
*mis_pdf = (*unguided_bsdf_pdf > 0.0f) ? *bsdf_pdf : 0.0f;
|
||||
}
|
||||
else if (kernel_data.integrator.guiding_directional_sampling_type ==
|
||||
GUIDING_DIRECTIONAL_SAMPLING_TYPE_RIS)
|
||||
{
|
||||
label = surface_shader_bsdf_guided_sample_closure_ris(kg,
|
||||
state,
|
||||
sd,
|
||||
sc,
|
||||
rand_bsdf,
|
||||
rng_state,
|
||||
bsdf_eval,
|
||||
wo,
|
||||
bsdf_pdf,
|
||||
mis_pdf,
|
||||
unguided_bsdf_pdf,
|
||||
sampled_roughness,
|
||||
eta);
|
||||
}
|
||||
if (!(*unguided_bsdf_pdf > 0.0f)) {
|
||||
*bsdf_pdf = 0.0f;
|
||||
*mis_pdf = 0.0f;
|
||||
}
|
||||
return label;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Sample direction for picked BSDF, and return evaluation and pdf for all
|
||||
|
|
|
@ -163,6 +163,11 @@ enum PathTraceDimension {
|
|||
PRNG_SURFACE_AO = 4,
|
||||
PRNG_SURFACE_BEVEL = 5,
|
||||
PRNG_SURFACE_BSDF_GUIDING = 6,
|
||||
|
||||
/* Guiding RIS */
|
||||
PRNG_SURFACE_RIS_GUIDING_0 = 10,
|
||||
PRNG_SURFACE_RIS_GUIDING_1 = 11,
|
||||
|
||||
/* Volume */
|
||||
PRNG_VOLUME_PHASE = 3,
|
||||
PRNG_VOLUME_PHASE_CHANNEL = 4,
|
||||
|
@ -506,6 +511,16 @@ typedef enum GuidingDistributionType {
|
|||
GUIDING_NUM_TYPES,
|
||||
} GuidingDistributionType;
|
||||
|
||||
/* Guiding Directional Sampling Type */
|
||||
|
||||
typedef enum GuidingDirectionalSamplingType {
|
||||
GUIDING_DIRECTIONAL_SAMPLING_TYPE_PRODUCT_MIS = 0,
|
||||
GUIDING_DIRECTIONAL_SAMPLING_TYPE_RIS = 1,
|
||||
GUIDING_DIRECTIONAL_SAMPLING_TYPE_ROUGHNESS = 2,
|
||||
|
||||
GUIDING_DIRECTIONAL_SAMPLING_NUM_TYPES,
|
||||
} GuidingDirectionalSamplingType;
|
||||
|
||||
/* Camera Type */
|
||||
|
||||
enum CameraType { CAMERA_PERSPECTIVE, CAMERA_ORTHOGRAPHIC, CAMERA_PANORAMA };
|
||||
|
|
|
@ -60,10 +60,17 @@ NODE_DEFINE(Integrator)
|
|||
SOCKET_INT(volume_max_steps, "Volume Max Steps", 1024);
|
||||
SOCKET_FLOAT(volume_step_rate, "Volume Step Rate", 1.0f);
|
||||
|
||||
static NodeEnum guiding_ditribution_enum;
|
||||
guiding_ditribution_enum.insert("PARALLAX_AWARE_VMM", GUIDING_TYPE_PARALLAX_AWARE_VMM);
|
||||
guiding_ditribution_enum.insert("DIRECTIONAL_QUAD_TREE", GUIDING_TYPE_DIRECTIONAL_QUAD_TREE);
|
||||
guiding_ditribution_enum.insert("VMM", GUIDING_TYPE_VMM);
|
||||
static NodeEnum guiding_distribution_enum;
|
||||
guiding_distribution_enum.insert("PARALLAX_AWARE_VMM", GUIDING_TYPE_PARALLAX_AWARE_VMM);
|
||||
guiding_distribution_enum.insert("DIRECTIONAL_QUAD_TREE", GUIDING_TYPE_DIRECTIONAL_QUAD_TREE);
|
||||
guiding_distribution_enum.insert("VMM", GUIDING_TYPE_VMM);
|
||||
|
||||
static NodeEnum guiding_directional_sampling_type_enum;
|
||||
guiding_directional_sampling_type_enum.insert("MIS",
|
||||
GUIDING_DIRECTIONAL_SAMPLING_TYPE_PRODUCT_MIS);
|
||||
guiding_directional_sampling_type_enum.insert("RIS", GUIDING_DIRECTIONAL_SAMPLING_TYPE_RIS);
|
||||
guiding_directional_sampling_type_enum.insert("ROUGHNESS",
|
||||
GUIDING_DIRECTIONAL_SAMPLING_TYPE_ROUGHNESS);
|
||||
|
||||
SOCKET_BOOLEAN(use_guiding, "Guiding", false);
|
||||
SOCKET_BOOLEAN(deterministic_guiding, "Deterministic Guiding", true);
|
||||
|
@ -76,8 +83,13 @@ NODE_DEFINE(Integrator)
|
|||
SOCKET_BOOLEAN(use_guiding_mis_weights, "Use MIS Weights", true);
|
||||
SOCKET_ENUM(guiding_distribution_type,
|
||||
"Guiding Distribution Type",
|
||||
guiding_ditribution_enum,
|
||||
guiding_distribution_enum,
|
||||
GUIDING_TYPE_PARALLAX_AWARE_VMM);
|
||||
SOCKET_ENUM(guiding_directional_sampling_type,
|
||||
"Guiding Directional Sampling Type",
|
||||
guiding_directional_sampling_type_enum,
|
||||
GUIDING_DIRECTIONAL_SAMPLING_TYPE_RIS);
|
||||
SOCKET_FLOAT(guiding_roughness_threshold, "Guiding Roughness Threshold", 0.05f);
|
||||
|
||||
SOCKET_BOOLEAN(caustics_reflective, "Reflective Caustics", true);
|
||||
SOCKET_BOOLEAN(caustics_refractive, "Refractive Caustics", true);
|
||||
|
@ -239,6 +251,8 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene
|
|||
kintegrator->use_guiding_direct_light = use_guiding_direct_light;
|
||||
kintegrator->use_guiding_mis_weights = use_guiding_mis_weights;
|
||||
kintegrator->guiding_distribution_type = guiding_params.type;
|
||||
kintegrator->guiding_directional_sampling_type = guiding_params.sampling_type;
|
||||
kintegrator->guiding_roughness_threshold = guiding_params.roughness_threshold;
|
||||
|
||||
kintegrator->seed = seed;
|
||||
|
||||
|
@ -409,7 +423,9 @@ GuidingParams Integrator::get_guiding_params(const Device *device) const
|
|||
guiding_params.type = guiding_distribution_type;
|
||||
guiding_params.training_samples = guiding_training_samples;
|
||||
guiding_params.deterministic = deterministic_guiding;
|
||||
|
||||
guiding_params.sampling_type = guiding_directional_sampling_type;
|
||||
// In Blender/Cycles the user set roughness is squared to behave more linear.
|
||||
guiding_params.roughness_threshold = guiding_roughness_threshold * guiding_roughness_threshold;
|
||||
return guiding_params;
|
||||
}
|
||||
CCL_NAMESPACE_END
|
||||
|
|
|
@ -54,6 +54,8 @@ class Integrator : public Node {
|
|||
NODE_SOCKET_API(bool, use_guiding_direct_light);
|
||||
NODE_SOCKET_API(bool, use_guiding_mis_weights);
|
||||
NODE_SOCKET_API(GuidingDistributionType, guiding_distribution_type);
|
||||
NODE_SOCKET_API(GuidingDirectionalSamplingType, guiding_directional_sampling_type);
|
||||
NODE_SOCKET_API(float, guiding_roughness_threshold);
|
||||
|
||||
NODE_SOCKET_API(bool, caustics_reflective)
|
||||
NODE_SOCKET_API(bool, caustics_refractive)
|
||||
|
|
We use snake style for variables, so
ris_sample
.Done