Changeset View
Changeset View
Standalone View
Standalone View
intern/cycles/kernel/kernel_path.h
| Show First 20 Lines • Show All 84 Lines • ▼ Show 20 Lines | if(dot(sd->Ng, ao_D) > 0.0f && ao_pdf != 0.0f) { | ||||
| light_ray.t = kernel_data.background.ao_distance; | light_ray.t = kernel_data.background.ao_distance; | ||||
| #ifdef __OBJECT_MOTION__ | #ifdef __OBJECT_MOTION__ | ||||
| light_ray.time = sd->time; | light_ray.time = sd->time; | ||||
| #endif /* __OBJECT_MOTION__ */ | #endif /* __OBJECT_MOTION__ */ | ||||
| light_ray.dP = sd->dP; | light_ray.dP = sd->dP; | ||||
| light_ray.dD = differential3_zero(); | light_ray.dD = differential3_zero(); | ||||
| if(!shadow_blocked(kg, emission_sd, state, &light_ray, &ao_shadow)) { | if(!shadow_blocked(kg, emission_sd, state, &light_ray, &ao_shadow)) { | ||||
| path_radiance_accum_ao(L, throughput, ao_alpha, ao_bsdf, ao_shadow, state->bounce); | path_radiance_accum_ao(L, state, throughput, ao_alpha, ao_bsdf, ao_shadow); | ||||
| } | } | ||||
| else { | else { | ||||
| path_radiance_accum_total_ao(L, throughput, ao_bsdf); | path_radiance_accum_total_ao(L, state, throughput, ao_bsdf); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| ccl_device void kernel_path_indirect(KernelGlobals *kg, | ccl_device void kernel_path_indirect(KernelGlobals *kg, | ||||
| ShaderData *sd, | ShaderData *sd, | ||||
| ShaderData *emission_sd, | ShaderData *emission_sd, | ||||
| RNG *rng, | RNG *rng, | ||||
| ▲ Show 20 Lines • Show All 309 Lines • ▼ Show 20 Lines | if(kernel_data.integrator.use_direct_light) { | ||||
| state, | state, | ||||
| throughput, | throughput, | ||||
| 1.0f, | 1.0f, | ||||
| L, | L, | ||||
| all); | all); | ||||
| } | } | ||||
| #endif /* defined(__EMISSION__) && defined(__BRANCHED_PATH__) */ | #endif /* defined(__EMISSION__) && defined(__BRANCHED_PATH__) */ | ||||
| kernel_update_denoising_features(kg, sd, state, L); | |||||
| 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; | break; | ||||
| } | } | ||||
| } | } | ||||
| ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg, | ccl_device_inline float kernel_path_integrate(KernelGlobals *kg, | ||||
| RNG *rng, | RNG *rng, | ||||
| int sample, | int sample, | ||||
| Ray ray, | Ray ray, | ||||
| ccl_global float *buffer) | ccl_global float *buffer, | ||||
| PathRadiance *L, | |||||
| bool *is_shadow_catcher) | |||||
| { | { | ||||
| /* initialize */ | /* initialize */ | ||||
| PathRadiance L; | |||||
| float3 throughput = make_float3(1.0f, 1.0f, 1.0f); | float3 throughput = make_float3(1.0f, 1.0f, 1.0f); | ||||
| float L_transparent = 0.0f; | float L_transparent = 0.0f; | ||||
| path_radiance_init(&L, kernel_data.film.use_light_pass); | path_radiance_init(L, kernel_data.film.use_light_pass); | ||||
| /* shader data memory used for both volumes and surfaces, saves stack space */ | /* shader data memory used for both volumes and surfaces, saves stack space */ | ||||
| ShaderData sd; | ShaderData sd; | ||||
| /* shader data used by emission, shadows, volume stacks */ | /* shader data used by emission, shadows, volume stacks */ | ||||
| ShaderData emission_sd; | ShaderData emission_sd; | ||||
| PathState state; | PathState state; | ||||
| path_state_init(kg, &emission_sd, &state, rng, sample, &ray); | path_state_init(kg, &emission_sd, &state, rng, sample, &ray); | ||||
| ▲ Show 20 Lines • Show All 62 Lines • ▼ Show 20 Lines | if(kernel_data.integrator.use_lamp_mis && !(state.flag & PATH_RAY_CAMERA)) { | ||||
| light_ray.time = ray.time; | light_ray.time = ray.time; | ||||
| light_ray.dD = ray.dD; | light_ray.dD = ray.dD; | ||||
| light_ray.dP = ray.dP; | light_ray.dP = ray.dP; | ||||
| /* intersect with lamp */ | /* intersect with lamp */ | ||||
| float3 emission; | float3 emission; | ||||
| if(indirect_lamp_emission(kg, &emission_sd, &state, &light_ray, &emission)) | if(indirect_lamp_emission(kg, &emission_sd, &state, &light_ray, &emission)) | ||||
| path_radiance_accum_emission(&L, throughput, emission, state.bounce); | path_radiance_accum_emission(L, throughput, emission, state.bounce); | ||||
| } | } | ||||
| #endif /* __LAMP_MIS__ */ | #endif /* __LAMP_MIS__ */ | ||||
| #ifdef __VOLUME__ | #ifdef __VOLUME__ | ||||
| /* Sanitize volume stack. */ | /* Sanitize volume stack. */ | ||||
| if(!hit) { | if(!hit) { | ||||
| kernel_volume_clean_stack(kg, state.volume_stack); | kernel_volume_clean_stack(kg, state.volume_stack); | ||||
| } | } | ||||
| Show All 15 Lines | # ifdef __VOLUME_DECOUPLED__ | ||||
| shader_setup_from_volume(kg, &sd, &volume_ray); | shader_setup_from_volume(kg, &sd, &volume_ray); | ||||
| kernel_volume_decoupled_record(kg, &state, | kernel_volume_decoupled_record(kg, &state, | ||||
| &volume_ray, &sd, &volume_segment, heterogeneous); | &volume_ray, &sd, &volume_segment, heterogeneous); | ||||
| volume_segment.sampling_method = sampling_method; | volume_segment.sampling_method = sampling_method; | ||||
| /* emission */ | /* emission */ | ||||
| if(volume_segment.closure_flag & SD_EMISSION) | if(volume_segment.closure_flag & SD_EMISSION) | ||||
| path_radiance_accum_emission(&L, throughput, volume_segment.accum_emission, state.bounce); | path_radiance_accum_emission(L, throughput, volume_segment.accum_emission, state.bounce); | ||||
| /* scattering */ | /* scattering */ | ||||
| VolumeIntegrateResult result = VOLUME_PATH_ATTENUATED; | VolumeIntegrateResult result = VOLUME_PATH_ATTENUATED; | ||||
| if(volume_segment.closure_flag & SD_SCATTER) { | if(volume_segment.closure_flag & SD_SCATTER) { | ||||
| int all = false; | int all = false; | ||||
| /* direct light sampling */ | /* direct light sampling */ | ||||
| kernel_branched_path_volume_connect_light(kg, rng, &sd, | kernel_branched_path_volume_connect_light(kg, rng, &sd, | ||||
| &emission_sd, throughput, &state, &L, all, | &emission_sd, throughput, &state, L, all, | ||||
| &volume_ray, &volume_segment); | &volume_ray, &volume_segment); | ||||
| /* indirect sample. if we use distance sampling and take just | /* indirect sample. if we use distance sampling and take just | ||||
| * one sample for direct and indirect light, we could share | * one sample for direct and indirect light, we could share | ||||
| * this computation, but makes code a bit complex */ | * this computation, but makes code a bit complex */ | ||||
| float rphase = path_state_rng_1D_for_decision(kg, rng, &state, PRNG_PHASE); | 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 rscatter = path_state_rng_1D_for_decision(kg, rng, &state, PRNG_SCATTER_DISTANCE); | ||||
| result = kernel_volume_decoupled_scatter(kg, | result = kernel_volume_decoupled_scatter(kg, | ||||
| &state, &volume_ray, &sd, &throughput, | &state, &volume_ray, &sd, &throughput, | ||||
| rphase, rscatter, &volume_segment, NULL, true); | rphase, rscatter, &volume_segment, NULL, true); | ||||
| } | } | ||||
| /* free cached steps */ | /* free cached steps */ | ||||
| kernel_volume_decoupled_free(kg, &volume_segment); | kernel_volume_decoupled_free(kg, &volume_segment); | ||||
| if(result == VOLUME_PATH_SCATTERED) { | if(result == VOLUME_PATH_SCATTERED) { | ||||
| if(kernel_path_volume_bounce(kg, rng, &sd, &throughput, &state, &L, &ray)) | if(kernel_path_volume_bounce(kg, rng, &sd, &throughput, &state, L, &ray)) | ||||
| continue; | continue; | ||||
| else | else | ||||
| break; | break; | ||||
| } | } | ||||
| else { | else { | ||||
| throughput *= volume_segment.accum_transmittance; | throughput *= volume_segment.accum_transmittance; | ||||
| } | } | ||||
| } | } | ||||
| else | else | ||||
| # endif /* __VOLUME_DECOUPLED__ */ | # endif /* __VOLUME_DECOUPLED__ */ | ||||
| { | { | ||||
| /* integrate along volume segment with distance sampling */ | /* integrate along volume segment with distance sampling */ | ||||
| VolumeIntegrateResult result = kernel_volume_integrate( | VolumeIntegrateResult result = kernel_volume_integrate( | ||||
| kg, &state, &sd, &volume_ray, &L, &throughput, rng, heterogeneous); | kg, &state, &sd, &volume_ray, L, &throughput, rng, heterogeneous); | ||||
| # ifdef __VOLUME_SCATTER__ | # ifdef __VOLUME_SCATTER__ | ||||
| if(result == VOLUME_PATH_SCATTERED) { | if(result == VOLUME_PATH_SCATTERED) { | ||||
| /* direct lighting */ | /* direct lighting */ | ||||
| kernel_path_volume_connect_light(kg, rng, &sd, &emission_sd, throughput, &state, &L); | kernel_path_volume_connect_light(kg, rng, &sd, &emission_sd, throughput, &state, L); | ||||
| /* indirect light bounce */ | /* indirect light bounce */ | ||||
| if(kernel_path_volume_bounce(kg, rng, &sd, &throughput, &state, &L, &ray)) | if(kernel_path_volume_bounce(kg, rng, &sd, &throughput, &state, L, &ray)) | ||||
| continue; | continue; | ||||
| else | else | ||||
| break; | break; | ||||
| } | } | ||||
| # endif /* __VOLUME_SCATTER__ */ | # endif /* __VOLUME_SCATTER__ */ | ||||
| } | } | ||||
| } | } | ||||
| #endif /* __VOLUME__ */ | #endif /* __VOLUME__ */ | ||||
| if(!hit) { | if(!hit) { | ||||
| /* eval background shader if nothing hit */ | /* eval background shader if nothing hit */ | ||||
| if(kernel_data.background.transparent && (state.flag & PATH_RAY_CAMERA)) { | if(kernel_data.background.transparent && (state.flag & PATH_RAY_CAMERA)) { | ||||
| L_transparent += average(throughput); | L_transparent += average(throughput); | ||||
| #ifdef __PASSES__ | #ifdef __PASSES__ | ||||
| if(!(kernel_data.film.pass_flag & PASS_BACKGROUND)) | if(!(kernel_data.film.pass_flag & PASS_BACKGROUND)) | ||||
| #endif /* __PASSES__ */ | #endif /* __PASSES__ */ | ||||
| break; | break; | ||||
| } | } | ||||
| #ifdef __BACKGROUND__ | #ifdef __BACKGROUND__ | ||||
| /* sample background shader */ | /* sample background shader */ | ||||
| float3 L_background = indirect_background(kg, &emission_sd, &state, &ray); | float3 L_background = indirect_background(kg, &emission_sd, &state, &ray); | ||||
| path_radiance_accum_background(&L, &state, throughput, L_background); | path_radiance_accum_background(L, &state, throughput, L_background); | ||||
| #endif /* __BACKGROUND__ */ | #endif /* __BACKGROUND__ */ | ||||
| break; | break; | ||||
| } | } | ||||
| else if(state.bounce > kernel_data.integrator.ao_bounces) { | else if(state.bounce > kernel_data.integrator.ao_bounces) { | ||||
| break; | break; | ||||
| } | } | ||||
| /* setup shading */ | /* setup shading */ | ||||
| shader_setup_from_ray(kg, &sd, &isect, &ray); | shader_setup_from_ray(kg, &sd, &isect, &ray); | ||||
| float rbsdf = path_state_rng_1D_for_decision(kg, rng, &state, PRNG_BSDF); | float rbsdf = path_state_rng_1D_for_decision(kg, rng, &state, PRNG_BSDF); | ||||
| shader_eval_surface(kg, &sd, rng, &state, rbsdf, state.flag, SHADER_CONTEXT_MAIN); | shader_eval_surface(kg, &sd, rng, &state, rbsdf, state.flag, SHADER_CONTEXT_MAIN); | ||||
| #ifdef __SHADOW_TRICKS__ | #ifdef __SHADOW_TRICKS__ | ||||
| if((sd.object_flag & SD_OBJECT_SHADOW_CATCHER)) { | if((sd.object_flag & SD_OBJECT_SHADOW_CATCHER)) { | ||||
| if(state.flag & PATH_RAY_CAMERA) { | if(state.flag & PATH_RAY_CAMERA) { | ||||
| state.flag |= (PATH_RAY_SHADOW_CATCHER | PATH_RAY_SHADOW_CATCHER_ONLY); | state.flag |= (PATH_RAY_SHADOW_CATCHER | PATH_RAY_SHADOW_CATCHER_ONLY); | ||||
| state.catcher_object = sd.object; | state.catcher_object = sd.object; | ||||
| if(!kernel_data.background.transparent) { | if(!kernel_data.background.transparent) { | ||||
| L.shadow_color = indirect_background(kg, &emission_sd, &state, &ray); | L->shadow_color = indirect_background(kg, &emission_sd, &state, &ray); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| state.flag &= ~PATH_RAY_SHADOW_CATCHER_ONLY; | state.flag &= ~PATH_RAY_SHADOW_CATCHER_ONLY; | ||||
| } | } | ||||
| #endif /* __SHADOW_TRICKS__ */ | #endif /* __SHADOW_TRICKS__ */ | ||||
| Show All 17 Lines | if(((sd.flag & SD_HOLDOUT) || | ||||
| if(sd.object_flag & SD_OBJECT_HOLDOUT_MASK) { | if(sd.object_flag & SD_OBJECT_HOLDOUT_MASK) { | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| #endif /* __HOLDOUT__ */ | #endif /* __HOLDOUT__ */ | ||||
| /* holdout mask objects do not write data passes */ | /* holdout mask objects do not write data passes */ | ||||
| kernel_write_data_passes(kg, buffer, &L, &sd, sample, &state, throughput); | kernel_write_data_passes(kg, buffer, L, &sd, sample, &state, throughput); | ||||
| /* blurring of bsdf after bounces, for rays that have a small likelihood | /* blurring of bsdf after bounces, for rays that have a small likelihood | ||||
| * of following this particular path (diffuse, rough glossy) */ | * of following this particular path (diffuse, rough glossy) */ | ||||
| if(kernel_data.integrator.filter_glossy != FLT_MAX && state.min_ray_pdf < 1e10f) { | if(kernel_data.integrator.filter_glossy != FLT_MAX && state.min_ray_pdf < 1e10f) { | ||||
| 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) { | if(blur_pdf < 1.0f) { | ||||
| float blur_roughness = sqrtf(1.0f - blur_pdf)*0.5f; | float blur_roughness = sqrtf(1.0f - blur_pdf)*0.5f; | ||||
| shader_bsdf_blur(kg, &sd, blur_roughness); | shader_bsdf_blur(kg, &sd, blur_roughness); | ||||
| } | } | ||||
| } | } | ||||
| #ifdef __EMISSION__ | #ifdef __EMISSION__ | ||||
| /* emission */ | /* emission */ | ||||
| if(sd.flag & SD_EMISSION) { | if(sd.flag & SD_EMISSION) { | ||||
| /* todo: is isect.t wrong here for transparent surfaces? */ | /* todo: is isect.t wrong here for transparent surfaces? */ | ||||
| float3 emission = indirect_primitive_emission(kg, &sd, isect.t, state.flag, state.ray_pdf); | float3 emission = indirect_primitive_emission(kg, &sd, isect.t, state.flag, state.ray_pdf); | ||||
| path_radiance_accum_emission(&L, throughput, emission, state.bounce); | path_radiance_accum_emission(L, throughput, emission, state.bounce); | ||||
| } | } | ||||
| #endif /* __EMISSION__ */ | #endif /* __EMISSION__ */ | ||||
| /* path termination. this is a strange place to put the termination, it's | /* 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 | * 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 */ | * shader evaluations, only need emission if we are going to terminate */ | ||||
| float probability = path_state_terminate_probability(kg, &state, throughput); | float probability = path_state_terminate_probability(kg, &state, throughput); | ||||
| if(probability == 0.0f) { | if(probability == 0.0f) { | ||||
| break; | break; | ||||
| } | } | ||||
| else if(probability != 1.0f) { | 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) | if(terminate >= probability) | ||||
| break; | break; | ||||
| throughput /= probability; | throughput /= probability; | ||||
| } | } | ||||
| #ifdef __AO__ | #ifdef __AO__ | ||||
| /* ambient occlusion */ | /* ambient occlusion */ | ||||
| if(kernel_data.integrator.use_ambient_occlusion || (sd.flag & SD_AO)) { | if(kernel_data.integrator.use_ambient_occlusion || (sd.flag & SD_AO)) { | ||||
| kernel_path_ao(kg, &sd, &emission_sd, &L, &state, rng, throughput, shader_bsdf_alpha(kg, &sd)); | kernel_path_ao(kg, &sd, &emission_sd, L, &state, rng, throughput, shader_bsdf_alpha(kg, &sd)); | ||||
| } | } | ||||
| #endif /* __AO__ */ | #endif /* __AO__ */ | ||||
| #ifdef __SUBSURFACE__ | #ifdef __SUBSURFACE__ | ||||
| /* bssrdf scatter to a different location on the same object, replacing | /* bssrdf scatter to a different location on the same object, replacing | ||||
| * the closures with a diffuse BSDF */ | * the closures with a diffuse BSDF */ | ||||
| if(sd.flag & SD_BSSRDF) { | if(sd.flag & SD_BSSRDF) { | ||||
| if(kernel_path_subsurface_scatter(kg, | if(kernel_path_subsurface_scatter(kg, | ||||
| &sd, | &sd, | ||||
| &emission_sd, | &emission_sd, | ||||
| &L, | L, | ||||
| &state, | &state, | ||||
| rng, | rng, | ||||
| &ray, | &ray, | ||||
| &throughput, | &throughput, | ||||
| &ss_indirect)) | &ss_indirect)) | ||||
| { | { | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| #endif /* __SUBSURFACE__ */ | #endif /* __SUBSURFACE__ */ | ||||
| /* direct lighting */ | /* direct lighting */ | ||||
| kernel_path_surface_connect_light(kg, rng, &sd, &emission_sd, throughput, &state, &L); | kernel_path_surface_connect_light(kg, rng, &sd, &emission_sd, throughput, &state, L); | ||||
| kernel_update_denoising_features(kg, &sd, &state, L); | |||||
brecht: I think this should be either done before subsurface scattering, or a call to this function… | |||||
| /* compute direct lighting and next bounce */ | /* compute direct lighting and next bounce */ | ||||
| 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; | break; | ||||
| } | } | ||||
| #ifdef __SUBSURFACE__ | #ifdef __SUBSURFACE__ | ||||
| kernel_path_subsurface_accum_indirect(&ss_indirect, &L); | kernel_path_subsurface_accum_indirect(&ss_indirect, L); | ||||
| /* Trace indirect subsurface rays by restarting the loop. this uses less | /* Trace indirect subsurface rays by restarting the loop. this uses less | ||||
| * stack memory than invoking kernel_path_indirect. | * stack memory than invoking kernel_path_indirect. | ||||
| */ | */ | ||||
| if(ss_indirect.num_rays) { | if(ss_indirect.num_rays) { | ||||
| kernel_path_subsurface_setup_indirect(kg, | kernel_path_subsurface_setup_indirect(kg, | ||||
| &ss_indirect, | &ss_indirect, | ||||
| &state, | &state, | ||||
| &ray, | &ray, | ||||
| &L, | L, | ||||
| &throughput); | &throughput); | ||||
| } | } | ||||
| else { | else { | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| #endif /* __SUBSURFACE__ */ | #endif /* __SUBSURFACE__ */ | ||||
| float3 L_sum; | |||||
| #ifdef __SHADOW_TRICKS__ | #ifdef __SHADOW_TRICKS__ | ||||
| if(state.flag & PATH_RAY_SHADOW_CATCHER) { | *is_shadow_catcher = (state.flag & PATH_RAY_SHADOW_CATCHER); | ||||
| L_sum = path_radiance_sum_shadowcatcher(kg, &L, &L_transparent); | |||||
| } | |||||
| else | |||||
| #endif /* __SHADOW_TRICKS__ */ | #endif /* __SHADOW_TRICKS__ */ | ||||
| { | |||||
| L_sum = path_radiance_clamp_and_sum(kg, &L); | |||||
| } | |||||
| kernel_write_light_passes(kg, buffer, &L, sample); | |||||
| #ifdef __KERNEL_DEBUG__ | #ifdef __KERNEL_DEBUG__ | ||||
| kernel_write_debug_passes(kg, buffer, &state, &debug_data, sample); | kernel_write_debug_passes(kg, buffer, &state, &debug_data, sample); | ||||
| #endif /* __KERNEL_DEBUG__ */ | #endif /* __KERNEL_DEBUG__ */ | ||||
| return make_float4(L_sum.x, L_sum.y, L_sum.z, 1.0f - L_transparent); | return 1.0f - L_transparent; | ||||
| } | } | ||||
| ccl_device void kernel_path_trace(KernelGlobals *kg, | ccl_device void kernel_path_trace(KernelGlobals *kg, | ||||
| ccl_global float *buffer, ccl_global uint *rng_state, | ccl_global float *buffer, ccl_global uint *rng_state, | ||||
| int sample, int x, int y, int offset, int stride) | int sample, int x, int y, int offset, int stride) | ||||
| { | { | ||||
| /* buffer offset */ | /* buffer offset */ | ||||
| int index = offset + x + y*stride; | int index = offset + x + y*stride; | ||||
| int pass_stride = kernel_data.film.pass_stride; | int pass_stride = kernel_data.film.pass_stride; | ||||
| rng_state += index; | rng_state += index; | ||||
| buffer += index*pass_stride; | buffer += index*pass_stride; | ||||
| /* initialize random numbers and ray */ | /* initialize random numbers and ray */ | ||||
| RNG rng; | RNG rng; | ||||
| Ray ray; | Ray ray; | ||||
| kernel_path_trace_setup(kg, rng_state, sample, x, y, &rng, &ray); | kernel_path_trace_setup(kg, rng_state, sample, x, y, &rng, &ray); | ||||
| /* integrate */ | /* integrate */ | ||||
| float4 L; | PathRadiance L; | ||||
| bool is_shadow_catcher; | |||||
| if(ray.t != 0.0f) | |||||
| L = kernel_path_integrate(kg, &rng, sample, ray, buffer); | |||||
| else | |||||
| L = make_float4(0.0f, 0.0f, 0.0f, 0.0f); | |||||
| /* accumulate result in output buffer */ | if(ray.t != 0.0f) { | ||||
| kernel_write_pass_float4(buffer, sample, L); | float alpha = kernel_path_integrate(kg, &rng, sample, ray, buffer, &L, &is_shadow_catcher); | ||||
| kernel_write_result(kg, buffer, sample, &L, alpha, is_shadow_catcher); | |||||
| } | |||||
| else { | |||||
| kernel_write_result(kg, buffer, sample, NULL, 0.0f, false); | |||||
| } | |||||
| path_rng_end(kg, rng_state, rng); | path_rng_end(kg, rng_state, rng); | ||||
| } | } | ||||
| CCL_NAMESPACE_END | CCL_NAMESPACE_END | ||||
I think this should be either done before subsurface scattering, or a call to this function should be added in kernel_path_subsurface_scatter()? Otherwise SSS doesn't contribute to the denoising features as far as I can tell.