diff options
Diffstat (limited to 'intern/cycles/kernel/kernel_path.h')
-rw-r--r-- | intern/cycles/kernel/kernel_path.h | 468 |
1 files changed, 353 insertions, 115 deletions
diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h index 9794ad1d180..c136c85df59 100644 --- a/intern/cycles/kernel/kernel_path.h +++ b/intern/cycles/kernel/kernel_path.h @@ -15,7 +15,7 @@ */ #ifdef __OSL__ -#include "osl_shader.h" +# include "osl_shader.h" #endif #include "kernel_random.h" @@ -32,11 +32,11 @@ #include "kernel_passes.h" #ifdef __SUBSURFACE__ -#include "kernel_subsurface.h" +# include "kernel_subsurface.h" #endif #ifdef __VOLUME__ -#include "kernel_volume.h" +# include "kernel_volume.h" #endif #include "kernel_path_state.h" @@ -47,52 +47,69 @@ #include "kernel_path_volume.h" #ifdef __KERNEL_DEBUG__ -#include "kernel_debug.h" +# include "kernel_debug.h" #endif CCL_NAMESPACE_BEGIN -ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, Ray ray, - float3 throughput, int num_samples, PathState state, PathRadiance *L) +ccl_device void kernel_path_indirect(KernelGlobals *kg, + RNG *rng, + Ray *ray, + float3 throughput, + int num_samples, + PathState *state, + PathRadiance *L) { /* path iteration */ for(;;) { /* intersect scene */ Intersection isect; - uint visibility = path_state_ray_visibility(kg, &state); - bool hit = scene_intersect(kg, &ray, visibility, &isect, NULL, 0.0f, 0.0f); + uint visibility = path_state_ray_visibility(kg, state); + bool hit = scene_intersect(kg, + ray, + visibility, + &isect, + NULL, + 0.0f, 0.0f); #ifdef __LAMP_MIS__ - if(kernel_data.integrator.use_lamp_mis && !(state.flag & PATH_RAY_CAMERA)) { + 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 - state.ray_t*ray.D; - state.ray_t += isect.t; - light_ray.D = ray.D; - light_ray.t = state.ray_t; - light_ray.time = ray.time; - light_ray.dD = ray.dD; - light_ray.dP = ray.dP; + light_ray.P = ray->P - state->ray_t*ray->D; + state->ray_t += isect.t; + light_ray.D = ray->D; + light_ray.t = state->ray_t; + light_ray.time = ray->time; + light_ray.dD = ray->dD; + light_ray.dP = ray->dP; /* intersect with lamp */ float3 emission; - - if(indirect_lamp_emission(kg, &state, &light_ray, &emission)) - path_radiance_accum_emission(L, throughput, emission, state.bounce); + if(indirect_lamp_emission(kg, state, &light_ray, &emission)) { + path_radiance_accum_emission(L, + throughput, + emission, + state->bounce); + } } #endif #ifdef __VOLUME__ /* volume attenuation, emission, scatter */ - if(state.volume_stack[0].shader != SHADER_NONE) { - Ray volume_ray = ray; + if(state->volume_stack[0].shader != SHADER_NONE) { + Ray volume_ray = *ray; volume_ray.t = (hit)? isect.t: FLT_MAX; - bool heterogeneous = volume_stack_is_heterogeneous(kg, state.volume_stack); + bool heterogeneous = + volume_stack_is_heterogeneous(kg, + state->volume_stack); -#ifdef __VOLUME_DECOUPLED__ - int sampling_method = volume_stack_sampling_method(kg, state.volume_stack); +# ifdef __VOLUME_DECOUPLED__ + int sampling_method = + volume_stack_sampling_method(kg, + state->volume_stack); bool decoupled = kernel_volume_use_decoupled(kg, heterogeneous, false, sampling_method); if(decoupled) { @@ -100,70 +117,117 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, Ray ray, VolumeSegment volume_segment; ShaderData volume_sd; - shader_setup_from_volume(kg, &volume_sd, &volume_ray, state.bounce, state.transparent_bounce); - kernel_volume_decoupled_record(kg, &state, - &volume_ray, &volume_sd, &volume_segment, heterogeneous); - + shader_setup_from_volume(kg, + &volume_sd, + &volume_ray); + kernel_volume_decoupled_record(kg, + state, + &volume_ray, + &volume_sd, + &volume_segment, + heterogeneous); + volume_segment.sampling_method = sampling_method; /* emission */ - if(volume_segment.closure_flag & SD_EMISSION) - path_radiance_accum_emission(L, throughput, volume_segment.accum_emission, state.bounce); + if(volume_segment.closure_flag & SD_EMISSION) { + path_radiance_accum_emission(L, + throughput, + volume_segment.accum_emission, + state->bounce); + } /* scattering */ VolumeIntegrateResult result = VOLUME_PATH_ATTENUATED; if(volume_segment.closure_flag & SD_SCATTER) { - bool all = kernel_data.integrator.sample_all_lights_indirect; + int all = kernel_data.integrator.sample_all_lights_indirect; /* direct light sampling */ - kernel_branched_path_volume_connect_light(kg, rng, &volume_sd, - throughput, &state, L, all, &volume_ray, &volume_segment); + kernel_branched_path_volume_connect_light(kg, + rng, + &volume_sd, + throughput, + state, + L, + all, + &volume_ray, + &volume_segment); /* indirect sample. if we use distance sampling and take just * one sample for direct and indirect light, we could share * this computation, but makes code a bit complex */ - float rphase = path_state_rng_1D_for_decision(kg, rng, &state, PRNG_PHASE); - float rscatter = path_state_rng_1D_for_decision(kg, rng, &state, PRNG_SCATTER_DISTANCE); + float rphase = path_state_rng_1D_for_decision(kg, rng, state, PRNG_PHASE); + float rscatter = path_state_rng_1D_for_decision(kg, rng, state, PRNG_SCATTER_DISTANCE); result = kernel_volume_decoupled_scatter(kg, - &state, &volume_ray, &volume_sd, &throughput, - rphase, rscatter, &volume_segment, NULL, true); + state, + &volume_ray, + &volume_sd, + &throughput, + rphase, + rscatter, + &volume_segment, + NULL, + true); } /* free cached steps */ kernel_volume_decoupled_free(kg, &volume_segment); if(result == VOLUME_PATH_SCATTERED) { - if(kernel_path_volume_bounce(kg, rng, &volume_sd, &throughput, &state, L, &ray)) + if(kernel_path_volume_bounce(kg, + rng, + &volume_sd, + &throughput, + state, + L, + ray)) + { continue; - else + } + else { break; + } } else { throughput *= volume_segment.accum_transmittance; } } else -#endif +# endif { /* integrate along volume segment with distance sampling */ ShaderData volume_sd; VolumeIntegrateResult result = kernel_volume_integrate( - kg, &state, &volume_sd, &volume_ray, L, &throughput, rng, heterogeneous); + kg, state, &volume_sd, &volume_ray, L, &throughput, rng, heterogeneous); -#ifdef __VOLUME_SCATTER__ +# ifdef __VOLUME_SCATTER__ if(result == VOLUME_PATH_SCATTERED) { /* direct lighting */ - kernel_path_volume_connect_light(kg, rng, &volume_sd, throughput, &state, L); + kernel_path_volume_connect_light(kg, + rng, + &volume_sd, + throughput, + state, + L); /* indirect light bounce */ - if(kernel_path_volume_bounce(kg, rng, &volume_sd, &throughput, &state, L, &ray)) + if(kernel_path_volume_bounce(kg, + rng, + &volume_sd, + &throughput, + state, + L, + ray)) + { continue; - else + } + else { break; + } } -#endif +# endif } } #endif @@ -171,8 +235,11 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, Ray ray, if(!hit) { #ifdef __BACKGROUND__ /* sample background shader */ - float3 L_background = indirect_background(kg, &state, &ray); - path_radiance_accum_background(L, throughput, L_background, state.bounce); + float3 L_background = indirect_background(kg, state, ray); + path_radiance_accum_background(L, + throughput, + L_background, + state->bounce); #endif break; @@ -180,9 +247,12 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, Ray ray, /* setup shading */ ShaderData sd; - shader_setup_from_ray(kg, &sd, &isect, &ray, state.bounce, state.transparent_bounce); - float rbsdf = path_state_rng_1D_for_decision(kg, rng, &state, PRNG_BSDF); - shader_eval_surface(kg, &sd, rbsdf, state.flag, SHADER_CONTEXT_INDIRECT); + shader_setup_from_ray(kg, + &sd, + &isect, + ray); + float rbsdf = path_state_rng_1D_for_decision(kg, rng, state, PRNG_BSDF); + shader_eval_surface(kg, &sd, state, rbsdf, state->flag, SHADER_CONTEXT_INDIRECT); #ifdef __BRANCHED_PATH__ shader_merge_closures(&sd); #endif @@ -190,7 +260,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, Ray ray, /* 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*state.min_ray_pdf; + float blur_pdf = kernel_data.integrator.filter_glossy*state->min_ray_pdf; if(blur_pdf < 1.0f) { float blur_roughness = sqrtf(1.0f - blur_pdf)*0.5f; @@ -201,21 +271,28 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, Ray ray, #ifdef __EMISSION__ /* emission */ if(sd.flag & SD_EMISSION) { - float3 emission = indirect_primitive_emission(kg, &sd, isect.t, state.flag, state.ray_pdf); - path_radiance_accum_emission(L, throughput, emission, state.bounce); + float3 emission = indirect_primitive_emission(kg, + &sd, + isect.t, + state->flag, + state->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); + float probability = + path_state_terminate_probability(kg, + state, + throughput*num_samples); if(probability == 0.0f) { break; } else if(probability != 1.0f) { - float terminate = path_state_rng_1D_for_decision(kg, rng, &state, PRNG_TERMINATE); + float terminate = path_state_rng_1D_for_decision(kg, rng, state, PRNG_TERMINATE); if(terminate >= probability) break; @@ -227,7 +304,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, Ray ray, /* ambient occlusion */ if(kernel_data.integrator.use_ambient_occlusion || (sd.flag & SD_AO)) { float bsdf_u, bsdf_v; - path_state_rng_2D(kg, rng, &state, PRNG_BSDF_U, &bsdf_u, &bsdf_v); + path_state_rng_2D(kg, rng, state, PRNG_BSDF_U, &bsdf_u, &bsdf_v); float ao_factor = kernel_data.background.ao_factor; float3 ao_N; @@ -245,14 +322,20 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, Ray ray, 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__ +# ifdef __OBJECT_MOTION__ light_ray.time = sd.time; -#endif +# 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_alpha, ao_bsdf, ao_shadow, state.bounce); + if(!shadow_blocked(kg, state, &light_ray, &ao_shadow)) { + path_radiance_accum_ao(L, + throughput, + ao_alpha, + ao_bsdf, + ao_shadow, + state->bounce); + } } } #endif @@ -269,28 +352,51 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, Ray ray, /* do bssrdf scatter step if we picked a bssrdf closure */ if(sc) { - uint lcg_state = lcg_state_init(rng, &state, 0x68bc21eb); + uint lcg_state = lcg_state_init(rng, state, 0x68bc21eb); float bssrdf_u, bssrdf_v; - path_state_rng_2D(kg, rng, &state, PRNG_BSDF_U, &bssrdf_u, &bssrdf_v); - subsurface_scatter_step(kg, &sd, state.flag, sc, &lcg_state, bssrdf_u, bssrdf_v, false); + path_state_rng_2D(kg, + rng, + state, + PRNG_BSDF_U, + &bssrdf_u, &bssrdf_v); + subsurface_scatter_step(kg, + &sd, + state, + state->flag, + sc, + &lcg_state, + bssrdf_u, bssrdf_v, + false); } } #endif #if defined(__EMISSION__) && defined(__BRANCHED_PATH__) if(kernel_data.integrator.use_direct_light) { - bool all = kernel_data.integrator.sample_all_lights_indirect; - kernel_branched_path_surface_connect_light(kg, rng, &sd, &state, throughput, 1.0f, L, all); + int all = kernel_data.integrator.sample_all_lights_indirect; + kernel_branched_path_surface_connect_light(kg, + rng, + &sd, + state, + throughput, + 1.0f, + L, + all); } #endif - if(!kernel_path_surface_bounce(kg, rng, &sd, &throughput, &state, L, &ray)) + if(!kernel_path_surface_bounce(kg, rng, &sd, &throughput, state, L, ray)) break; } } -ccl_device void kernel_path_ao(KernelGlobals *kg, ShaderData *sd, PathRadiance *L, PathState *state, RNG *rng, float3 throughput) +ccl_device_noinline void kernel_path_ao(KernelGlobals *kg, + ShaderData *sd, + PathRadiance *L, + PathState *state, + RNG *rng, + float3 throughput) { /* todo: solve correlation */ float bsdf_u, bsdf_v; @@ -326,7 +432,15 @@ ccl_device void kernel_path_ao(KernelGlobals *kg, ShaderData *sd, PathRadiance * #ifdef __SUBSURFACE__ -ccl_device bool kernel_path_subsurface_scatter(KernelGlobals *kg, ShaderData *sd, PathRadiance *L, PathState *state, RNG *rng, Ray *ray, float3 *throughput) +ccl_device bool kernel_path_subsurface_scatter( + KernelGlobals *kg, + ShaderData *sd, + PathRadiance *L, + PathState *state, + RNG *rng, + Ray *ray, + float3 *throughput, + SubsurfaceIndirectRays *ss_indirect) { float bssrdf_probability; ShaderClosure *sc = subsurface_scatter_pick_closure(kg, sd, &bssrdf_probability); @@ -336,64 +450,152 @@ ccl_device bool kernel_path_subsurface_scatter(KernelGlobals *kg, ShaderData *sd /* do bssrdf scatter step if we picked a bssrdf closure */ if(sc) { + /* We should never have two consecutive BSSRDF bounces, + * the second one should be converted to a diffuse BSDF to + * avoid this. + */ + kernel_assert(!ss_indirect->tracing); + uint lcg_state = lcg_state_init(rng, state, 0x68bc21eb); - ShaderData bssrdf_sd[BSSRDF_MAX_HITS]; + SubsurfaceIntersection ss_isect; float bssrdf_u, bssrdf_v; path_state_rng_2D(kg, rng, state, 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); -#ifdef __VOLUME__ - Ray volume_ray = *ray; - bool need_update_volume_stack = kernel_data.integrator.use_volumes && - ccl_fetch(sd, flag) & SD_OBJECT_INTERSECTS_VOLUME; -#endif + int num_hits = subsurface_scatter_multi_intersect(kg, + &ss_isect, + sd, + sc, + &lcg_state, + bssrdf_u, bssrdf_v, + false); +# ifdef __VOLUME__ + ss_indirect->need_update_volume_stack = + kernel_data.integrator.use_volumes && + ccl_fetch(sd, flag) & SD_OBJECT_INTERSECTS_VOLUME; +# endif /* 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; - - hit_state.rng_offset += PRNG_BOUNCE_NUM; - - kernel_path_surface_connect_light(kg, rng, &bssrdf_sd[hit], tp, state, L); - - if(kernel_path_surface_bounce(kg, rng, &bssrdf_sd[hit], &tp, &hit_state, L, &hit_ray)) { -#ifdef __LAMP_MIS__ - hit_state.ray_t = 0.0f; -#endif + /* NOTE: We reuse the existing ShaderData, we assume the path + * integration loop stops when this function returns true. + */ + subsurface_scatter_multi_setup(kg, + &ss_isect, + hit, + sd, + state, + state->flag, + sc, + false); + + PathState *hit_state = &ss_indirect->state[ss_indirect->num_rays]; + Ray *hit_ray = &ss_indirect->rays[ss_indirect->num_rays]; + float3 *hit_tp = &ss_indirect->throughputs[ss_indirect->num_rays]; + PathRadiance *hit_L = &ss_indirect->L[ss_indirect->num_rays]; + + *hit_state = *state; + *hit_ray = *ray; + *hit_tp = *throughput; + + hit_state->rng_offset += PRNG_BOUNCE_NUM; + + path_radiance_init(hit_L, kernel_data.film.use_light_pass); + hit_L->direct_throughput = L->direct_throughput; + path_radiance_copy_indirect(hit_L, L); + + kernel_path_surface_connect_light(kg, rng, sd, *hit_tp, state, hit_L); + + if(kernel_path_surface_bounce(kg, + rng, + sd, + hit_tp, + hit_state, + hit_L, + hit_ray)) + { +# ifdef __LAMP_MIS__ + hit_state->ray_t = 0.0f; +# endif -#ifdef __VOLUME__ - if(need_update_volume_stack) { +# ifdef __VOLUME__ + if(ss_indirect->need_update_volume_stack) { + Ray volume_ray = *ray; /* Setup ray from previous surface point to the new one. */ - volume_ray.D = normalize_len(hit_ray.P - volume_ray.P, + volume_ray.D = normalize_len(hit_ray->P - volume_ray.P, &volume_ray.t); kernel_volume_stack_update_for_subsurface( kg, &volume_ray, - hit_state.volume_stack); - - /* Move volume ray forward. */ - volume_ray.P = hit_ray.P; + hit_state->volume_stack); } -#endif - - kernel_path_indirect(kg, rng, hit_ray, tp, state->num_samples, hit_state, L); - - /* for render passes, sum and reset indirect light pass variables - * for the next samples */ - path_radiance_sum_indirect(L); +# endif path_radiance_reset_indirect(L); + ss_indirect->num_rays++; + } + else { + path_radiance_accum_sample(L, hit_L, 1); } } return true; } return false; } -#endif -ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, Ray ray, ccl_global float *buffer) +ccl_device_inline void kernel_path_subsurface_init_indirect( + SubsurfaceIndirectRays *ss_indirect) +{ + ss_indirect->tracing = false; + ss_indirect->num_rays = 0; +} + +ccl_device void kernel_path_subsurface_accum_indirect( + SubsurfaceIndirectRays *ss_indirect, + PathRadiance *L) +{ + if(ss_indirect->tracing) { + path_radiance_sum_indirect(L); + path_radiance_accum_sample(&ss_indirect->direct_L, L, 1); + if(ss_indirect->num_rays == 0) { + *L = ss_indirect->direct_L; + } + } +} + +ccl_device void kernel_path_subsurface_setup_indirect( + KernelGlobals *kg, + SubsurfaceIndirectRays *ss_indirect, + PathState *state, + Ray *ray, + PathRadiance *L, + float3 *throughput) +{ + if(!ss_indirect->tracing) { + ss_indirect->direct_L = *L; + } + ss_indirect->tracing = true; + + /* Setup state, ray and throughput for indirect SSS rays. */ + ss_indirect->num_rays--; + + Ray *indirect_ray = &ss_indirect->rays[ss_indirect->num_rays]; + PathRadiance *indirect_L = &ss_indirect->L[ss_indirect->num_rays]; + + *state = ss_indirect->state[ss_indirect->num_rays]; + *ray = *indirect_ray; + *L = *indirect_L; + *throughput = ss_indirect->throughputs[ss_indirect->num_rays]; + + state->rng_offset += ss_indirect->num_rays * PRNG_BOUNCE_NUM; +} + +#endif /* __SUBSURFACE__ */ + +ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg, + RNG *rng, + int sample, + Ray ray, + ccl_global float *buffer) { /* initialize */ PathRadiance L; @@ -410,6 +612,13 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, debug_data_init(&debug_data); #endif +#ifdef __SUBSURFACE__ + SubsurfaceIndirectRays ss_indirect; + kernel_path_subsurface_init_indirect(&ss_indirect); + + for(;;) { +#endif + /* path iteration */ for(;;) { /* intersect scene */ @@ -473,7 +682,7 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, bool heterogeneous = volume_stack_is_heterogeneous(kg, state.volume_stack); -#ifdef __VOLUME_DECOUPLED__ +# ifdef __VOLUME_DECOUPLED__ int sampling_method = volume_stack_sampling_method(kg, state.volume_stack); bool decoupled = kernel_volume_use_decoupled(kg, heterogeneous, true, sampling_method); @@ -482,7 +691,7 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, VolumeSegment volume_segment; ShaderData volume_sd; - shader_setup_from_volume(kg, &volume_sd, &volume_ray, state.bounce, state.transparent_bounce); + shader_setup_from_volume(kg, &volume_sd, &volume_ray); kernel_volume_decoupled_record(kg, &state, &volume_ray, &volume_sd, &volume_segment, heterogeneous); @@ -496,7 +705,7 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, VolumeIntegrateResult result = VOLUME_PATH_ATTENUATED; if(volume_segment.closure_flag & SD_SCATTER) { - bool all = false; + int all = false; /* direct light sampling */ kernel_branched_path_volume_connect_light(kg, rng, &volume_sd, @@ -526,15 +735,15 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, throughput *= volume_segment.accum_transmittance; } } - else -#endif + else +# endif { /* integrate along volume segment with distance sampling */ ShaderData volume_sd; VolumeIntegrateResult result = kernel_volume_integrate( kg, &state, &volume_sd, &volume_ray, &L, &throughput, rng, heterogeneous); -#ifdef __VOLUME_SCATTER__ +# ifdef __VOLUME_SCATTER__ if(result == VOLUME_PATH_SCATTERED) { /* direct lighting */ kernel_path_volume_connect_light(kg, rng, &volume_sd, throughput, &state, &L); @@ -545,7 +754,7 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, else break; } -#endif +# endif } } #endif @@ -572,9 +781,9 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, /* setup shading */ ShaderData sd; - shader_setup_from_ray(kg, &sd, &isect, &ray, state.bounce, state.transparent_bounce); + shader_setup_from_ray(kg, &sd, &isect, &ray); float rbsdf = path_state_rng_1D_for_decision(kg, rng, &state, PRNG_BSDF); - shader_eval_surface(kg, &sd, rbsdf, state.flag, SHADER_CONTEXT_MAIN); + shader_eval_surface(kg, &sd, &state, rbsdf, state.flag, SHADER_CONTEXT_MAIN); /* holdout */ #ifdef __HOLDOUT__ @@ -647,10 +856,19 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, /* bssrdf scatter to a different location on the same object, replacing * the closures with a diffuse BSDF */ if(sd.flag & SD_BSSRDF) { - if(kernel_path_subsurface_scatter(kg, &sd, &L, &state, rng, &ray, &throughput)) + if(kernel_path_subsurface_scatter(kg, + &sd, + &L, + &state, + rng, + &ray, + &throughput, + &ss_indirect)) + { break; + } } -#endif +#endif /* __SUBSURFACE__ */ /* direct lighting */ kernel_path_surface_connect_light(kg, rng, &sd, throughput, &state, &L); @@ -660,6 +878,26 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, break; } +#ifdef __SUBSURFACE__ + kernel_path_subsurface_accum_indirect(&ss_indirect, &L); + + /* Trace indirect subsurface rays by restarting the loop. this uses less + * stack memory than invoking kernel_path_indirect. + */ + if(ss_indirect.num_rays) { + kernel_path_subsurface_setup_indirect(kg, + &ss_indirect, + &state, + &ray, + &L, + &throughput); + } + else { + break; + } + } +#endif /* __SUBSURFACE__ */ + float3 L_sum = path_radiance_clamp_and_sum(kg, &L); kernel_write_light_passes(kg, buffer, &L, sample); |