forked from bartvdbraak/blender
Cycles: reduce noise using regular path tracing + subsurface scattering with
new cubic and gaussian falloff. Like the branched path tracer, this will now shade all intersection points instead of using one at random.
This commit is contained in:
parent
25ffb79a0b
commit
722d0d92ad
@ -189,7 +189,7 @@ void BlenderSync::sync_integrator()
|
||||
}
|
||||
#endif
|
||||
|
||||
integrator->method = (Integrator::Method)get_int(cscene, "progressive");
|
||||
integrator->method = (Integrator::Method)get_enum(cscene, "progressive");
|
||||
|
||||
int diffuse_samples = get_int(cscene, "diffuse_samples");
|
||||
int glossy_samples = get_int(cscene, "glossy_samples");
|
||||
|
@ -231,6 +231,341 @@ __device_inline bool shadow_blocked(KernelGlobals *kg, PathState *state, Ray *ra
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
#if defined(__BRANCHED_PATH__) || defined(__BSSRDF__)
|
||||
|
||||
__device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ray ray, __global float *buffer,
|
||||
float3 throughput, int num_samples, int num_total_samples,
|
||||
float min_ray_pdf, float ray_pdf, PathState state, int rng_offset, PathRadiance *L)
|
||||
{
|
||||
#ifdef __LAMP_MIS__
|
||||
float ray_t = 0.0f;
|
||||
#endif
|
||||
|
||||
/* path iteration */
|
||||
for(;; rng_offset += PRNG_BOUNCE_NUM) {
|
||||
/* intersect scene */
|
||||
Intersection isect;
|
||||
uint visibility = path_state_ray_visibility(kg, &state);
|
||||
#ifdef __HAIR__
|
||||
bool hit = scene_intersect(kg, &ray, visibility, &isect, NULL, 0.0f, 0.0f);
|
||||
#else
|
||||
bool hit = scene_intersect(kg, &ray, visibility, &isect);
|
||||
#endif
|
||||
|
||||
#ifdef __LAMP_MIS__
|
||||
if(kernel_data.integrator.use_lamp_mis && !(state.flag & PATH_RAY_CAMERA)) {
|
||||
/* ray starting from previous non-transparent bounce */
|
||||
Ray light_ray;
|
||||
|
||||
light_ray.P = ray.P - ray_t*ray.D;
|
||||
ray_t += isect.t;
|
||||
light_ray.D = ray.D;
|
||||
light_ray.t = ray_t;
|
||||
light_ray.time = ray.time;
|
||||
light_ray.dD = ray.dD;
|
||||
light_ray.dP = ray.dP;
|
||||
|
||||
/* intersect with lamp */
|
||||
float light_t = path_rng_1D(kg, rng, sample, num_total_samples, rng_offset + PRNG_LIGHT);
|
||||
float3 emission;
|
||||
|
||||
if(indirect_lamp_emission(kg, &light_ray, state.flag, ray_pdf, light_t, &emission, state.bounce))
|
||||
path_radiance_accum_emission(L, throughput, emission, state.bounce);
|
||||
}
|
||||
#endif
|
||||
|
||||
if(!hit) {
|
||||
#ifdef __BACKGROUND__
|
||||
/* sample background shader */
|
||||
float3 L_background = indirect_background(kg, &ray, state.flag, ray_pdf, state.bounce);
|
||||
path_radiance_accum_background(L, throughput, L_background, state.bounce);
|
||||
#endif
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* setup shading */
|
||||
ShaderData sd;
|
||||
shader_setup_from_ray(kg, &sd, &isect, &ray, state.bounce);
|
||||
float rbsdf = path_rng_1D(kg, rng, sample, num_total_samples, rng_offset + PRNG_BSDF);
|
||||
shader_eval_surface(kg, &sd, rbsdf, state.flag, SHADER_CONTEXT_INDIRECT);
|
||||
shader_merge_closures(kg, &sd);
|
||||
|
||||
/* blurring of bsdf after bounces, for rays that have a small likelihood
|
||||
* of following this particular path (diffuse, rough glossy) */
|
||||
if(kernel_data.integrator.filter_glossy != FLT_MAX) {
|
||||
float blur_pdf = kernel_data.integrator.filter_glossy*min_ray_pdf;
|
||||
|
||||
if(blur_pdf < 1.0f) {
|
||||
float blur_roughness = sqrtf(1.0f - blur_pdf)*0.5f;
|
||||
shader_bsdf_blur(kg, &sd, blur_roughness);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __EMISSION__
|
||||
/* emission */
|
||||
if(sd.flag & SD_EMISSION) {
|
||||
float3 emission = indirect_primitive_emission(kg, &sd, isect.t, state.flag, ray_pdf);
|
||||
path_radiance_accum_emission(L, throughput, emission, state.bounce);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* path termination. this is a strange place to put the termination, it's
|
||||
* mainly due to the mixed in MIS that we use. gives too many unneeded
|
||||
* shader evaluations, only need emission if we are going to terminate */
|
||||
float probability = path_state_terminate_probability(kg, &state, throughput*num_samples);
|
||||
|
||||
if(probability == 0.0f) {
|
||||
break;
|
||||
}
|
||||
else if(probability != 1.0f) {
|
||||
float terminate = path_rng_1D(kg, rng, sample, num_total_samples, rng_offset + PRNG_TERMINATE);
|
||||
|
||||
if(terminate >= probability)
|
||||
break;
|
||||
|
||||
throughput /= probability;
|
||||
}
|
||||
|
||||
#ifdef __AO__
|
||||
/* ambient occlusion */
|
||||
if(kernel_data.integrator.use_ambient_occlusion || (sd.flag & SD_AO)) {
|
||||
float bsdf_u, bsdf_v;
|
||||
path_rng_2D(kg, rng, sample, num_total_samples, rng_offset + PRNG_BSDF_U, &bsdf_u, &bsdf_v);
|
||||
|
||||
float ao_factor = kernel_data.background.ao_factor;
|
||||
float3 ao_N;
|
||||
float3 ao_bsdf = shader_bsdf_ao(kg, &sd, ao_factor, &ao_N);
|
||||
float3 ao_D;
|
||||
float ao_pdf;
|
||||
|
||||
sample_cos_hemisphere(ao_N, bsdf_u, bsdf_v, &ao_D, &ao_pdf);
|
||||
|
||||
if(dot(sd.Ng, ao_D) > 0.0f && ao_pdf != 0.0f) {
|
||||
Ray light_ray;
|
||||
float3 ao_shadow;
|
||||
|
||||
light_ray.P = ray_offset(sd.P, sd.Ng);
|
||||
light_ray.D = ao_D;
|
||||
light_ray.t = kernel_data.background.ao_distance;
|
||||
#ifdef __OBJECT_MOTION__
|
||||
light_ray.time = sd.time;
|
||||
#endif
|
||||
light_ray.dP = sd.dP;
|
||||
light_ray.dD = differential3_zero();
|
||||
|
||||
if(!shadow_blocked(kg, &state, &light_ray, &ao_shadow))
|
||||
path_radiance_accum_ao(L, throughput, ao_bsdf, ao_shadow, state.bounce);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __SUBSURFACE__
|
||||
/* bssrdf scatter to a different location on the same object, replacing
|
||||
* the closures with a diffuse BSDF */
|
||||
if(sd.flag & SD_BSSRDF) {
|
||||
float bssrdf_probability;
|
||||
ShaderClosure *sc = subsurface_scatter_pick_closure(kg, &sd, &bssrdf_probability);
|
||||
|
||||
/* modify throughput for picking bssrdf or bsdf */
|
||||
throughput *= bssrdf_probability;
|
||||
|
||||
/* do bssrdf scatter step if we picked a bssrdf closure */
|
||||
if(sc) {
|
||||
uint lcg_state = lcg_init(*rng + rng_offset + sample*0x68bc21eb);
|
||||
|
||||
if(old_subsurface_scatter_use(&sd)) {
|
||||
old_subsurface_scatter_step(kg, &sd, state.flag, sc, &lcg_state, false);
|
||||
}
|
||||
else {
|
||||
float bssrdf_u, bssrdf_v;
|
||||
path_rng_2D(kg, rng, sample, num_total_samples, rng_offset + PRNG_BSDF_U, &bssrdf_u, &bssrdf_v);
|
||||
subsurface_scatter_step(kg, &sd, state.flag, sc, &lcg_state, bssrdf_u, bssrdf_v, false);
|
||||
}
|
||||
|
||||
state.flag |= PATH_RAY_BSSRDF_ANCESTOR;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __EMISSION__
|
||||
if(kernel_data.integrator.use_direct_light) {
|
||||
/* sample illumination from lights to find path contribution */
|
||||
if(sd.flag & SD_BSDF_HAS_EVAL) {
|
||||
float light_t = path_rng_1D(kg, rng, sample, num_total_samples, rng_offset + PRNG_LIGHT);
|
||||
#ifdef __MULTI_CLOSURE__
|
||||
float light_o = 0.0f;
|
||||
#else
|
||||
float light_o = path_rng_1D(kg, rng, sample, num_total_samples, rng_offset + PRNG_LIGHT_F);
|
||||
#endif
|
||||
float light_u, light_v;
|
||||
path_rng_2D(kg, rng, sample, num_total_samples, rng_offset + PRNG_LIGHT_U, &light_u, &light_v);
|
||||
|
||||
Ray light_ray;
|
||||
BsdfEval L_light;
|
||||
bool is_lamp;
|
||||
|
||||
#ifdef __OBJECT_MOTION__
|
||||
light_ray.time = sd.time;
|
||||
#endif
|
||||
|
||||
/* sample random light */
|
||||
if(direct_emission(kg, &sd, -1, light_t, light_o, light_u, light_v, &light_ray, &L_light, &is_lamp, state.bounce)) {
|
||||
/* trace shadow ray */
|
||||
float3 shadow;
|
||||
|
||||
if(!shadow_blocked(kg, &state, &light_ray, &shadow)) {
|
||||
/* accumulate */
|
||||
path_radiance_accum_light(L, throughput, &L_light, shadow, 1.0f, state.bounce, is_lamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* no BSDF? we can stop here */
|
||||
if(!(sd.flag & SD_BSDF))
|
||||
break;
|
||||
|
||||
/* sample BSDF */
|
||||
float bsdf_pdf;
|
||||
BsdfEval bsdf_eval;
|
||||
float3 bsdf_omega_in;
|
||||
differential3 bsdf_domega_in;
|
||||
float bsdf_u, bsdf_v;
|
||||
path_rng_2D(kg, rng, sample, num_total_samples, rng_offset + PRNG_BSDF_U, &bsdf_u, &bsdf_v);
|
||||
int label;
|
||||
|
||||
label = shader_bsdf_sample(kg, &sd, bsdf_u, bsdf_v, &bsdf_eval,
|
||||
&bsdf_omega_in, &bsdf_domega_in, &bsdf_pdf);
|
||||
|
||||
if(bsdf_pdf == 0.0f || bsdf_eval_is_zero(&bsdf_eval))
|
||||
break;
|
||||
|
||||
/* modify throughput */
|
||||
path_radiance_bsdf_bounce(L, &throughput, &bsdf_eval, bsdf_pdf, state.bounce, label);
|
||||
|
||||
/* set labels */
|
||||
if(!(label & LABEL_TRANSPARENT)) {
|
||||
ray_pdf = bsdf_pdf;
|
||||
#ifdef __LAMP_MIS__
|
||||
ray_t = 0.0f;
|
||||
#endif
|
||||
min_ray_pdf = fminf(bsdf_pdf, min_ray_pdf);
|
||||
}
|
||||
|
||||
/* update path state */
|
||||
path_state_next(kg, &state, label);
|
||||
|
||||
/* setup ray */
|
||||
ray.P = ray_offset(sd.P, (label & LABEL_TRANSMIT)? -sd.Ng: sd.Ng);
|
||||
ray.D = bsdf_omega_in;
|
||||
ray.t = FLT_MAX;
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
ray.dP = sd.dP;
|
||||
ray.dD = bsdf_domega_in;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __SUBSURFACE__
|
||||
|
||||
__device_inline bool kernel_path_integrate_lighting(KernelGlobals *kg, RNG *rng,
|
||||
int sample, int num_samples,
|
||||
ShaderData *sd, float3 *throughput,
|
||||
float *min_ray_pdf, float *ray_pdf, PathState *state,
|
||||
int rng_offset, PathRadiance *L, Ray *ray, float *ray_t)
|
||||
{
|
||||
#ifdef __EMISSION__
|
||||
if(kernel_data.integrator.use_direct_light) {
|
||||
/* sample illumination from lights to find path contribution */
|
||||
if(sd->flag & SD_BSDF_HAS_EVAL) {
|
||||
float light_t = path_rng_1D(kg, rng, sample, num_samples, rng_offset + PRNG_LIGHT);
|
||||
#ifdef __MULTI_CLOSURE__
|
||||
float light_o = 0.0f;
|
||||
#else
|
||||
float light_o = path_rng_1D(kg, rng, sample, num_samples, rng_offset + PRNG_LIGHT_F);
|
||||
#endif
|
||||
float light_u, light_v;
|
||||
path_rng_2D(kg, rng, sample, num_samples, rng_offset + PRNG_LIGHT_U, &light_u, &light_v);
|
||||
|
||||
Ray light_ray;
|
||||
BsdfEval L_light;
|
||||
bool is_lamp;
|
||||
|
||||
#ifdef __OBJECT_MOTION__
|
||||
light_ray.time = sd->time;
|
||||
#endif
|
||||
|
||||
if(direct_emission(kg, sd, -1, light_t, light_o, light_u, light_v, &light_ray, &L_light, &is_lamp, state->bounce)) {
|
||||
/* trace shadow ray */
|
||||
float3 shadow;
|
||||
|
||||
if(!shadow_blocked(kg, state, &light_ray, &shadow)) {
|
||||
/* accumulate */
|
||||
path_radiance_accum_light(L, *throughput, &L_light, shadow, 1.0f, state->bounce, is_lamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* no BSDF? we can stop here */
|
||||
if(!(sd->flag & SD_BSDF))
|
||||
return false;
|
||||
|
||||
/* sample BSDF */
|
||||
float bsdf_pdf;
|
||||
BsdfEval bsdf_eval;
|
||||
float3 bsdf_omega_in;
|
||||
differential3 bsdf_domega_in;
|
||||
float bsdf_u, bsdf_v;
|
||||
path_rng_2D(kg, rng, sample, num_samples, rng_offset + PRNG_BSDF_U, &bsdf_u, &bsdf_v);
|
||||
int label;
|
||||
|
||||
label = shader_bsdf_sample(kg, sd, bsdf_u, bsdf_v, &bsdf_eval,
|
||||
&bsdf_omega_in, &bsdf_domega_in, &bsdf_pdf);
|
||||
|
||||
if(bsdf_pdf == 0.0f || bsdf_eval_is_zero(&bsdf_eval))
|
||||
return false;
|
||||
|
||||
/* modify throughput */
|
||||
path_radiance_bsdf_bounce(L, throughput, &bsdf_eval, bsdf_pdf, state->bounce, label);
|
||||
|
||||
/* set labels */
|
||||
if(!(label & LABEL_TRANSPARENT)) {
|
||||
*ray_pdf = bsdf_pdf;
|
||||
#ifdef __LAMP_MIS__
|
||||
*ray_t = 0.0f;
|
||||
#endif
|
||||
*min_ray_pdf = fminf(bsdf_pdf, *min_ray_pdf);
|
||||
}
|
||||
|
||||
/* update path state */
|
||||
path_state_next(kg, state, label);
|
||||
|
||||
/* setup ray */
|
||||
ray->P = ray_offset(sd->P, (label & LABEL_TRANSMIT)? -sd->Ng: sd->Ng);
|
||||
ray->D = bsdf_omega_in;
|
||||
|
||||
if(state->bounce == 0)
|
||||
ray->t -= sd->ray_length; /* clipping works through transparent */
|
||||
else
|
||||
ray->t = FLT_MAX;
|
||||
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
ray->dP = sd->dP;
|
||||
ray->dD = bsdf_domega_in;
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
__device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, Ray ray, __global float *buffer)
|
||||
{
|
||||
/* initialize */
|
||||
@ -242,9 +577,7 @@ __device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, R
|
||||
|
||||
float min_ray_pdf = FLT_MAX;
|
||||
float ray_pdf = 0.0f;
|
||||
#ifdef __LAMP_MIS__
|
||||
float ray_t = 0.0f;
|
||||
#endif
|
||||
PathState state;
|
||||
int rng_offset = PRNG_BASE_NUM;
|
||||
#ifdef __CMJ__
|
||||
@ -389,32 +722,6 @@ __device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, R
|
||||
throughput /= probability;
|
||||
}
|
||||
|
||||
#ifdef __SUBSURFACE__
|
||||
/* bssrdf scatter to a different location on the same object, replacing
|
||||
* the closures with a diffuse BSDF */
|
||||
if(sd.flag & SD_BSSRDF) {
|
||||
float bssrdf_probability;
|
||||
ShaderClosure *sc = subsurface_scatter_pick_closure(kg, &sd, &bssrdf_probability);
|
||||
|
||||
/* modify throughput for picking bssrdf or bsdf */
|
||||
throughput *= bssrdf_probability;
|
||||
|
||||
/* do bssrdf scatter step if we picked a bssrdf closure */
|
||||
if(sc) {
|
||||
uint lcg_state = lcg_init(*rng + rng_offset + sample*0x68bc21eb);
|
||||
|
||||
if(old_subsurface_scatter_use(&sd)) {
|
||||
old_subsurface_scatter_step(kg, &sd, state.flag, sc, &lcg_state, false);
|
||||
}
|
||||
else {
|
||||
float bssrdf_u, bssrdf_v;
|
||||
path_rng_2D(kg, rng, sample, num_samples, rng_offset + PRNG_BSDF_U, &bssrdf_u, &bssrdf_v);
|
||||
subsurface_scatter_step(kg, &sd, state.flag, sc, &lcg_state, bssrdf_u, bssrdf_v, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __AO__
|
||||
/* ambient occlusion */
|
||||
if(kernel_data.integrator.use_ambient_occlusion || (sd.flag & SD_AO)) {
|
||||
@ -449,6 +756,67 @@ __device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, R
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __SUBSURFACE__
|
||||
/* bssrdf scatter to a different location on the same object, replacing
|
||||
* the closures with a diffuse BSDF */
|
||||
if(sd.flag & SD_BSSRDF) {
|
||||
float bssrdf_probability;
|
||||
ShaderClosure *sc = subsurface_scatter_pick_closure(kg, &sd, &bssrdf_probability);
|
||||
|
||||
/* modify throughput for picking bssrdf or bsdf */
|
||||
throughput *= bssrdf_probability;
|
||||
|
||||
/* do bssrdf scatter step if we picked a bssrdf closure */
|
||||
if(sc) {
|
||||
uint lcg_state = lcg_init(*rng + rng_offset + sample*0x68bc21eb);
|
||||
|
||||
if(old_subsurface_scatter_use(&sd)) {
|
||||
old_subsurface_scatter_step(kg, &sd, state.flag, sc, &lcg_state, false);
|
||||
}
|
||||
else {
|
||||
ShaderData bssrdf_sd[BSSRDF_MAX_HITS];
|
||||
float bssrdf_u, bssrdf_v;
|
||||
path_rng_2D(kg, rng, sample, num_samples, rng_offset + PRNG_BSDF_U, &bssrdf_u, &bssrdf_v);
|
||||
int num_hits = subsurface_scatter_multi_step(kg, &sd, bssrdf_sd, state.flag, sc, &lcg_state, bssrdf_u, bssrdf_v, false);
|
||||
|
||||
/* compute lighting with the BSDF closure */
|
||||
for(int hit = 0; hit < num_hits; hit++) {
|
||||
float3 tp = throughput;
|
||||
PathState hit_state = state;
|
||||
Ray hit_ray = ray;
|
||||
float hit_ray_t = ray_t;
|
||||
float hit_ray_pdf = ray_pdf;
|
||||
float hit_min_ray_pdf = min_ray_pdf;
|
||||
|
||||
hit_state.flag |= PATH_RAY_BSSRDF_ANCESTOR;
|
||||
|
||||
if(kernel_path_integrate_lighting(kg, rng, sample, num_samples, &bssrdf_sd[hit],
|
||||
&tp, &hit_min_ray_pdf, &hit_ray_pdf, &hit_state, rng_offset, &L, &hit_ray, &hit_ray_t)) {
|
||||
kernel_path_indirect(kg, rng, sample, hit_ray, buffer,
|
||||
tp, num_samples, num_samples,
|
||||
hit_min_ray_pdf, hit_ray_pdf, hit_state, rng_offset+PRNG_BOUNCE_NUM, &L);
|
||||
|
||||
/* for render passes, sum and reset indirect light pass variables
|
||||
* for the next samples */
|
||||
path_radiance_sum_indirect(&L);
|
||||
path_radiance_reset_indirect(&L);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __SUBSURFACE__
|
||||
|
||||
if(!kernel_path_integrate_lighting(kg, rng, sample, num_samples, &sd,
|
||||
&throughput, &min_ray_pdf, &ray_pdf, &state, rng_offset, &L, &ray, &ray_t))
|
||||
break;
|
||||
|
||||
#else
|
||||
|
||||
#ifdef __EMISSION__
|
||||
if(kernel_data.integrator.use_direct_light) {
|
||||
/* sample illumination from lights to find path contribution */
|
||||
@ -529,6 +897,8 @@ __device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, R
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
ray.dP = sd.dP;
|
||||
ray.dD = bsdf_domega_in;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -545,284 +915,12 @@ __device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, R
|
||||
|
||||
#ifdef __BRANCHED_PATH__
|
||||
|
||||
__device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ray ray, __global float *buffer,
|
||||
float3 throughput, int num_samples, int num_total_samples,
|
||||
float min_ray_pdf, float ray_pdf, PathState state, int rng_offset, PathRadiance *L)
|
||||
{
|
||||
#ifdef __LAMP_MIS__
|
||||
float ray_t = 0.0f;
|
||||
#endif
|
||||
|
||||
/* path iteration */
|
||||
for(;; rng_offset += PRNG_BOUNCE_NUM) {
|
||||
/* intersect scene */
|
||||
Intersection isect;
|
||||
uint visibility = path_state_ray_visibility(kg, &state);
|
||||
#ifdef __HAIR__
|
||||
bool hit = scene_intersect(kg, &ray, visibility, &isect, NULL, 0.0f, 0.0f);
|
||||
#else
|
||||
bool hit = scene_intersect(kg, &ray, visibility, &isect);
|
||||
#endif
|
||||
|
||||
#ifdef __LAMP_MIS__
|
||||
if(kernel_data.integrator.use_lamp_mis && !(state.flag & PATH_RAY_CAMERA)) {
|
||||
/* ray starting from previous non-transparent bounce */
|
||||
Ray light_ray;
|
||||
|
||||
light_ray.P = ray.P - ray_t*ray.D;
|
||||
ray_t += isect.t;
|
||||
light_ray.D = ray.D;
|
||||
light_ray.t = ray_t;
|
||||
light_ray.time = ray.time;
|
||||
light_ray.dD = ray.dD;
|
||||
light_ray.dP = ray.dP;
|
||||
|
||||
/* intersect with lamp */
|
||||
float light_t = path_rng_1D(kg, rng, sample, num_total_samples, rng_offset + PRNG_LIGHT);
|
||||
float3 emission;
|
||||
|
||||
if(indirect_lamp_emission(kg, &light_ray, state.flag, ray_pdf, light_t, &emission, state.bounce))
|
||||
path_radiance_accum_emission(L, throughput, emission, state.bounce);
|
||||
}
|
||||
#endif
|
||||
|
||||
if(!hit) {
|
||||
#ifdef __BACKGROUND__
|
||||
/* sample background shader */
|
||||
float3 L_background = indirect_background(kg, &ray, state.flag, ray_pdf, state.bounce);
|
||||
path_radiance_accum_background(L, throughput, L_background, state.bounce);
|
||||
#endif
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* setup shading */
|
||||
ShaderData sd;
|
||||
shader_setup_from_ray(kg, &sd, &isect, &ray, state.bounce);
|
||||
float rbsdf = path_rng_1D(kg, rng, sample, num_total_samples, rng_offset + PRNG_BSDF);
|
||||
shader_eval_surface(kg, &sd, rbsdf, state.flag, SHADER_CONTEXT_INDIRECT);
|
||||
shader_merge_closures(kg, &sd);
|
||||
|
||||
/* blurring of bsdf after bounces, for rays that have a small likelihood
|
||||
* of following this particular path (diffuse, rough glossy) */
|
||||
if(kernel_data.integrator.filter_glossy != FLT_MAX) {
|
||||
float blur_pdf = kernel_data.integrator.filter_glossy*min_ray_pdf;
|
||||
|
||||
if(blur_pdf < 1.0f) {
|
||||
float blur_roughness = sqrtf(1.0f - blur_pdf)*0.5f;
|
||||
shader_bsdf_blur(kg, &sd, blur_roughness);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __EMISSION__
|
||||
/* emission */
|
||||
if(sd.flag & SD_EMISSION) {
|
||||
float3 emission = indirect_primitive_emission(kg, &sd, isect.t, state.flag, ray_pdf);
|
||||
path_radiance_accum_emission(L, throughput, emission, state.bounce);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* path termination. this is a strange place to put the termination, it's
|
||||
* mainly due to the mixed in MIS that we use. gives too many unneeded
|
||||
* shader evaluations, only need emission if we are going to terminate */
|
||||
float probability = path_state_terminate_probability(kg, &state, throughput*num_samples);
|
||||
|
||||
if(probability == 0.0f) {
|
||||
break;
|
||||
}
|
||||
else if(probability != 1.0f) {
|
||||
float terminate = path_rng_1D(kg, rng, sample, num_total_samples, rng_offset + PRNG_TERMINATE);
|
||||
|
||||
if(terminate >= probability)
|
||||
break;
|
||||
|
||||
throughput /= probability;
|
||||
}
|
||||
|
||||
#ifdef __SUBSURFACE__
|
||||
/* bssrdf scatter to a different location on the same object, replacing
|
||||
* the closures with a diffuse BSDF */
|
||||
if(sd.flag & SD_BSSRDF) {
|
||||
float bssrdf_probability;
|
||||
ShaderClosure *sc = subsurface_scatter_pick_closure(kg, &sd, &bssrdf_probability);
|
||||
|
||||
/* modify throughput for picking bssrdf or bsdf */
|
||||
throughput *= bssrdf_probability;
|
||||
|
||||
/* do bssrdf scatter step if we picked a bssrdf closure */
|
||||
if(sc) {
|
||||
uint lcg_state = lcg_init(*rng + rng_offset + sample*0x68bc21eb);
|
||||
|
||||
if(old_subsurface_scatter_use(&sd)) {
|
||||
old_subsurface_scatter_step(kg, &sd, state.flag, sc, &lcg_state, false);
|
||||
}
|
||||
else {
|
||||
float bssrdf_u, bssrdf_v;
|
||||
path_rng_2D(kg, rng, sample, num_total_samples, rng_offset + PRNG_BSDF_U, &bssrdf_u, &bssrdf_v);
|
||||
subsurface_scatter_step(kg, &sd, state.flag, sc, &lcg_state, bssrdf_u, bssrdf_v, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __AO__
|
||||
/* ambient occlusion */
|
||||
if(kernel_data.integrator.use_ambient_occlusion || (sd.flag & SD_AO)) {
|
||||
float bsdf_u, bsdf_v;
|
||||
path_rng_2D(kg, rng, sample, num_total_samples, rng_offset + PRNG_BSDF_U, &bsdf_u, &bsdf_v);
|
||||
|
||||
float ao_factor = kernel_data.background.ao_factor;
|
||||
float3 ao_N;
|
||||
float3 ao_bsdf = shader_bsdf_ao(kg, &sd, ao_factor, &ao_N);
|
||||
float3 ao_D;
|
||||
float ao_pdf;
|
||||
|
||||
sample_cos_hemisphere(ao_N, bsdf_u, bsdf_v, &ao_D, &ao_pdf);
|
||||
|
||||
if(dot(sd.Ng, ao_D) > 0.0f && ao_pdf != 0.0f) {
|
||||
Ray light_ray;
|
||||
float3 ao_shadow;
|
||||
|
||||
light_ray.P = ray_offset(sd.P, sd.Ng);
|
||||
light_ray.D = ao_D;
|
||||
light_ray.t = kernel_data.background.ao_distance;
|
||||
#ifdef __OBJECT_MOTION__
|
||||
light_ray.time = sd.time;
|
||||
#endif
|
||||
light_ray.dP = sd.dP;
|
||||
light_ray.dD = differential3_zero();
|
||||
|
||||
if(!shadow_blocked(kg, &state, &light_ray, &ao_shadow))
|
||||
path_radiance_accum_ao(L, throughput, ao_bsdf, ao_shadow, state.bounce);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __EMISSION__
|
||||
if(kernel_data.integrator.use_direct_light) {
|
||||
/* sample illumination from lights to find path contribution */
|
||||
if(sd.flag & SD_BSDF_HAS_EVAL) {
|
||||
float light_t = path_rng_1D(kg, rng, sample, num_total_samples, rng_offset + PRNG_LIGHT);
|
||||
#ifdef __MULTI_CLOSURE__
|
||||
float light_o = 0.0f;
|
||||
#else
|
||||
float light_o = path_rng_1D(kg, rng, sample, num_total_samples, rng_offset + PRNG_LIGHT_F);
|
||||
#endif
|
||||
float light_u, light_v;
|
||||
path_rng_2D(kg, rng, sample, num_total_samples, rng_offset + PRNG_LIGHT_U, &light_u, &light_v);
|
||||
|
||||
Ray light_ray;
|
||||
BsdfEval L_light;
|
||||
bool is_lamp;
|
||||
|
||||
#ifdef __OBJECT_MOTION__
|
||||
light_ray.time = sd.time;
|
||||
#endif
|
||||
|
||||
/* sample random light */
|
||||
if(direct_emission(kg, &sd, -1, light_t, light_o, light_u, light_v, &light_ray, &L_light, &is_lamp, state.bounce)) {
|
||||
/* trace shadow ray */
|
||||
float3 shadow;
|
||||
|
||||
if(!shadow_blocked(kg, &state, &light_ray, &shadow)) {
|
||||
/* accumulate */
|
||||
path_radiance_accum_light(L, throughput, &L_light, shadow, 1.0f, state.bounce, is_lamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* no BSDF? we can stop here */
|
||||
if(!(sd.flag & SD_BSDF))
|
||||
break;
|
||||
|
||||
/* sample BSDF */
|
||||
float bsdf_pdf;
|
||||
BsdfEval bsdf_eval;
|
||||
float3 bsdf_omega_in;
|
||||
differential3 bsdf_domega_in;
|
||||
float bsdf_u, bsdf_v;
|
||||
path_rng_2D(kg, rng, sample, num_total_samples, rng_offset + PRNG_BSDF_U, &bsdf_u, &bsdf_v);
|
||||
int label;
|
||||
|
||||
label = shader_bsdf_sample(kg, &sd, bsdf_u, bsdf_v, &bsdf_eval,
|
||||
&bsdf_omega_in, &bsdf_domega_in, &bsdf_pdf);
|
||||
|
||||
if(bsdf_pdf == 0.0f || bsdf_eval_is_zero(&bsdf_eval))
|
||||
break;
|
||||
|
||||
/* modify throughput */
|
||||
path_radiance_bsdf_bounce(L, &throughput, &bsdf_eval, bsdf_pdf, state.bounce, label);
|
||||
|
||||
/* set labels */
|
||||
if(!(label & LABEL_TRANSPARENT)) {
|
||||
ray_pdf = bsdf_pdf;
|
||||
#ifdef __LAMP_MIS__
|
||||
ray_t = 0.0f;
|
||||
#endif
|
||||
min_ray_pdf = fminf(bsdf_pdf, min_ray_pdf);
|
||||
}
|
||||
|
||||
/* update path state */
|
||||
path_state_next(kg, &state, label);
|
||||
|
||||
/* setup ray */
|
||||
ray.P = ray_offset(sd.P, (label & LABEL_TRANSMIT)? -sd.Ng: sd.Ng);
|
||||
ray.D = bsdf_omega_in;
|
||||
ray.t = FLT_MAX;
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
ray.dP = sd.dP;
|
||||
ray.dD = bsdf_domega_in;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
__device_noinline void kernel_branched_path_integrate_lighting(KernelGlobals *kg, RNG *rng,
|
||||
int sample, int aa_samples,
|
||||
ShaderData *sd, float3 throughput, float num_samples_adjust,
|
||||
float min_ray_pdf, float ray_pdf, PathState state,
|
||||
int rng_offset, PathRadiance *L, __global float *buffer)
|
||||
{
|
||||
#ifdef __AO__
|
||||
/* ambient occlusion */
|
||||
if(kernel_data.integrator.use_ambient_occlusion || (sd->flag & SD_AO)) {
|
||||
int num_samples = ceil_to_int(kernel_data.integrator.ao_samples*num_samples_adjust);
|
||||
float num_samples_inv = num_samples_adjust/num_samples;
|
||||
float ao_factor = kernel_data.background.ao_factor;
|
||||
float3 ao_N;
|
||||
float3 ao_bsdf = shader_bsdf_ao(kg, sd, ao_factor, &ao_N);
|
||||
|
||||
for(int j = 0; j < num_samples; j++) {
|
||||
float bsdf_u, bsdf_v;
|
||||
path_rng_2D(kg, rng, sample*num_samples + j, aa_samples*num_samples, rng_offset + PRNG_BSDF_U, &bsdf_u, &bsdf_v);
|
||||
|
||||
float3 ao_D;
|
||||
float ao_pdf;
|
||||
|
||||
sample_cos_hemisphere(ao_N, bsdf_u, bsdf_v, &ao_D, &ao_pdf);
|
||||
|
||||
if(dot(sd->Ng, ao_D) > 0.0f && ao_pdf != 0.0f) {
|
||||
Ray light_ray;
|
||||
float3 ao_shadow;
|
||||
|
||||
light_ray.P = ray_offset(sd->P, sd->Ng);
|
||||
light_ray.D = ao_D;
|
||||
light_ray.t = kernel_data.background.ao_distance;
|
||||
#ifdef __OBJECT_MOTION__
|
||||
light_ray.time = sd->time;
|
||||
#endif
|
||||
light_ray.dP = sd->dP;
|
||||
light_ray.dD = differential3_zero();
|
||||
|
||||
if(!shadow_blocked(kg, &state, &light_ray, &ao_shadow))
|
||||
path_radiance_accum_ao(L, throughput*num_samples_inv, ao_bsdf, ao_shadow, state.bounce);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __EMISSION__
|
||||
/* sample illumination from lights to find path contribution */
|
||||
if(sd->flag & SD_BSDF_HAS_EVAL) {
|
||||
@ -901,8 +999,10 @@ __device_noinline void kernel_branched_path_integrate_lighting(KernelGlobals *kg
|
||||
|
||||
int num_samples;
|
||||
|
||||
if(CLOSURE_IS_BSDF_DIFFUSE(sc->type) || CLOSURE_IS_BSDF_BSSRDF(sc->type))
|
||||
if(CLOSURE_IS_BSDF_DIFFUSE(sc->type))
|
||||
num_samples = kernel_data.integrator.diffuse_samples;
|
||||
else if(CLOSURE_IS_BSDF_BSSRDF(sc->type))
|
||||
num_samples = 1;
|
||||
else if(CLOSURE_IS_BSDF_GLOSSY(sc->type))
|
||||
num_samples = kernel_data.integrator.glossy_samples;
|
||||
else
|
||||
@ -1086,6 +1186,44 @@ __device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, int
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __AO__
|
||||
/* ambient occlusion */
|
||||
if(kernel_data.integrator.use_ambient_occlusion || (sd.flag & SD_AO)) {
|
||||
int num_samples = kernel_data.integrator.ao_samples;
|
||||
float num_samples_inv = 1.0f/num_samples;
|
||||
float ao_factor = kernel_data.background.ao_factor;
|
||||
float3 ao_N;
|
||||
float3 ao_bsdf = shader_bsdf_ao(kg, &sd, ao_factor, &ao_N);
|
||||
|
||||
for(int j = 0; j < num_samples; j++) {
|
||||
float bsdf_u, bsdf_v;
|
||||
path_rng_2D(kg, rng, sample*num_samples + j, aa_samples*num_samples, rng_offset + PRNG_BSDF_U, &bsdf_u, &bsdf_v);
|
||||
|
||||
float3 ao_D;
|
||||
float ao_pdf;
|
||||
|
||||
sample_cos_hemisphere(ao_N, bsdf_u, bsdf_v, &ao_D, &ao_pdf);
|
||||
|
||||
if(dot(sd.Ng, ao_D) > 0.0f && ao_pdf != 0.0f) {
|
||||
Ray light_ray;
|
||||
float3 ao_shadow;
|
||||
|
||||
light_ray.P = ray_offset(sd.P, sd.Ng);
|
||||
light_ray.D = ao_D;
|
||||
light_ray.t = kernel_data.background.ao_distance;
|
||||
#ifdef __OBJECT_MOTION__
|
||||
light_ray.time = sd.time;
|
||||
#endif
|
||||
light_ray.dP = sd.dP;
|
||||
light_ray.dD = differential3_zero();
|
||||
|
||||
if(!shadow_blocked(kg, &state, &light_ray, &ao_shadow))
|
||||
path_radiance_accum_ao(&L, throughput*num_samples_inv, ao_bsdf, ao_shadow, state.bounce);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __SUBSURFACE__
|
||||
/* bssrdf scatter to a different location on the same object */
|
||||
if(sd.flag & SD_BSSRDF) {
|
||||
@ -1101,6 +1239,8 @@ __device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, int
|
||||
float num_samples_inv = 1.0f/num_samples;
|
||||
RNG bssrdf_rng = cmj_hash(*rng, i);
|
||||
|
||||
state.flag |= PATH_RAY_BSSRDF_ANCESTOR;
|
||||
|
||||
/* do subsurface scatter step with copy of shader data, this will
|
||||
* replace the BSSRDF with a diffuse BSDF closure */
|
||||
for(int j = 0; j < num_samples; j++) {
|
||||
@ -1128,6 +1268,8 @@ __device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, int
|
||||
ray_pdf, ray_pdf, state, rng_offset, &L, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
state.flag &= ~PATH_RAY_BSSRDF_ANCESTOR;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -221,20 +221,18 @@ __device int subsurface_scatter_multi_step(KernelGlobals *kg, ShaderData *sd, Sh
|
||||
disk_N = sd->Ng;
|
||||
make_orthonormals(disk_N, &disk_T, &disk_B);
|
||||
|
||||
if(disk_u < 0.5f) {
|
||||
if(sd->randb_closure < 0.5f) {
|
||||
pick_pdf_N = 0.5f;
|
||||
pick_pdf_T = 0.25f;
|
||||
pick_pdf_B = 0.25f;
|
||||
disk_u *= 2.0f;
|
||||
}
|
||||
else if(disk_u < 0.75f) {
|
||||
else if(sd->randb_closure < 0.75f) {
|
||||
float3 tmp = disk_N;
|
||||
disk_N = disk_T;
|
||||
disk_T = tmp;
|
||||
pick_pdf_N = 0.25f;
|
||||
pick_pdf_T = 0.5f;
|
||||
pick_pdf_B = 0.25f;
|
||||
disk_u = (disk_u - 0.5f)*4.0f;
|
||||
}
|
||||
else {
|
||||
float3 tmp = disk_N;
|
||||
@ -243,7 +241,6 @@ __device int subsurface_scatter_multi_step(KernelGlobals *kg, ShaderData *sd, Sh
|
||||
pick_pdf_N = 0.25f;
|
||||
pick_pdf_T = 0.25f;
|
||||
pick_pdf_B = 0.5f;
|
||||
disk_u = (disk_u - 0.75f)*4.0f;
|
||||
}
|
||||
|
||||
/* sample point on disk */
|
||||
@ -323,20 +320,18 @@ __device void subsurface_scatter_step(KernelGlobals *kg, ShaderData *sd,
|
||||
disk_N = sd->Ng;
|
||||
make_orthonormals(disk_N, &disk_T, &disk_B);
|
||||
|
||||
if(disk_u < 0.5f) {
|
||||
if(sd->randb_closure < 0.5f) {
|
||||
pick_pdf_N = 0.5f;
|
||||
pick_pdf_T = 0.25f;
|
||||
pick_pdf_B = 0.25f;
|
||||
disk_u *= 2.0f;
|
||||
}
|
||||
else if(disk_u < 0.75f) {
|
||||
else if(sd->randb_closure < 0.75f) {
|
||||
float3 tmp = disk_N;
|
||||
disk_N = disk_T;
|
||||
disk_T = tmp;
|
||||
pick_pdf_N = 0.25f;
|
||||
pick_pdf_T = 0.5f;
|
||||
pick_pdf_B = 0.25f;
|
||||
disk_u = (disk_u - 0.5f)*4.0f;
|
||||
}
|
||||
else {
|
||||
float3 tmp = disk_N;
|
||||
@ -345,7 +340,6 @@ __device void subsurface_scatter_step(KernelGlobals *kg, ShaderData *sd,
|
||||
pick_pdf_N = 0.25f;
|
||||
pick_pdf_T = 0.25f;
|
||||
pick_pdf_B = 0.5f;
|
||||
disk_u = (disk_u - 0.75f)*4.0f;
|
||||
}
|
||||
|
||||
/* sample point on disk */
|
||||
|
@ -220,6 +220,7 @@ enum PathRayFlag {
|
||||
PATH_RAY_MIS_SKIP = 1024,
|
||||
PATH_RAY_DIFFUSE_ANCESTOR = 2048,
|
||||
PATH_RAY_GLOSSY_ANCESTOR = 4096,
|
||||
PATH_RAY_BSSRDF_ANCESTOR = 8192,
|
||||
|
||||
/* this gives collisions with localview bits
|
||||
* see: blender_util.h, grr - Campbell */
|
||||
|
@ -209,6 +209,7 @@ void OSLShaderManager::shading_system_init()
|
||||
"__unused__",
|
||||
"diffuse_ancestor", /* PATH_RAY_DIFFUSE_ANCESTOR */
|
||||
"glossy_ancestor", /* PATH_RAY_GLOSSY_ANCESTOR */
|
||||
"bssrdf_ancestor", /* PATH_RAY_BSSRDF_ANCESTOR */
|
||||
};
|
||||
|
||||
const int nraytypes = sizeof(raytypes)/sizeof(raytypes[0]);
|
||||
|
Loading…
Reference in New Issue
Block a user