Changing volume parameters during rendering could cause a crash when guiding was enabled. It was due to an unintialized state paramter at the beginning of the path tracing process. In addition guiding is disabled when dealing with almost delta volumes (i.e., g close to 1.0 or -1.0).
548 lines
23 KiB
C++
548 lines
23 KiB
C++
/* SPDX-License-Identifier: Apache-2.0
|
|
* Copyright 2011-2022 Blender Foundation */
|
|
|
|
#pragma once
|
|
|
|
#include "kernel/closure/alloc.h"
|
|
#include "kernel/closure/bsdf.h"
|
|
#include "kernel/film/write.h"
|
|
|
|
CCL_NAMESPACE_BEGIN
|
|
|
|
/* Utilities. */
|
|
|
|
#if defined(__PATH_GUIDING__)
|
|
static pgl_vec3f guiding_vec3f(const float3 v)
|
|
{
|
|
return openpgl::cpp::Vector3(v.x, v.y, v.z);
|
|
}
|
|
|
|
static pgl_point3f guiding_point3f(const float3 v)
|
|
{
|
|
return openpgl::cpp::Point3(v.x, v.y, v.z);
|
|
}
|
|
#endif
|
|
|
|
/* Path recording for guiding. */
|
|
|
|
/* Record Surface Interactions */
|
|
|
|
/* Records/Adds a new path segment with the current path vertex on a surface.
|
|
* If the path is not terminated this call is usually followed by a call of
|
|
* guiding_record_surface_bounce. */
|
|
ccl_device_forceinline void guiding_record_surface_segment(KernelGlobals kg,
|
|
IntegratorState state,
|
|
ccl_private const ShaderData *sd)
|
|
{
|
|
#if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 1
|
|
if (!kernel_data.integrator.train_guiding) {
|
|
return;
|
|
}
|
|
|
|
const pgl_vec3f zero = guiding_vec3f(zero_float3());
|
|
const pgl_vec3f one = guiding_vec3f(one_float3());
|
|
|
|
state->guiding.path_segment = kg->opgl_path_segment_storage->NextSegment();
|
|
openpgl::cpp::SetPosition(state->guiding.path_segment, guiding_point3f(sd->P));
|
|
openpgl::cpp::SetDirectionOut(state->guiding.path_segment, guiding_vec3f(sd->I));
|
|
openpgl::cpp::SetVolumeScatter(state->guiding.path_segment, false);
|
|
openpgl::cpp::SetScatteredContribution(state->guiding.path_segment, zero);
|
|
openpgl::cpp::SetDirectContribution(state->guiding.path_segment, zero);
|
|
openpgl::cpp::SetTransmittanceWeight(state->guiding.path_segment, one);
|
|
openpgl::cpp::SetEta(state->guiding.path_segment, 1.0);
|
|
#endif
|
|
}
|
|
|
|
/* Records the surface scattering event at the current vertex position of the segment.*/
|
|
ccl_device_forceinline void guiding_record_surface_bounce(KernelGlobals kg,
|
|
IntegratorState state,
|
|
ccl_private const ShaderData *sd,
|
|
const Spectrum weight,
|
|
const float pdf,
|
|
const float3 N,
|
|
const float3 omega_in,
|
|
const float2 roughness,
|
|
const float eta)
|
|
{
|
|
#if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 4
|
|
if (!kernel_data.integrator.train_guiding) {
|
|
return;
|
|
}
|
|
const float min_roughness = safe_sqrtf(fminf(roughness.x, roughness.y));
|
|
const bool is_delta = (min_roughness == 0.0f);
|
|
const float3 weight_rgb = spectrum_to_rgb(weight);
|
|
const float3 normal = clamp(N, -one_float3(), one_float3());
|
|
|
|
kernel_assert(state->guiding.path_segment != nullptr);
|
|
|
|
openpgl::cpp::SetTransmittanceWeight(state->guiding.path_segment, guiding_vec3f(one_float3()));
|
|
openpgl::cpp::SetVolumeScatter(state->guiding.path_segment, false);
|
|
openpgl::cpp::SetNormal(state->guiding.path_segment, guiding_vec3f(normal));
|
|
openpgl::cpp::SetDirectionIn(state->guiding.path_segment, guiding_vec3f(omega_in));
|
|
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, is_delta);
|
|
openpgl::cpp::SetEta(state->guiding.path_segment, eta);
|
|
openpgl::cpp::SetRoughness(state->guiding.path_segment, min_roughness);
|
|
#endif
|
|
}
|
|
|
|
/* Records the emission at the current surface intersection (physical or virtual) */
|
|
ccl_device_forceinline void guiding_record_surface_emission(KernelGlobals kg,
|
|
IntegratorState state,
|
|
const Spectrum Le,
|
|
const float mis_weight)
|
|
{
|
|
#if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 1
|
|
if (!kernel_data.integrator.train_guiding) {
|
|
return;
|
|
}
|
|
const float3 Le_rgb = spectrum_to_rgb(Le);
|
|
|
|
openpgl::cpp::SetDirectContribution(state->guiding.path_segment, guiding_vec3f(Le_rgb));
|
|
openpgl::cpp::SetMiWeight(state->guiding.path_segment, mis_weight);
|
|
#endif
|
|
}
|
|
|
|
/* Record BSSRDF Interactions */
|
|
|
|
/* Records/Adds a new path segment where the vertex position is the point of entry
|
|
* of the sub surface scattering boundary.
|
|
* If the path is not terminated this call is usually followed by a call of
|
|
* guiding_record_bssrdf_weight and guiding_record_bssrdf_bounce. */
|
|
ccl_device_forceinline void guiding_record_bssrdf_segment(KernelGlobals kg,
|
|
IntegratorState state,
|
|
const float3 P,
|
|
const float3 I)
|
|
{
|
|
#if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 1
|
|
if (!kernel_data.integrator.train_guiding) {
|
|
return;
|
|
}
|
|
const pgl_vec3f zero = guiding_vec3f(zero_float3());
|
|
const pgl_vec3f one = guiding_vec3f(one_float3());
|
|
|
|
state->guiding.path_segment = kg->opgl_path_segment_storage->NextSegment();
|
|
openpgl::cpp::SetPosition(state->guiding.path_segment, guiding_point3f(P));
|
|
openpgl::cpp::SetDirectionOut(state->guiding.path_segment, guiding_vec3f(I));
|
|
openpgl::cpp::SetVolumeScatter(state->guiding.path_segment, true);
|
|
openpgl::cpp::SetScatteredContribution(state->guiding.path_segment, zero);
|
|
openpgl::cpp::SetDirectContribution(state->guiding.path_segment, zero);
|
|
openpgl::cpp::SetTransmittanceWeight(state->guiding.path_segment, one);
|
|
openpgl::cpp::SetEta(state->guiding.path_segment, 1.0);
|
|
#endif
|
|
}
|
|
|
|
/* Records the transmission of the path at the point of entry while passing
|
|
* the surface boundary.*/
|
|
ccl_device_forceinline void guiding_record_bssrdf_weight(KernelGlobals kg,
|
|
IntegratorState state,
|
|
const Spectrum weight,
|
|
const Spectrum albedo)
|
|
{
|
|
#if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 1
|
|
if (!kernel_data.integrator.train_guiding) {
|
|
return;
|
|
}
|
|
|
|
/* Note albedo left out here, will be included in guiding_record_bssrdf_bounce. */
|
|
const float3 weight_rgb = spectrum_to_rgb(safe_divide_color(weight, albedo));
|
|
|
|
kernel_assert(state->guiding.path_segment != nullptr);
|
|
|
|
openpgl::cpp::SetTransmittanceWeight(state->guiding.path_segment, guiding_vec3f(zero_float3()));
|
|
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.0f);
|
|
openpgl::cpp::SetRoughness(state->guiding.path_segment, 1.0f);
|
|
#endif
|
|
}
|
|
|
|
/* Records the direction at the point of entry the path takes when sampling the SSS contribution.
|
|
* If not terminated this function is usually followed by a call of
|
|
* guiding_record_volume_transmission to record the transmittance between the point of entry and
|
|
* the point of exit.*/
|
|
ccl_device_forceinline void guiding_record_bssrdf_bounce(KernelGlobals kg,
|
|
IntegratorState state,
|
|
const float pdf,
|
|
const float3 N,
|
|
const float3 omega_in,
|
|
const Spectrum weight,
|
|
const Spectrum albedo)
|
|
{
|
|
#if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 1
|
|
if (!kernel_data.integrator.train_guiding) {
|
|
return;
|
|
}
|
|
const float3 normal = clamp(N, -one_float3(), one_float3());
|
|
const float3 weight_rgb = spectrum_to_rgb(weight * albedo);
|
|
|
|
kernel_assert(state->guiding.path_segment != nullptr);
|
|
|
|
openpgl::cpp::SetVolumeScatter(state->guiding.path_segment, false);
|
|
openpgl::cpp::SetNormal(state->guiding.path_segment, guiding_vec3f(normal));
|
|
openpgl::cpp::SetDirectionIn(state->guiding.path_segment, guiding_vec3f(omega_in));
|
|
openpgl::cpp::SetPDFDirectionIn(state->guiding.path_segment, pdf);
|
|
openpgl::cpp::SetTransmittanceWeight(state->guiding.path_segment, guiding_vec3f(weight_rgb));
|
|
#endif
|
|
}
|
|
|
|
/* Record Volume Interactions */
|
|
|
|
/* Records/Adds a new path segment with the current path vertex being inside a volume.
|
|
* If the path is not terminated this call is usually followed by a call of
|
|
* guiding_record_volume_bounce. */
|
|
ccl_device_forceinline void guiding_record_volume_segment(KernelGlobals kg,
|
|
IntegratorState state,
|
|
const float3 P,
|
|
const float3 I)
|
|
{
|
|
#if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 1
|
|
if (!kernel_data.integrator.train_guiding) {
|
|
return;
|
|
}
|
|
const pgl_vec3f zero = guiding_vec3f(zero_float3());
|
|
const pgl_vec3f one = guiding_vec3f(one_float3());
|
|
|
|
state->guiding.path_segment = kg->opgl_path_segment_storage->NextSegment();
|
|
|
|
openpgl::cpp::SetPosition(state->guiding.path_segment, guiding_point3f(P));
|
|
openpgl::cpp::SetDirectionOut(state->guiding.path_segment, guiding_vec3f(I));
|
|
openpgl::cpp::SetVolumeScatter(state->guiding.path_segment, true);
|
|
openpgl::cpp::SetScatteredContribution(state->guiding.path_segment, zero);
|
|
openpgl::cpp::SetDirectContribution(state->guiding.path_segment, zero);
|
|
openpgl::cpp::SetTransmittanceWeight(state->guiding.path_segment, one);
|
|
openpgl::cpp::SetEta(state->guiding.path_segment, 1.0);
|
|
#endif
|
|
}
|
|
|
|
/* Records the volume scattering event at the current vertex position of the segment.*/
|
|
ccl_device_forceinline void guiding_record_volume_bounce(KernelGlobals kg,
|
|
IntegratorState state,
|
|
ccl_private const ShaderData *sd,
|
|
const Spectrum weight,
|
|
const float pdf,
|
|
const float3 omega_in,
|
|
const float roughness)
|
|
{
|
|
#if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 4
|
|
if (!kernel_data.integrator.train_guiding) {
|
|
return;
|
|
}
|
|
const float3 weight_rgb = spectrum_to_rgb(weight);
|
|
const float3 normal = make_float3(0.0f, 0.0f, 1.0f);
|
|
|
|
kernel_assert(state->guiding.path_segment != nullptr);
|
|
|
|
openpgl::cpp::SetVolumeScatter(state->guiding.path_segment, true);
|
|
openpgl::cpp::SetTransmittanceWeight(state->guiding.path_segment, guiding_vec3f(one_float3()));
|
|
openpgl::cpp::SetNormal(state->guiding.path_segment, guiding_vec3f(normal));
|
|
openpgl::cpp::SetDirectionIn(state->guiding.path_segment, guiding_vec3f(omega_in));
|
|
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::SetRoughness(state->guiding.path_segment, roughness);
|
|
#endif
|
|
}
|
|
|
|
/* Records the transmission (a.k.a. transmittance weight) between the current path segment
|
|
* and the next one, when the path is inside or passes a volume.*/
|
|
ccl_device_forceinline void guiding_record_volume_transmission(KernelGlobals kg,
|
|
IntegratorState state,
|
|
const float3 transmittance_weight)
|
|
{
|
|
#if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 1
|
|
if (!kernel_data.integrator.train_guiding) {
|
|
return;
|
|
}
|
|
|
|
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]) ||
|
|
std::isnan(transmittance_weight[0])) ||
|
|
(transmittance_weight[1] < 0.f || !std::isfinite(transmittance_weight[1]) ||
|
|
std::isnan(transmittance_weight[1])) ||
|
|
(transmittance_weight[2] < 0.f || !std::isfinite(transmittance_weight[2]) ||
|
|
std::isnan(transmittance_weight[2]))) {
|
|
}
|
|
else {
|
|
openpgl::cpp::SetTransmittanceWeight(state->guiding.path_segment,
|
|
guiding_vec3f(transmittance_weight));
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/* Records the emission of a volume at the vertex of the current path segment. */
|
|
ccl_device_forceinline void guiding_record_volume_emission(KernelGlobals kg,
|
|
IntegratorState state,
|
|
const Spectrum Le)
|
|
{
|
|
#if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 1
|
|
if (!kernel_data.integrator.train_guiding) {
|
|
return;
|
|
}
|
|
|
|
if (state->guiding.path_segment) {
|
|
const float3 Le_rgb = spectrum_to_rgb(Le);
|
|
|
|
openpgl::cpp::SetDirectContribution(state->guiding.path_segment, guiding_vec3f(Le_rgb));
|
|
openpgl::cpp::SetMiWeight(state->guiding.path_segment, 1.0f);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/* Record Light Interactions */
|
|
|
|
/* Adds a pseudo path vertex/segment when intersecting a virtual light source.
|
|
* (e.g., area, sphere, or disk light). This call is often followed
|
|
* a call of guiding_record_surface_emission, if the intersected light source
|
|
* emits light in the direction of the path. */
|
|
ccl_device_forceinline void guiding_record_light_surface_segment(
|
|
KernelGlobals kg, IntegratorState state, ccl_private const Intersection *ccl_restrict isect)
|
|
{
|
|
#if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 1
|
|
if (!kernel_data.integrator.train_guiding) {
|
|
return;
|
|
}
|
|
const pgl_vec3f zero = guiding_vec3f(zero_float3());
|
|
const pgl_vec3f one = guiding_vec3f(one_float3());
|
|
const float3 ray_P = INTEGRATOR_STATE(state, ray, P);
|
|
const float3 ray_D = INTEGRATOR_STATE(state, ray, D);
|
|
const float3 P = ray_P + isect->t * ray_D;
|
|
|
|
state->guiding.path_segment = kg->opgl_path_segment_storage->NextSegment();
|
|
openpgl::cpp::SetPosition(state->guiding.path_segment, guiding_point3f(P));
|
|
openpgl::cpp::SetDirectionOut(state->guiding.path_segment, guiding_vec3f(-ray_D));
|
|
openpgl::cpp::SetNormal(state->guiding.path_segment, guiding_vec3f(-ray_D));
|
|
openpgl::cpp::SetDirectionIn(state->guiding.path_segment, guiding_vec3f(ray_D));
|
|
openpgl::cpp::SetPDFDirectionIn(state->guiding.path_segment, 1.0f);
|
|
openpgl::cpp::SetVolumeScatter(state->guiding.path_segment, false);
|
|
openpgl::cpp::SetScatteredContribution(state->guiding.path_segment, zero);
|
|
openpgl::cpp::SetDirectContribution(state->guiding.path_segment, zero);
|
|
openpgl::cpp::SetTransmittanceWeight(state->guiding.path_segment, one);
|
|
openpgl::cpp::SetScatteringWeight(state->guiding.path_segment, one);
|
|
openpgl::cpp::SetEta(state->guiding.path_segment, 1.0f);
|
|
#endif
|
|
}
|
|
|
|
/* Records/Adds a final path segment when the path leaves the scene and
|
|
* intersects with a background light (e.g., background color,
|
|
* distant light, or env map). The vertex for this segment is placed along
|
|
* the current ray far out the scene.*/
|
|
ccl_device_forceinline void guiding_record_background(KernelGlobals kg,
|
|
IntegratorState state,
|
|
const Spectrum L,
|
|
const float mis_weight)
|
|
{
|
|
#if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 1
|
|
if (!kernel_data.integrator.train_guiding) {
|
|
return;
|
|
}
|
|
|
|
const float3 L_rgb = spectrum_to_rgb(L);
|
|
const float3 ray_P = INTEGRATOR_STATE(state, ray, P);
|
|
const float3 ray_D = INTEGRATOR_STATE(state, ray, D);
|
|
const float3 P = ray_P + (1e6f) * ray_D;
|
|
const float3 normal = make_float3(0.0f, 0.0f, 1.0f);
|
|
|
|
openpgl::cpp::PathSegment background_segment;
|
|
openpgl::cpp::SetPosition(&background_segment, guiding_vec3f(P));
|
|
openpgl::cpp::SetNormal(&background_segment, guiding_vec3f(normal));
|
|
openpgl::cpp::SetDirectionOut(&background_segment, guiding_vec3f(-ray_D));
|
|
openpgl::cpp::SetDirectContribution(&background_segment, guiding_vec3f(L_rgb));
|
|
openpgl::cpp::SetMiWeight(&background_segment, mis_weight);
|
|
kg->opgl_path_segment_storage->AddSegment(background_segment);
|
|
#endif
|
|
}
|
|
|
|
/* Records the scattered contribution of a next event estimation
|
|
* (i.e., a direct light estimate scattered at the current path vertex
|
|
* towards the previous vertex).*/
|
|
ccl_device_forceinline void guiding_record_direct_light(KernelGlobals kg,
|
|
IntegratorShadowState state)
|
|
{
|
|
#if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 1
|
|
if (!kernel_data.integrator.train_guiding) {
|
|
return;
|
|
}
|
|
if (state->shadow_path.path_segment) {
|
|
const Spectrum Lo = safe_divide_color(INTEGRATOR_STATE(state, shadow_path, throughput),
|
|
INTEGRATOR_STATE(state, shadow_path, unlit_throughput));
|
|
|
|
const float3 Lo_rgb = spectrum_to_rgb(Lo);
|
|
openpgl::cpp::AddScatteredContribution(state->shadow_path.path_segment, guiding_vec3f(Lo_rgb));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/* Record Russian Roulette */
|
|
/* Records the probability of continuing the path at the current path segment. */
|
|
ccl_device_forceinline void guiding_record_continuation_probability(
|
|
KernelGlobals kg, IntegratorState state, const float continuation_probability)
|
|
{
|
|
#if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 1
|
|
if (!kernel_data.integrator.train_guiding) {
|
|
return;
|
|
}
|
|
|
|
if (state->guiding.path_segment) {
|
|
openpgl::cpp::SetRussianRouletteProbability(state->guiding.path_segment,
|
|
continuation_probability);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/* Path guiding debug render passes. */
|
|
|
|
/* Write a set of path guiding related debug information (e.g., guiding probability at first
|
|
* bounce) into separate rendering passes.*/
|
|
ccl_device_forceinline void guiding_write_debug_passes(KernelGlobals kg,
|
|
IntegratorState state,
|
|
ccl_private const ShaderData *sd,
|
|
ccl_global float *ccl_restrict
|
|
render_buffer)
|
|
{
|
|
#if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 4
|
|
# ifdef WITH_CYCLES_DEBUG
|
|
if (!kernel_data.integrator.train_guiding) {
|
|
return;
|
|
}
|
|
|
|
if (INTEGRATOR_STATE(state, path, bounce) != 0) {
|
|
return;
|
|
}
|
|
|
|
const uint32_t render_pixel_index = INTEGRATOR_STATE(state, path, render_pixel_index);
|
|
const uint64_t render_buffer_offset = (uint64_t)render_pixel_index *
|
|
kernel_data.film.pass_stride;
|
|
ccl_global float *buffer = render_buffer + render_buffer_offset;
|
|
|
|
if (kernel_data.film.pass_guiding_probability != PASS_UNUSED) {
|
|
float guiding_prob = state->guiding.surface_guiding_sampling_prob;
|
|
film_write_pass_float(buffer + kernel_data.film.pass_guiding_probability, guiding_prob);
|
|
}
|
|
|
|
if (kernel_data.film.pass_guiding_avg_roughness != PASS_UNUSED) {
|
|
float avg_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_roughness += sc->sample_weight * bsdf_get_specular_roughness_squared(sc);
|
|
sum_sample_weight += sc->sample_weight;
|
|
}
|
|
|
|
avg_roughness = avg_roughness > 0.f ? avg_roughness / sum_sample_weight : 0.f;
|
|
|
|
film_write_pass_float(buffer + kernel_data.film.pass_guiding_avg_roughness, avg_roughness);
|
|
}
|
|
# endif
|
|
#endif
|
|
}
|
|
|
|
/* Guided BSDFs */
|
|
|
|
ccl_device_forceinline bool guiding_bsdf_init(KernelGlobals kg,
|
|
IntegratorState state,
|
|
const float3 P,
|
|
const float3 N,
|
|
ccl_private float &rand)
|
|
{
|
|
#if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 4
|
|
if (kg->opgl_surface_sampling_distribution->Init(
|
|
kg->opgl_guiding_field, guiding_point3f(P), rand, true)) {
|
|
kg->opgl_surface_sampling_distribution->ApplyCosineProduct(guiding_point3f(N));
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
return false;
|
|
}
|
|
|
|
ccl_device_forceinline float guiding_bsdf_sample(KernelGlobals kg,
|
|
IntegratorState state,
|
|
const float2 rand_bsdf,
|
|
ccl_private float3 *omega_in)
|
|
{
|
|
#if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 4
|
|
pgl_vec3f wo;
|
|
const pgl_point2f rand = openpgl::cpp::Point2(rand_bsdf.x, rand_bsdf.y);
|
|
const float pdf = kg->opgl_surface_sampling_distribution->SamplePDF(rand, wo);
|
|
*omega_in = make_float3(wo.x, wo.y, wo.z);
|
|
return pdf;
|
|
#else
|
|
return 0.0f;
|
|
#endif
|
|
}
|
|
|
|
ccl_device_forceinline float guiding_bsdf_pdf(KernelGlobals kg,
|
|
IntegratorState state,
|
|
const float3 omega_in)
|
|
{
|
|
#if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 4
|
|
return kg->opgl_surface_sampling_distribution->PDF(guiding_vec3f(omega_in));
|
|
#else
|
|
return 0.0f;
|
|
#endif
|
|
}
|
|
|
|
/* Guided Volume Phases */
|
|
|
|
ccl_device_forceinline bool guiding_phase_init(KernelGlobals kg,
|
|
IntegratorState state,
|
|
const float3 P,
|
|
const float3 D,
|
|
const float g,
|
|
ccl_private float &rand)
|
|
{
|
|
#if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 4
|
|
/* we do not need to guide almost delta phase functions */
|
|
if (fabsf(g) >= 0.99f) {
|
|
return false;
|
|
}
|
|
|
|
if (kg->opgl_volume_sampling_distribution->Init(
|
|
kg->opgl_guiding_field, guiding_point3f(P), rand, true)) {
|
|
kg->opgl_volume_sampling_distribution->ApplySingleLobeHenyeyGreensteinProduct(guiding_vec3f(D),
|
|
g);
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
return false;
|
|
}
|
|
|
|
ccl_device_forceinline float guiding_phase_sample(KernelGlobals kg,
|
|
IntegratorState state,
|
|
const float2 rand_phase,
|
|
ccl_private float3 *omega_in)
|
|
{
|
|
#if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 4
|
|
pgl_vec3f wo;
|
|
const pgl_point2f rand = openpgl::cpp::Point2(rand_phase.x, rand_phase.y);
|
|
const float pdf = kg->opgl_volume_sampling_distribution->SamplePDF(rand, wo);
|
|
*omega_in = make_float3(wo.x, wo.y, wo.z);
|
|
return pdf;
|
|
#else
|
|
return 0.0f;
|
|
#endif
|
|
}
|
|
|
|
ccl_device_forceinline float guiding_phase_pdf(KernelGlobals kg,
|
|
IntegratorState state,
|
|
const float3 omega_in)
|
|
{
|
|
#if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 4
|
|
return kg->opgl_volume_sampling_distribution->PDF(guiding_vec3f(omega_in));
|
|
#else
|
|
return 0.0f;
|
|
#endif
|
|
}
|
|
|
|
CCL_NAMESPACE_END
|