diff options
author | Brecht Van Lommel <brechtvanlommel@gmail.com> | 2014-03-29 16:03:49 +0400 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@gmail.com> | 2014-03-29 16:03:49 +0400 |
commit | 676e1cbe40cef4bbaffd0346ea467e10e04ed4d1 (patch) | |
tree | 1214452b9355495c216723df8c79a3f9796f4daf /intern/cycles | |
parent | b1615f0e0e09e05b3da9ae52f41cb44011a477e8 (diff) |
Cycles code refactor: move some more volume code into separate functions.
Diffstat (limited to 'intern/cycles')
-rw-r--r-- | intern/cycles/kernel/kernel_volume.h | 142 |
1 files changed, 83 insertions, 59 deletions
diff --git a/intern/cycles/kernel/kernel_volume.h b/intern/cycles/kernel/kernel_volume.h index 19e1629a903..1282e59d57d 100644 --- a/intern/cycles/kernel/kernel_volume.h +++ b/intern/cycles/kernel/kernel_volume.h @@ -193,7 +193,7 @@ ccl_device_noinline void kernel_volume_shadow(KernelGlobals *kg, PathState *stat /* Equi-angular sampling as in: * "Importance Sampling Techniques for Path Tracing in Participating Media" */ -ccl_device float kernel_volume_equiangular_sample(Ray *ray, float3 light_P, float xi, float *pdf) +ccl_device float kernel_volume_equiangular_sample(Ray *ray, float3 sigma_t, float3 light_P, float xi, float3 *transmittance, float *pdf) { float t = ray->t; @@ -205,7 +205,10 @@ ccl_device float kernel_volume_equiangular_sample(Ray *ray, float3 light_P, floa *pdf = D / ((theta_b - theta_a) * (D * D + t_ * t_)); - return min(t, delta + t_); /* min is only for float precision errors */ + float sample_t = min(t, delta + t_); /* min is only for float precision errors */ + *transmittance = volume_color_attenuation(sigma_t, sample_t); + + return sample_t; } ccl_device float kernel_volume_equiangular_pdf(Ray *ray, float3 light_P, float sample_t) @@ -224,6 +227,69 @@ ccl_device float kernel_volume_equiangular_pdf(Ray *ray, float3 light_P, float s return pdf; } +ccl_device bool kernel_volume_equiangular_light_position(KernelGlobals *kg, PathState *state, Ray *ray, RNG *rng, float3 *light_P) +{ + /* light RNGs */ + float light_t = path_state_rng_1D(kg, rng, state, PRNG_LIGHT); + float light_u, light_v; + path_state_rng_2D(kg, rng, state, PRNG_LIGHT_U, &light_u, &light_v); + + /* light sample */ + LightSample ls; + light_sample(kg, light_t, light_u, light_v, ray->time, ray->P, &ls); + if(ls.pdf == 0.0f) + return false; + + *light_P = ls.P; + return true; +} + +/* Distance sampling */ + +ccl_device bool kernel_volume_distance_sample(Ray *ray, float3 sigma_t, int channel, float xi, float *sample_t, float3 *transmittance, float *pdf) +{ + /* xi is [0, 1[ so log(0) should never happen, division by zero is + * avoided because sample_sigma_t > 0 when SD_SCATTER is set */ + float sample_sigma_t = kernel_volume_channel_get(sigma_t, channel); + + *sample_t = min(ray->t, -logf(1.0f - xi)/sample_sigma_t); + *transmittance = volume_color_attenuation(sigma_t, *sample_t); + + if(*sample_t < ray->t) { + /* hit */ + *pdf = dot(sigma_t, *transmittance) * (1.0f/3.0f); + return true; + } + else { + /* miss */ + *pdf = (transmittance->x + transmittance->y + transmittance->z) * (1.0f/3.0f); + return false; + } +} + +/* Emission */ + +ccl_device float3 kernel_volume_emission_integrate(VolumeShaderCoefficients *coeff, int closure_flag, float3 transmittance, float t) +{ + /* integral E * exp(-sigma_t * t) from 0 to t = E * (1 - exp(-sigma_t * t))/sigma_t + * this goes to E * t as sigma_t goes to zero + * + * todo: we should use an epsilon to avoid precision issues near zero sigma_t */ + float3 emission = coeff->emission; + + if(closure_flag & SD_ABSORPTION) { + float3 sigma_t = coeff->sigma_a + coeff->sigma_s; + + emission.x *= (sigma_t.x > 0.0f)? (1.0f - transmittance.x)/sigma_t.x: t; + emission.y *= (sigma_t.y > 0.0f)? (1.0f - transmittance.y)/sigma_t.y: t; + emission.z *= (sigma_t.z > 0.0f)? (1.0f - transmittance.z)/sigma_t.z: t; + } + else + emission *= t; + + return emission; +} + /* Volume Path */ /* homogeneous volume: assume shader evaluation at the start gives @@ -257,21 +323,17 @@ ccl_device VolumeIntegrateResult kernel_volume_integrate_homogeneous(KernelGloba /* distance sampling */ if(kernel_data.integrator.volume_homogeneous_sampling == 0 || !kernel_data.integrator.num_all_lights) { - /* xi is [0, 1[ so log(0) should never happen, division by zero is - * avoided because sample_sigma_t > 0 when SD_SCATTER is set */ float xi = path_state_rng_1D(kg, rng, state, PRNG_SCATTER_DISTANCE); - float sample_t = min(t, -logf(1.0f - xi)/sample_sigma_t); + float pdf, sample_t; - transmittance = volume_color_attenuation(sigma_t, sample_t); - - if(sample_t < t) { - float pdf = dot(sigma_t, transmittance); - new_tp = *throughput * coeff.sigma_s * transmittance * (3.0f / pdf); + if(kernel_volume_distance_sample(ray, sigma_t, channel, xi, &sample_t, &transmittance, &pdf)) { + /* hit */ + new_tp = *throughput * coeff.sigma_s * transmittance / pdf; t = sample_t; } else { - float pdf = (transmittance.x + transmittance.y + transmittance.z); - new_tp = *throughput * transmittance * (3.0f / pdf); + /* miss */ + new_tp = *throughput * transmittance / pdf; } } /* equi-angular sampling */ @@ -292,22 +354,14 @@ ccl_device VolumeIntegrateResult kernel_volume_integrate_homogeneous(KernelGloba /* rescale random number so we can reuse it */ xi = (xi - sample_transmittance)/(1.0f - sample_transmittance); - /* light RNGs */ - float light_t = path_state_rng_1D(kg, rng, state, PRNG_LIGHT); - float light_u, light_v; - path_state_rng_2D(kg, rng, state, PRNG_LIGHT_U, &light_u, &light_v); - - /* light sample */ - LightSample ls; - light_sample(kg, light_t, light_u, light_v, ray->time, ray->P, &ls); - if(ls.pdf == 0.0f) + /* sample position on light */ + float3 light_P; + if(!kernel_volume_equiangular_light_position(kg, state, ray, rng, &light_P)) return VOLUME_PATH_MISSED; /* sampling */ - float sample_t, pdf; - sample_t = kernel_volume_equiangular_sample(ray, ls.P, xi, &pdf); - - transmittance = volume_color_attenuation(sigma_t, sample_t); + float pdf; + float sample_t = kernel_volume_equiangular_sample(ray, sigma_t, light_P, xi, &transmittance, &pdf); new_tp = *throughput * coeff.sigma_s * transmittance / ((1.0f - sample_transmittance) * pdf); t = sample_t; @@ -320,24 +374,9 @@ ccl_device VolumeIntegrateResult kernel_volume_integrate_homogeneous(KernelGloba new_tp = *throughput * transmittance; } - /* integrate emission attenuated by extinction - * integral E * exp(-sigma_t * t) from 0 to t = E * (1 - exp(-sigma_t * t))/sigma_t - * this goes to E * t as sigma_t goes to zero - * - * todo: we should use an epsilon to avoid precision issues near zero sigma_t */ + /* integrate emission attenuated by extinction */ if(closure_flag & SD_EMISSION) { - float3 emission = coeff.emission; - - if(closure_flag & SD_ABSORPTION) { - float3 sigma_t = coeff.sigma_a + coeff.sigma_s; - - emission.x *= (sigma_t.x > 0.0f)? (1.0f - transmittance.x)/sigma_t.x: t; - emission.y *= (sigma_t.y > 0.0f)? (1.0f - transmittance.y)/sigma_t.y: t; - emission.z *= (sigma_t.z > 0.0f)? (1.0f - transmittance.z)/sigma_t.z: t; - } - else - emission *= t; - + float3 emission = kernel_volume_emission_integrate(&coeff, closure_flag, transmittance, t); path_radiance_accum_emission(L, *throughput, emission, state->bounce); } @@ -468,24 +507,9 @@ ccl_device VolumeIntegrateResult kernel_volume_integrate_heterogeneous(KernelGlo * tp_eps check too */ } - /* integrate emission attenuated by absorption - * integral E * exp(-sigma_t * t) from 0 to t = E * (1 - exp(-sigma_t * t))/sigma_t - * this goes to E * t as sigma_t goes to zero - * - * todo: we should use an epsilon to avoid precision issues near zero sigma_t */ + /* integrate emission attenuated by absorption */ if(closure_flag & SD_EMISSION) { - float3 emission = coeff.emission; - - if(closure_flag & SD_ABSORPTION) { - float3 sigma_t = coeff.sigma_a + coeff.sigma_s; - - emission.x *= (sigma_t.x > 0.0f)? (1.0f - transmittance.x)/sigma_t.x: dt; - emission.y *= (sigma_t.y > 0.0f)? (1.0f - transmittance.y)/sigma_t.y: dt; - emission.z *= (sigma_t.z > 0.0f)? (1.0f - transmittance.z)/sigma_t.z: dt; - } - else - emission *= dt; - + float3 emission = kernel_volume_emission_integrate(&coeff, closure_flag, transmittance, dt); path_radiance_accum_emission(L, tp, emission, state->bounce); } |