diff options
author | Brecht Van Lommel <brechtvanlommel@gmail.com> | 2014-01-03 05:48:48 +0400 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@gmail.com> | 2014-01-03 21:57:38 +0400 |
commit | bb0a0315e28216e64190b3c6e5657438a28ad56d (patch) | |
tree | 02da099e09c58b6b3f8de559d9abe819fb3b9af3 | |
parent | 57407d39b0230a1f1a137beaedb7a4771d8b8272 (diff) |
Code refactor: move random number and MIS variables into PathState.
This makes it easier to pass this state around, and wraps some common RNG
dimension computations in utility functions.
-rw-r--r-- | intern/cycles/kernel/kernel_path.h | 232 | ||||
-rw-r--r-- | intern/cycles/kernel/kernel_path_state.h | 18 | ||||
-rw-r--r-- | intern/cycles/kernel/kernel_random.h | 44 | ||||
-rw-r--r-- | intern/cycles/kernel/kernel_types.h | 19 |
4 files changed, 185 insertions, 128 deletions
diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h index ee56dbd40d9..fda6b45e149 100644 --- a/intern/cycles/kernel/kernel_path.h +++ b/intern/cycles/kernel/kernel_path.h @@ -50,16 +50,11 @@ CCL_NAMESPACE_BEGIN #if defined(__BRANCHED_PATH__) || defined(__SUBSURFACE__) -ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ray ray, ccl_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) +ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, Ray ray, ccl_global float *buffer, + float3 throughput, int num_samples, PathState state, PathRadiance *L) { -#ifdef __LAMP_MIS__ - float ray_t = 0.0f; -#endif - /* path iteration */ - for(;; rng_offset += PRNG_BOUNCE_NUM) { + for(;;) { /* intersect scene */ Intersection isect; uint visibility = path_state_ray_visibility(kg, &state); @@ -74,19 +69,19 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ra /* 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.P = ray.P - state.ray_t*ray.D; + state.ray_t += isect.t; light_ray.D = ray.D; - light_ray.t = ray_t; + light_ray.t = state.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); + float light_t = path_state_rng_1D(kg, rng, &state, PRNG_LIGHT); float3 emission; - if(indirect_lamp_emission(kg, &light_ray, state.flag, ray_pdf, light_t, &emission, state.bounce)) + if(indirect_lamp_emission(kg, &light_ray, state.flag, state.ray_pdf, light_t, &emission, state.bounce)) path_radiance_accum_emission(L, throughput, emission, state.bounce); } #endif @@ -103,7 +98,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ra if(!hit) { #ifdef __BACKGROUND__ /* sample background shader */ - float3 L_background = indirect_background(kg, &ray, state.flag, ray_pdf, state.bounce); + float3 L_background = indirect_background(kg, &ray, state.flag, state.ray_pdf, state.bounce); path_radiance_accum_background(L, throughput, L_background, state.bounce); #endif @@ -113,7 +108,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ra /* 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); + float rbsdf = path_state_rng_1D(kg, rng, &state, PRNG_BSDF); shader_eval_surface(kg, &sd, rbsdf, state.flag, SHADER_CONTEXT_INDIRECT); #ifdef __BRANCHED_PATH__ shader_merge_closures(&sd); @@ -122,7 +117,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ra /* 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; + 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; @@ -133,7 +128,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ra #ifdef __EMISSION__ /* emission */ if(sd.flag & SD_EMISSION) { - float3 emission = indirect_primitive_emission(kg, &sd, isect.t, state.flag, 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); } #endif @@ -147,7 +142,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ra break; } else if(probability != 1.0f) { - float terminate = path_rng_1D(kg, rng, sample, num_total_samples, rng_offset + PRNG_TERMINATE); + float terminate = path_state_rng_1D(kg, rng, &state, PRNG_TERMINATE); if(terminate >= probability) break; @@ -159,7 +154,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ra /* 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); + 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; @@ -201,10 +196,10 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ra /* do bssrdf scatter step if we picked a bssrdf closure */ if(sc) { - uint lcg_state = lcg_init(*rng + rng_offset + sample*0x68bc21eb); + uint lcg_state = lcg_state_init(rng, &state, 0x68bc21eb); float bssrdf_u, bssrdf_v; - path_rng_2D(kg, rng, sample, num_total_samples, rng_offset + PRNG_BSDF_U, &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); state.flag |= PATH_RAY_BSSRDF_ANCESTOR; @@ -216,14 +211,14 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ra 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); + float light_t = path_state_rng_1D(kg, rng, &state, 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); + float light_o = path_state_rng_1D(kg, rng, &state, 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); + path_state_rng_2D(kg, rng, &state, PRNG_LIGHT_U, &light_u, &light_v); Ray light_ray; BsdfEval L_light; @@ -255,7 +250,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ra 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); + path_state_rng_2D(kg, rng, &state, PRNG_BSDF_U, &bsdf_u, &bsdf_v); int label; label = shader_bsdf_sample(kg, &sd, bsdf_u, bsdf_v, &bsdf_eval, @@ -269,11 +264,11 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ra /* set labels */ if(!(label & LABEL_TRANSPARENT)) { - ray_pdf = bsdf_pdf; + state.ray_pdf = bsdf_pdf; #ifdef __LAMP_MIS__ - ray_t = 0.0f; + state.ray_t = 0.0f; #endif - min_ray_pdf = fminf(bsdf_pdf, min_ray_pdf); + state.min_ray_pdf = fminf(bsdf_pdf, state.min_ray_pdf); } /* update path state */ @@ -323,23 +318,20 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ra #ifdef __SUBSURFACE__ ccl_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) + ShaderData *sd, float3 *throughput, PathState *state, PathRadiance *L, Ray *ray) { #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); + float light_t = path_state_rng_1D(kg, rng, state, 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); + float light_o = path_state_rng_1D(kg, rng, state, 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); + path_state_rng_2D(kg, rng, state, PRNG_LIGHT_U, &light_u, &light_v); Ray light_ray; BsdfEval L_light; @@ -370,7 +362,7 @@ ccl_device_inline bool kernel_path_integrate_lighting(KernelGlobals *kg, RNG *rn 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); + path_state_rng_2D(kg, rng, state, PRNG_BSDF_U, &bsdf_u, &bsdf_v); int label; label = shader_bsdf_sample(kg, sd, bsdf_u, bsdf_v, &bsdf_eval, @@ -384,11 +376,11 @@ ccl_device_inline bool kernel_path_integrate_lighting(KernelGlobals *kg, RNG *rn /* set labels */ if(!(label & LABEL_TRANSPARENT)) { - *ray_pdf = bsdf_pdf; + state->ray_pdf = bsdf_pdf; #ifdef __LAMP_MIS__ - *ray_t = 0.0f; + state->ray_t = 0.0f; #endif - *min_ray_pdf = fminf(bsdf_pdf, *min_ray_pdf); + state->min_ray_pdf = fminf(bsdf_pdf, state->min_ray_pdf); } /* update path state */ @@ -450,23 +442,11 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, path_radiance_init(&L, kernel_data.film.use_light_pass); - 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__ - int num_samples = kernel_data.integrator.aa_samples; -#else - int num_samples = 0; -#endif - path_state_init(kg, &state, rng, sample); /* path iteration */ - for(;; rng_offset += PRNG_BOUNCE_NUM) { + for(;;) { /* intersect scene */ Intersection isect; uint visibility = path_state_ray_visibility(kg, &state); @@ -483,7 +463,7 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, } extmax = kernel_data.curve.maximum_width; - lcg_state = lcg_init(*rng + rng_offset + sample*0x51633e2d); + lcg_state = lcg_state_init(rng, &state, 0x51633e2d); } bool hit = scene_intersect(kg, &ray, visibility, &isect, &lcg_state, difl, extmax); @@ -496,19 +476,19 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, /* 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.P = ray.P - state.ray_t*ray.D; + state.ray_t += isect.t; light_ray.D = ray.D; - light_ray.t = ray_t; + light_ray.t = state.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_samples, rng_offset + PRNG_LIGHT); + float light_t = path_state_rng_1D(kg, rng, &state, PRNG_LIGHT); float3 emission; - if(indirect_lamp_emission(kg, &light_ray, state.flag, ray_pdf, light_t, &emission, state.bounce)) + if(indirect_lamp_emission(kg, &light_ray, state.flag, state.ray_pdf, light_t, &emission, state.bounce)) path_radiance_accum_emission(&L, throughput, emission, state.bounce); } #endif @@ -535,7 +515,7 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, #ifdef __BACKGROUND__ /* sample background shader */ - float3 L_background = indirect_background(kg, &ray, state.flag, ray_pdf, state.bounce); + float3 L_background = indirect_background(kg, &ray, state.flag, state.ray_pdf, state.bounce); path_radiance_accum_background(&L, throughput, L_background, state.bounce); #endif @@ -545,7 +525,7 @@ 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); - float rbsdf = path_rng_1D(kg, rng, sample, num_samples, rng_offset + PRNG_BSDF); + float rbsdf = path_state_rng_1D(kg, rng, &state, PRNG_BSDF); shader_eval_surface(kg, &sd, rbsdf, state.flag, SHADER_CONTEXT_MAIN); /* holdout */ @@ -574,7 +554,7 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, /* 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; + 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; @@ -586,7 +566,7 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, /* emission */ if(sd.flag & SD_EMISSION) { /* todo: is isect.t wrong here for transparent surfaces? */ - float3 emission = indirect_primitive_emission(kg, &sd, isect.t, state.flag, 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); } #endif @@ -600,7 +580,7 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, break; } else if(probability != 1.0f) { - float terminate = path_rng_1D(kg, rng, sample, num_samples, rng_offset + PRNG_TERMINATE); + float terminate = path_state_rng_1D(kg, rng, &state, PRNG_TERMINATE); if(terminate >= probability) break; @@ -613,7 +593,7 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, if(kernel_data.integrator.use_ambient_occlusion || (sd.flag & SD_AO)) { /* todo: solve correlation */ float bsdf_u, bsdf_v; - path_rng_2D(kg, rng, sample, num_samples, rng_offset + 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; @@ -655,11 +635,11 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, /* do bssrdf scatter step if we picked a bssrdf closure */ if(sc) { - uint lcg_state = lcg_init(*rng + rng_offset + sample*0x68bc21eb); + uint lcg_state = lcg_state_init(rng, &state, 0x68bc21eb); 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); + 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); /* compute lighting with the BSDF closure */ @@ -667,17 +647,16 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, 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; + hit_state.rng_offset += PRNG_BOUNCE_NUM; - 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+PRNG_BOUNCE_NUM, &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*2, &L); + if(kernel_path_integrate_lighting(kg, rng, &bssrdf_sd[hit], &tp, &hit_state, &L, &hit_ray)) { +#ifdef __LAMP_MIS__ + hit_state.ray_t = 0.0f; +#endif + + kernel_path_indirect(kg, rng, hit_ray, buffer, tp, state.num_samples, hit_state, &L); /* for render passes, sum and reset indirect light pass variables * for the next samples */ @@ -696,14 +675,14 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, 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); + float light_t = path_state_rng_1D(kg, rng, &state, 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); + float light_o = path_state_rng_1D(kg, rng, &state, 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); + path_state_rng_2D(kg, rng, &state, PRNG_LIGHT_U, &light_u, &light_v); Ray light_ray; BsdfEval L_light; @@ -733,7 +712,7 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, 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); + path_state_rng_2D(kg, rng, &state, PRNG_BSDF_U, &bsdf_u, &bsdf_v); int label; label = shader_bsdf_sample(kg, &sd, bsdf_u, bsdf_v, &bsdf_eval, @@ -747,11 +726,11 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, /* set labels */ if(!(label & LABEL_TRANSPARENT)) { - ray_pdf = bsdf_pdf; + state.ray_pdf = bsdf_pdf; #ifdef __LAMP_MIS__ - ray_t = 0.0f; + state.ray_t = 0.0f; #endif - min_ray_pdf = fminf(bsdf_pdf, min_ray_pdf); + state.min_ray_pdf = fminf(bsdf_pdf, state.min_ray_pdf); } /* update path state */ @@ -815,11 +794,9 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, #ifdef __BRANCHED_PATH__ -ccl_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, ccl_global float *buffer) +ccl_device_noinline void kernel_branched_path_integrate_lighting(KernelGlobals *kg, + RNG *rng, ShaderData *sd, float3 throughput, float num_samples_adjust, + PathState *state, PathRadiance *L, ccl_global float *buffer) { #ifdef __EMISSION__ /* sample illumination from lights to find path contribution */ @@ -843,15 +820,15 @@ ccl_device_noinline void kernel_branched_path_integrate_lighting(KernelGlobals * for(int j = 0; j < num_samples; j++) { float light_u, light_v; - path_rng_2D(kg, &lamp_rng, sample*num_samples + j, aa_samples*num_samples, rng_offset + PRNG_LIGHT_U, &light_u, &light_v); + path_branched_rng_2D(kg, &lamp_rng, state, j, num_samples, PRNG_LIGHT_U, &light_u, &light_v); - if(direct_emission(kg, sd, i, 0.0f, 0.0f, light_u, light_v, &light_ray, &L_light, &is_lamp, state.bounce)) { + if(direct_emission(kg, sd, i, 0.0f, 0.0f, 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)) { + if(!shadow_blocked(kg, state, &light_ray, &shadow)) { /* accumulate */ - path_radiance_accum_light(L, throughput*num_samples_inv, &L_light, shadow, num_samples_inv, state.bounce, is_lamp); + path_radiance_accum_light(L, throughput*num_samples_inv, &L_light, shadow, num_samples_inv, state->bounce, is_lamp); } } } @@ -866,21 +843,21 @@ ccl_device_noinline void kernel_branched_path_integrate_lighting(KernelGlobals * num_samples_inv *= 0.5f; for(int j = 0; j < num_samples; j++) { - float light_t = path_rng_1D(kg, rng, sample*num_samples + j, aa_samples*num_samples, rng_offset + PRNG_LIGHT); + float light_t = path_branched_rng_1D(kg, rng, state, j, num_samples, PRNG_LIGHT); float light_u, light_v; - path_rng_2D(kg, rng, sample*num_samples + j, aa_samples*num_samples, rng_offset + PRNG_LIGHT_U, &light_u, &light_v); + path_branched_rng_2D(kg, rng, state, j, num_samples, PRNG_LIGHT_U, &light_u, &light_v); /* only sample triangle lights */ if(kernel_data.integrator.num_all_lights) light_t = 0.5f*light_t; - if(direct_emission(kg, sd, -1, light_t, 0.0f, light_u, light_v, &light_ray, &L_light, &is_lamp, state.bounce)) { + if(direct_emission(kg, sd, -1, light_t, 0.0f, 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)) { + if(!shadow_blocked(kg, state, &light_ray, &shadow)) { /* accumulate */ - path_radiance_accum_light(L, throughput*num_samples_inv, &L_light, shadow, num_samples_inv, state.bounce, is_lamp); + path_radiance_accum_light(L, throughput*num_samples_inv, &L_light, shadow, num_samples_inv, state->bounce, is_lamp); } } } @@ -920,7 +897,7 @@ ccl_device_noinline void kernel_branched_path_integrate_lighting(KernelGlobals * float3 bsdf_omega_in; differential3 bsdf_domega_in; float bsdf_u, bsdf_v; - path_rng_2D(kg, &bsdf_rng, sample*num_samples + j, aa_samples*num_samples, rng_offset + PRNG_BSDF_U, &bsdf_u, &bsdf_v); + path_branched_rng_2D(kg, &bsdf_rng, state, j, num_samples, PRNG_BSDF_U, &bsdf_u, &bsdf_v); int label; label = shader_bsdf_sample_closure(kg, sd, sc, bsdf_u, bsdf_v, &bsdf_eval, @@ -931,13 +908,10 @@ ccl_device_noinline void kernel_branched_path_integrate_lighting(KernelGlobals * /* modify throughput */ float3 tp = throughput; - path_radiance_bsdf_bounce(L, &tp, &bsdf_eval, bsdf_pdf, state.bounce, label); - - /* set labels */ - float min_ray_pdf = fminf(bsdf_pdf, FLT_MAX); + path_radiance_bsdf_bounce(L, &tp, &bsdf_eval, bsdf_pdf, state->bounce, label); /* modify path state */ - PathState ps = state; + PathState ps = *state; path_state_next(kg, &ps, label); /* setup ray */ @@ -960,9 +934,17 @@ ccl_device_noinline void kernel_branched_path_integrate_lighting(KernelGlobals * kernel_volume_stack_enter_exit(kg, sd, ps.volume_stack); #endif - kernel_path_indirect(kg, rng, sample*num_samples + j, bsdf_ray, buffer, - tp*num_samples_inv, num_samples, aa_samples*num_samples, - min_ray_pdf, bsdf_pdf, ps, rng_offset+PRNG_BOUNCE_NUM, L); + /* update RNG state */ + path_state_branch(&ps, j, num_samples); + + /* set MIS state */ + ps.min_ray_pdf = fminf(bsdf_pdf, FLT_MAX); + ps.ray_pdf = bsdf_pdf; +#ifdef __LAMP_MIS__ + ps.ray_t = 0.0f; +#endif + + kernel_path_indirect(kg, rng, bsdf_ray, buffer, tp*num_samples_inv, num_samples, ps, L); /* for render passes, sum and reset indirect light pass variables * for the next samples */ @@ -981,18 +963,10 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in path_radiance_init(&L, kernel_data.film.use_light_pass); - float ray_pdf = 0.0f; PathState state; - int rng_offset = PRNG_BASE_NUM; -#ifdef __CMJ__ - int aa_samples = kernel_data.integrator.aa_samples; -#else - int aa_samples = 0; -#endif - path_state_init(kg, &state, rng, sample); - for(;; rng_offset += PRNG_BOUNCE_NUM) { + for(;;) { /* intersect scene */ Intersection isect; uint visibility = path_state_ray_visibility(kg, &state); @@ -1009,7 +983,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in } extmax = kernel_data.curve.maximum_width; - lcg_state = lcg_init(*rng + rng_offset + sample*0x51633e2d); + lcg_state = lcg_state_init(rng, &state, 0x51633e2d); } bool hit = scene_intersect(kg, &ray, visibility, &isect, &lcg_state, difl, extmax); @@ -1039,7 +1013,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in #ifdef __BACKGROUND__ /* sample background shader */ - float3 L_background = indirect_background(kg, &ray, state.flag, ray_pdf, state.bounce); + float3 L_background = indirect_background(kg, &ray, state.flag, state.ray_pdf, state.bounce); path_radiance_accum_background(&L, throughput, L_background, state.bounce); #endif @@ -1078,7 +1052,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in #ifdef __EMISSION__ /* emission */ if(sd.flag & SD_EMISSION) { - float3 emission = indirect_primitive_emission(kg, &sd, isect.t, state.flag, 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); } #endif @@ -1094,7 +1068,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in break; } else if(probability != 1.0f) { - float terminate = path_rng_1D(kg, rng, sample, aa_samples, rng_offset + PRNG_TERMINATE); + float terminate = path_state_rng_1D(kg, rng, &state, PRNG_TERMINATE); if(terminate >= probability) break; @@ -1115,7 +1089,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in 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); + path_branched_rng_2D(kg, rng, &state, j, num_samples, PRNG_BSDF_U, &bsdf_u, &bsdf_v); float3 ao_D; float ao_pdf; @@ -1152,7 +1126,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in continue; /* set up random number generator */ - uint lcg_state = lcg_init(*rng + rng_offset + sample*0x68bc21eb); + uint lcg_state = lcg_state_init(rng, &state, 0x68bc21eb); int num_samples = kernel_data.integrator.subsurface_samples; float num_samples_inv = 1.0f/num_samples; RNG bssrdf_rng = cmj_hash(*rng, i); @@ -1164,15 +1138,19 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in for(int j = 0; j < num_samples; j++) { ShaderData bssrdf_sd[BSSRDF_MAX_HITS]; float bssrdf_u, bssrdf_v; - path_rng_2D(kg, &bssrdf_rng, sample*num_samples + j, aa_samples*num_samples, rng_offset + PRNG_BSDF_U, &bssrdf_u, &bssrdf_v); + path_branched_rng_2D(kg, &bssrdf_rng, &state, j, num_samples, 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, true); /* compute lighting with the BSDF closure */ - for(int hit = 0; hit < num_hits; hit++) - kernel_branched_path_integrate_lighting(kg, rng, sample*num_samples + j, - aa_samples*num_samples, + for(int hit = 0; hit < num_hits; hit++) { + PathState hit_state = state; + + path_state_branch(&hit_state, j, num_samples); + + kernel_branched_path_integrate_lighting(kg, rng, &bssrdf_sd[hit], throughput, num_samples_inv, - ray_pdf, ray_pdf, state, rng_offset+PRNG_BOUNCE_NUM, &L, buffer); + &hit_state, &L, buffer); + } } state.flag &= ~PATH_RAY_BSSRDF_ANCESTOR; @@ -1181,9 +1159,11 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in #endif if(!(sd.flag & SD_HAS_ONLY_VOLUME)) { + PathState hit_state = state; + /* lighting */ - kernel_branched_path_integrate_lighting(kg, rng, sample, aa_samples, - &sd, throughput, 1.0f, ray_pdf, ray_pdf, state, rng_offset, &L, buffer); + kernel_branched_path_integrate_lighting(kg, rng, + &sd, throughput, 1.0f, &hit_state, &L, buffer); /* continue in case of transparency */ throughput *= shader_bsdf_transparency(kg, &sd); diff --git a/intern/cycles/kernel/kernel_path_state.h b/intern/cycles/kernel/kernel_path_state.h index 3e0ad81c187..fe4d38b10d6 100644 --- a/intern/cycles/kernel/kernel_path_state.h +++ b/intern/cycles/kernel/kernel_path_state.h @@ -19,12 +19,27 @@ CCL_NAMESPACE_BEGIN ccl_device_inline void path_state_init(KernelGlobals *kg, PathState *state, RNG *rng, int sample) { state->flag = PATH_RAY_CAMERA|PATH_RAY_SINGULAR|PATH_RAY_MIS_SKIP; + + state->rng_offset = PRNG_BASE_NUM; + state->sample = sample; +#ifdef __CMJ__ + state->num_samples = kernel_data.integrator.aa_samples; +#else + state->num_samples = 0; +#endif + state->bounce = 0; state->diffuse_bounce = 0; state->glossy_bounce = 0; state->transmission_bounce = 0; state->transparent_bounce = 0; + state->min_ray_pdf = FLT_MAX; + state->ray_pdf = 0.0f; +#ifdef __LAMP_MIS__ + state->ray_t = 0.0f; +#endif + #ifdef __VOLUME__ if(kernel_data.integrator.use_volumes) { /* initialize volume stack with volume we are inside of */ @@ -88,6 +103,9 @@ ccl_device_inline void path_state_next(KernelGlobals *kg, PathState *state, int state->flag |= PATH_RAY_GLOSSY|PATH_RAY_SINGULAR|PATH_RAY_MIS_SKIP; state->flag &= ~PATH_RAY_DIFFUSE; } + + /* random number generator next bounce */ + state->rng_offset += PRNG_BOUNCE_NUM; } ccl_device_inline uint path_state_ray_visibility(KernelGlobals *kg, PathState *state) diff --git a/intern/cycles/kernel/kernel_random.h b/intern/cycles/kernel/kernel_random.h index c435c27b7b4..e3b1c1d7822 100644 --- a/intern/cycles/kernel/kernel_random.h +++ b/intern/cycles/kernel/kernel_random.h @@ -227,6 +227,8 @@ ccl_device void path_rng_end(KernelGlobals *kg, ccl_global uint *rng_state, RNG #endif +/* Linear Congruential Generator */ + ccl_device uint lcg_step_uint(uint *rng) { /* implicit mod 2^32 */ @@ -248,5 +250,47 @@ ccl_device uint lcg_init(uint seed) return rng; } +/* Path Tracing Utility Functions + * + * For each random number in each step of the path we must have a unique + * dimension to avoid using the same sequence twice. + * + * For branches in the path we must be careful not to reuse the same number + * in a sequence and offset accordingly. */ + +ccl_device_inline float path_state_rng_1D(KernelGlobals *kg, RNG *rng, PathState *state, int dimension) +{ + return path_rng_1D(kg, rng, state->sample, state->num_samples, state->rng_offset + dimension); +} + +ccl_device_inline void path_state_rng_2D(KernelGlobals *kg, RNG *rng, PathState *state, int dimension, float *fx, float *fy) +{ + path_rng_2D(kg, rng, state->sample, state->num_samples, state->rng_offset + dimension, fx, fy); +} + +ccl_device_inline float path_branched_rng_1D(KernelGlobals *kg, RNG *rng, PathState *state, int branch, int num_branches, int dimension) +{ + return path_rng_1D(kg, rng, state->sample*num_branches + branch, state->num_samples*num_branches, state->rng_offset + dimension); +} + +ccl_device_inline void path_branched_rng_2D(KernelGlobals *kg, RNG *rng, PathState *state, int branch, int num_branches, int dimension, float *fx, float *fy) +{ + path_rng_2D(kg, rng, state->sample*num_branches + branch, state->num_samples*num_branches, state->rng_offset + dimension, fx, fy); +} + +ccl_device_inline void path_state_branch(PathState *state, int branch, int num_branches) +{ + /* path is splitting into a branch, adjust so that each branch + * still gets a unique sample from the same sequence */ + state->rng_offset += PRNG_BOUNCE_NUM; + state->sample = state->sample*num_branches + branch; + state->num_samples = state->num_samples*num_branches; +} + +ccl_device inline uint lcg_state_init(RNG *rng, PathState *state, uint scramble) +{ + return lcg_init(*rng + state->rng_offset + state->sample*scramble); +} + CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index 00cb73b1e34..faed1e7a71e 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -622,14 +622,29 @@ typedef struct VolumeStack { #endif typedef struct PathState { - int flag; - int bounce; + /* see enum PathRayFlag */ + int flag; + + /* random number generator state */ + int rng_offset; /* dimension offset */ + int sample; /* path sample number */ + int num_samples; /* total number of times this path will be sampled */ + /* bounce counting */ + int bounce; int diffuse_bounce; int glossy_bounce; int transmission_bounce; int transparent_bounce; + /* multiple importance sampling */ + float min_ray_pdf; /* smallest bounce pdf over entire path up to now */ + float ray_pdf; /* last bounce pdf */ +#ifdef __LAMP_MIS__ + float ray_t; /* accumulated distance through transparent surfaces */ +#endif + + /* volume rendering */ #ifdef __VOLUME__ RNG rng_congruential; VolumeStack volume_stack[VOLUME_STACK_SIZE]; |