forked from bartvdbraak/blender
Cycles: Path Guiding: Adding guiding on glossy surfaces via RIS
Pull Request: https://projects.blender.org/blender/blender/pulls/107782
This commit is contained in:
parent
6cce149144
commit
8d17458569
@ -209,6 +209,21 @@ enum_guiding_distribution = (
|
|||||||
('VMM', "VMM", "Use von Mises-Fisher models as directional distribution", 2),
|
('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):
|
def enum_openimagedenoise_denoiser(self, context):
|
||||||
import _cycles
|
import _cycles
|
||||||
@ -568,6 +583,13 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
|
|||||||
default='PARALLAX_AWARE_VMM',
|
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(
|
use_surface_guiding: BoolProperty(
|
||||||
name="Surface Guiding",
|
name="Surface Guiding",
|
||||||
description="Use guiding when sampling directions on a surface",
|
description="Use guiding when sampling directions on a surface",
|
||||||
@ -617,6 +639,13 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
|
|||||||
default=True,
|
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(
|
max_bounces: IntProperty(
|
||||||
name="Max Bounces",
|
name="Max Bounces",
|
||||||
description="Total maximum number of 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.active = cscene.use_guiding
|
||||||
|
|
||||||
layout.prop(cscene, "guiding_distribution_type", text="Distribution Type")
|
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 = layout.column(align=True)
|
||||||
col.prop(cscene, "surface_guiding_probability")
|
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(
|
GuidingDistributionType guiding_distribution_type = (GuidingDistributionType)get_enum(
|
||||||
cscene, "guiding_distribution_type", GUIDING_NUM_TYPES, GUIDING_TYPE_PARALLAX_AWARE_VMM);
|
cscene, "guiding_distribution_type", GUIDING_NUM_TYPES, GUIDING_TYPE_PARALLAX_AWARE_VMM);
|
||||||
integrator->set_guiding_distribution_type(guiding_distribution_type);
|
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);
|
DenoiseParams denoise_params = get_denoise_params(b_scene, b_view_layer, background);
|
||||||
|
@ -15,6 +15,8 @@ struct GuidingParams {
|
|||||||
bool use_volume_guiding = false;
|
bool use_volume_guiding = false;
|
||||||
|
|
||||||
GuidingDistributionType type = GUIDING_TYPE_PARALLAX_AWARE_VMM;
|
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;
|
int training_samples = 128;
|
||||||
bool deterministic = false;
|
bool deterministic = false;
|
||||||
|
|
||||||
@ -24,7 +26,9 @@ struct GuidingParams {
|
|||||||
{
|
{
|
||||||
return !((use == other.use) && (use_surface_guiding == other.use_surface_guiding) &&
|
return !((use == other.use) && (use_surface_guiding == other.use_surface_guiding) &&
|
||||||
(use_volume_guiding == other.use_volume_guiding) && (type == other.type) &&
|
(use_volume_guiding == other.use_volume_guiding) && (type == other.type) &&
|
||||||
|
(sampling_type == other.sampling_type) &&
|
||||||
(training_samples == other.training_samples) &&
|
(training_samples == other.training_samples) &&
|
||||||
|
(roughness_threshold == other.roughness_threshold) &&
|
||||||
(deterministic == other.deterministic));
|
(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, surface_guiding_probability)
|
||||||
KERNEL_STRUCT_MEMBER(integrator, float, volume_guiding_probability)
|
KERNEL_STRUCT_MEMBER(integrator, float, volume_guiding_probability)
|
||||||
KERNEL_STRUCT_MEMBER(integrator, int, guiding_distribution_type)
|
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, use_guiding)
|
||||||
KERNEL_STRUCT_MEMBER(integrator, int, train_guiding)
|
KERNEL_STRUCT_MEMBER(integrator, int, train_guiding)
|
||||||
KERNEL_STRUCT_MEMBER(integrator, int, use_surface_guiding)
|
KERNEL_STRUCT_MEMBER(integrator, int, use_surface_guiding)
|
||||||
@ -216,6 +218,8 @@ KERNEL_STRUCT_MEMBER(integrator, int, use_guiding_mis_weights)
|
|||||||
|
|
||||||
/* Padding. */
|
/* Padding. */
|
||||||
KERNEL_STRUCT_MEMBER(integrator, int, pad1)
|
KERNEL_STRUCT_MEMBER(integrator, int, pad1)
|
||||||
|
KERNEL_STRUCT_MEMBER(integrator, int, pad2)
|
||||||
|
KERNEL_STRUCT_MEMBER(integrator, int, pad3)
|
||||||
KERNEL_STRUCT_END(KernelIntegrator)
|
KERNEL_STRUCT_END(KernelIntegrator)
|
||||||
|
|
||||||
/* SVM. For shader specialization. */
|
/* SVM. For shader specialization. */
|
||||||
|
@ -7,10 +7,66 @@
|
|||||||
#include "kernel/closure/bsdf.h"
|
#include "kernel/closure/bsdf.h"
|
||||||
#include "kernel/film/write.h"
|
#include "kernel/film/write.h"
|
||||||
|
|
||||||
|
#if OPENPGL_VERSION_MINOR >= 5
|
||||||
|
# define RIS_INCOMING_RADIANCE
|
||||||
|
#endif
|
||||||
|
|
||||||
CCL_NAMESPACE_BEGIN
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
/* Utilities. */
|
/* 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,
|
||||||
|
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__)
|
#if defined(__PATH_GUIDING__)
|
||||||
static pgl_vec3f guiding_vec3f(const float3 v)
|
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::SetPDFDirectionIn(state->guiding.path_segment, pdf);
|
||||||
openpgl::cpp::SetScatteringWeight(state->guiding.path_segment, guiding_vec3f(weight_rgb));
|
openpgl::cpp::SetScatteringWeight(state->guiding.path_segment, guiding_vec3f(weight_rgb));
|
||||||
openpgl::cpp::SetIsDelta(state->guiding.path_segment, false);
|
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);
|
openpgl::cpp::SetRoughness(state->guiding.path_segment, roughness);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -259,11 +315,11 @@ ccl_device_forceinline void guiding_record_volume_transmission(KernelGlobals kg,
|
|||||||
|
|
||||||
if (state->guiding.path_segment) {
|
if (state->guiding.path_segment) {
|
||||||
// TODO (sherholz): need to find a better way to avoid this check
|
// 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])) ||
|
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])) ||
|
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])))
|
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;
|
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);
|
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
|
#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 */
|
/* Guided Volume Phases */
|
||||||
|
|
||||||
ccl_device_forceinline bool guiding_phase_init(KernelGlobals kg,
|
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);
|
float2 bsdf_sampled_roughness = make_float2(1.0f, 1.0f);
|
||||||
float bsdf_eta = 1.0f;
|
float bsdf_eta = 1.0f;
|
||||||
|
float mis_pdf = 1.0f;
|
||||||
|
|
||||||
#if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 4
|
#if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 4
|
||||||
if (kernel_data.integrator.use_surface_guiding) {
|
if (kernel_data.integrator.use_surface_guiding) {
|
||||||
@ -383,9 +384,11 @@ ccl_device_forceinline int integrate_surface_bsdf_bssrdf_bounce(
|
|||||||
&bsdf_eval,
|
&bsdf_eval,
|
||||||
&bsdf_wo,
|
&bsdf_wo,
|
||||||
&bsdf_pdf,
|
&bsdf_pdf,
|
||||||
|
&mis_pdf,
|
||||||
&unguided_bsdf_pdf,
|
&unguided_bsdf_pdf,
|
||||||
&bsdf_sampled_roughness,
|
&bsdf_sampled_roughness,
|
||||||
&bsdf_eta);
|
&bsdf_eta,
|
||||||
|
rng_state);
|
||||||
|
|
||||||
if (bsdf_pdf == 0.0f || bsdf_eval_is_zero(&bsdf_eval)) {
|
if (bsdf_pdf == 0.0f || bsdf_eval_is_zero(&bsdf_eval)) {
|
||||||
return LABEL_NONE;
|
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)) {
|
if (bsdf_pdf == 0.0f || bsdf_eval_is_zero(&bsdf_eval)) {
|
||||||
return LABEL_NONE;
|
return LABEL_NONE;
|
||||||
}
|
}
|
||||||
|
mis_pdf = bsdf_pdf;
|
||||||
unguided_bsdf_pdf = bsdf_pdf;
|
unguided_bsdf_pdf = bsdf_pdf;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -445,7 +448,7 @@ ccl_device_forceinline int integrate_surface_bsdf_bssrdf_bounce(
|
|||||||
|
|
||||||
/* Update path state */
|
/* Update path state */
|
||||||
if (!(label & LABEL_TRANSPARENT)) {
|
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, mis_origin_n) = sd->N;
|
||||||
INTEGRATOR_STATE_WRITE(state, path, min_ray_pdf) = fminf(
|
INTEGRATOR_STATE_WRITE(state, path, min_ray_pdf) = fminf(
|
||||||
unguided_bsdf_pdf, INTEGRATOR_STATE(state, path, min_ray_pdf));
|
unguided_bsdf_pdf, INTEGRATOR_STATE(state, path, min_ray_pdf));
|
||||||
|
@ -24,6 +24,28 @@ CCL_NAMESPACE_BEGIN
|
|||||||
/* Guiding */
|
/* Guiding */
|
||||||
|
|
||||||
#ifdef __PATH_GUIDING__
|
#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,
|
ccl_device_inline void surface_shader_prepare_guiding(KernelGlobals kg,
|
||||||
IntegratorState state,
|
IntegratorState state,
|
||||||
ccl_private ShaderData *sd,
|
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 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);
|
float rand_bsdf_guiding = path_state_rng_1D(kg, rng_state, PRNG_SURFACE_BSDF_GUIDING);
|
||||||
|
|
||||||
/* Compute proportion of diffuse BSDF and BSSRDFs. */
|
/* 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 bssrdf_sampling_fraction = 0.0f;
|
||||||
float bsdf_bssrdf_sampling_sum = 0.0f;
|
float bsdf_bssrdf_sampling_sum = 0.0f;
|
||||||
|
|
||||||
|
bool fully_opaque = true;
|
||||||
|
|
||||||
for (int i = 0; i < sd->num_closure; i++) {
|
for (int i = 0; i < sd->num_closure; i++) {
|
||||||
ShaderClosure *sc = &sd->closure[i];
|
ShaderClosure *sc = &sd->closure[i];
|
||||||
if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) {
|
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)) {
|
if (CLOSURE_IS_BSSRDF(sc->type)) {
|
||||||
bssrdf_sampling_fraction += sweight;
|
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;
|
bssrdf_sampling_fraction /= bsdf_bssrdf_sampling_sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Init guiding (diffuse BSDFs only for now). */
|
/* Init guiding */
|
||||||
if (!(diffuse_sampling_fraction > 0.0f &&
|
/* The the roughness because the function returns alpha.x * alpha.y. In addition alpha is squared
|
||||||
guiding_bsdf_init(kg, state, sd->P, sd->N, rand_bsdf_guiding)))
|
* 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.use_surface_guiding = false;
|
||||||
|
state->guiding.surface_guiding_sampling_prob = 0.0f;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
state->guiding.use_surface_guiding = true;
|
state->guiding.use_surface_guiding = true;
|
||||||
|
if (kernel_data.integrator.guiding_directional_sampling_type ==
|
||||||
|
GUIDING_DIRECTIONAL_SAMPLING_TYPE_PRODUCT_MIS)
|
||||||
|
{
|
||||||
state->guiding.surface_guiding_sampling_prob = surface_guiding_probability *
|
state->guiding.surface_guiding_sampling_prob = surface_guiding_probability *
|
||||||
diffuse_sampling_fraction;
|
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.bssrdf_sampling_prob = bssrdf_sampling_fraction;
|
||||||
state->guiding.sample_surface_guiding_rand = rand_bsdf_guiding;
|
state->guiding.sample_surface_guiding_rand = rand_bsdf_guiding;
|
||||||
|
|
||||||
@ -325,13 +375,21 @@ ccl_device_inline
|
|||||||
kg, sd, wo, NULL, bsdf_eval, 0.0f, 0.0f, light_shader_flags);
|
kg, sd, wo, NULL, bsdf_eval, 0.0f, 0.0f, light_shader_flags);
|
||||||
|
|
||||||
#if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 4
|
#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 guiding_sampling_prob = state->guiding.surface_guiding_sampling_prob;
|
||||||
const float bssrdf_sampling_prob = state->guiding.bssrdf_sampling_prob;
|
const float bssrdf_sampling_prob = state->guiding.bssrdf_sampling_prob;
|
||||||
const float guide_pdf = guiding_bsdf_pdf(kg, state, wo);
|
const float guide_pdf = guiding_bsdf_pdf(kg, state, wo);
|
||||||
|
|
||||||
|
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)) +
|
pdf = (guiding_sampling_prob * guide_pdf * (1.0f - bssrdf_sampling_prob)) +
|
||||||
(1.0f - guiding_sampling_prob) * pdf;
|
(1.0f - guiding_sampling_prob) * pdf;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return pdf;
|
return pdf;
|
||||||
@ -406,7 +464,7 @@ surface_shader_bssrdf_sample_weight(ccl_private const ShaderData *ccl_restrict s
|
|||||||
/* Sample direction for picked BSDF, and return evaluation and pdf for all
|
/* Sample direction for picked BSDF, and return evaluation and pdf for all
|
||||||
* BSDFs combined using MIS. */
|
* BSDFs combined using MIS. */
|
||||||
|
|
||||||
ccl_device int surface_shader_bsdf_guided_sample_closure(KernelGlobals kg,
|
ccl_device int surface_shader_bsdf_guided_sample_closure_mis(KernelGlobals kg,
|
||||||
IntegratorState state,
|
IntegratorState state,
|
||||||
ccl_private ShaderData *sd,
|
ccl_private ShaderData *sd,
|
||||||
ccl_private const ShaderClosure *sc,
|
ccl_private const ShaderClosure *sc,
|
||||||
@ -478,6 +536,10 @@ ccl_device int surface_shader_bsdf_guided_sample_closure(KernelGlobals kg,
|
|||||||
|
|
||||||
label = bsdf_label(kg, &sd->closure[idx], *wo);
|
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);
|
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,
|
sampled_rougness,
|
||||||
eta);
|
eta);
|
||||||
# if 0
|
# 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) {
|
if (*unguided_bsdf_pdf > 0.0f) {
|
||||||
surface_shader_validate_bsdf_sample(kg, sc, *wo, label, sampled_roughness, eta);
|
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;
|
return label;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
// ----------------------------------------------------
|
||||||
|
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)));
|
||||||
|
# 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;
|
||||||
|
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,
|
||||||
|
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
|
#endif
|
||||||
|
|
||||||
/* Sample direction for picked BSDF, and return evaluation and pdf for all
|
/* Sample direction for picked BSDF, and return evaluation and pdf for all
|
||||||
|
@ -163,6 +163,11 @@ enum PathTraceDimension {
|
|||||||
PRNG_SURFACE_AO = 4,
|
PRNG_SURFACE_AO = 4,
|
||||||
PRNG_SURFACE_BEVEL = 5,
|
PRNG_SURFACE_BEVEL = 5,
|
||||||
PRNG_SURFACE_BSDF_GUIDING = 6,
|
PRNG_SURFACE_BSDF_GUIDING = 6,
|
||||||
|
|
||||||
|
/* Guiding RIS */
|
||||||
|
PRNG_SURFACE_RIS_GUIDING_0 = 10,
|
||||||
|
PRNG_SURFACE_RIS_GUIDING_1 = 11,
|
||||||
|
|
||||||
/* Volume */
|
/* Volume */
|
||||||
PRNG_VOLUME_PHASE = 3,
|
PRNG_VOLUME_PHASE = 3,
|
||||||
PRNG_VOLUME_PHASE_CHANNEL = 4,
|
PRNG_VOLUME_PHASE_CHANNEL = 4,
|
||||||
@ -506,6 +511,16 @@ typedef enum GuidingDistributionType {
|
|||||||
GUIDING_NUM_TYPES,
|
GUIDING_NUM_TYPES,
|
||||||
} GuidingDistributionType;
|
} 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 */
|
/* Camera Type */
|
||||||
|
|
||||||
enum CameraType { CAMERA_PERSPECTIVE, CAMERA_ORTHOGRAPHIC, CAMERA_PANORAMA };
|
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_INT(volume_max_steps, "Volume Max Steps", 1024);
|
||||||
SOCKET_FLOAT(volume_step_rate, "Volume Step Rate", 1.0f);
|
SOCKET_FLOAT(volume_step_rate, "Volume Step Rate", 1.0f);
|
||||||
|
|
||||||
static NodeEnum guiding_ditribution_enum;
|
static NodeEnum guiding_distribution_enum;
|
||||||
guiding_ditribution_enum.insert("PARALLAX_AWARE_VMM", GUIDING_TYPE_PARALLAX_AWARE_VMM);
|
guiding_distribution_enum.insert("PARALLAX_AWARE_VMM", GUIDING_TYPE_PARALLAX_AWARE_VMM);
|
||||||
guiding_ditribution_enum.insert("DIRECTIONAL_QUAD_TREE", GUIDING_TYPE_DIRECTIONAL_QUAD_TREE);
|
guiding_distribution_enum.insert("DIRECTIONAL_QUAD_TREE", GUIDING_TYPE_DIRECTIONAL_QUAD_TREE);
|
||||||
guiding_ditribution_enum.insert("VMM", GUIDING_TYPE_VMM);
|
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(use_guiding, "Guiding", false);
|
||||||
SOCKET_BOOLEAN(deterministic_guiding, "Deterministic Guiding", true);
|
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_BOOLEAN(use_guiding_mis_weights, "Use MIS Weights", true);
|
||||||
SOCKET_ENUM(guiding_distribution_type,
|
SOCKET_ENUM(guiding_distribution_type,
|
||||||
"Guiding Distribution Type",
|
"Guiding Distribution Type",
|
||||||
guiding_ditribution_enum,
|
guiding_distribution_enum,
|
||||||
GUIDING_TYPE_PARALLAX_AWARE_VMM);
|
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_reflective, "Reflective Caustics", true);
|
||||||
SOCKET_BOOLEAN(caustics_refractive, "Refractive 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_direct_light = use_guiding_direct_light;
|
||||||
kintegrator->use_guiding_mis_weights = use_guiding_mis_weights;
|
kintegrator->use_guiding_mis_weights = use_guiding_mis_weights;
|
||||||
kintegrator->guiding_distribution_type = guiding_params.type;
|
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;
|
kintegrator->seed = seed;
|
||||||
|
|
||||||
@ -409,7 +423,9 @@ GuidingParams Integrator::get_guiding_params(const Device *device) const
|
|||||||
guiding_params.type = guiding_distribution_type;
|
guiding_params.type = guiding_distribution_type;
|
||||||
guiding_params.training_samples = guiding_training_samples;
|
guiding_params.training_samples = guiding_training_samples;
|
||||||
guiding_params.deterministic = deterministic_guiding;
|
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;
|
return guiding_params;
|
||||||
}
|
}
|
||||||
CCL_NAMESPACE_END
|
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_direct_light);
|
||||||
NODE_SOCKET_API(bool, use_guiding_mis_weights);
|
NODE_SOCKET_API(bool, use_guiding_mis_weights);
|
||||||
NODE_SOCKET_API(GuidingDistributionType, guiding_distribution_type);
|
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_reflective)
|
||||||
NODE_SOCKET_API(bool, caustics_refractive)
|
NODE_SOCKET_API(bool, caustics_refractive)
|
||||||
|
Loading…
Reference in New Issue
Block a user