From 722d0d92adefbeca2fb8326ce7bf217530d7b59c Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Sat, 24 Aug 2013 15:02:08 +0000 Subject: [PATCH] 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. --- intern/cycles/blender/blender_sync.cpp | 2 +- intern/cycles/kernel/kernel_path.h | 744 ++++++++++++++--------- intern/cycles/kernel/kernel_subsurface.h | 14 +- intern/cycles/kernel/kernel_types.h | 1 + intern/cycles/render/osl.cpp | 1 + 5 files changed, 450 insertions(+), 312 deletions(-) diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp index 38a6c8eac91..4a686487462 100644 --- a/intern/cycles/blender/blender_sync.cpp +++ b/intern/cycles/blender/blender_sync.cpp @@ -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"); diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h index cdf80aed4d1..8cb83e0797e 100644 --- a/intern/cycles/kernel/kernel_path.h +++ b/intern/cycles/kernel/kernel_path.h @@ -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 diff --git a/intern/cycles/kernel/kernel_subsurface.h b/intern/cycles/kernel/kernel_subsurface.h index 7127775669b..5eb641f5af4 100644 --- a/intern/cycles/kernel/kernel_subsurface.h +++ b/intern/cycles/kernel/kernel_subsurface.h @@ -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 */ diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index caf68e913e8..f64277564c4 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -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 */ diff --git a/intern/cycles/render/osl.cpp b/intern/cycles/render/osl.cpp index 038da269d91..d0ed95cca34 100644 --- a/intern/cycles/render/osl.cpp +++ b/intern/cycles/render/osl.cpp @@ -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]);