Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrecht Van Lommel <brechtvanlommel@gmail.com>2013-12-28 19:56:19 +0400
committerBrecht Van Lommel <brechtvanlommel@gmail.com>2013-12-28 19:57:10 +0400
commite369a5c48529864118d49222dde3d530d58ebeae (patch)
tree8d803e5318c57b7bfbdd321da1393e4d71878d35 /intern/cycles/kernel/kernel_path.h
parent133f770ab3e7a6db49562cb73cb7aa5f75cf13f8 (diff)
Cycles Volume Render: support for rendering of homogeneous volume with absorption.
This is the simplest possible volume rendering case, constant density inside the volume and no scattering or emission. My plan is to tweak, verify and commit more volume rendering effects one by one, doing it all at once makes it difficult to verify correctness and track down bugs. Documentation is here: http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Materials/Volume Currently this hooks into path tracing in 3 ways, which should get us pretty far until we add more advanced light sampling. These 3 hooks are repeated in the path tracing, branched path tracing and transparent shadow code: * Determine active volume shader at start of the path * Change active volume shader on transmission through a surface * Light attenuation over line segments between camera, surfaces and background This is work by "storm", Stuart Broadfoot, Thomas Dinges and myself.
Diffstat (limited to 'intern/cycles/kernel/kernel_path.h')
-rw-r--r--intern/cycles/kernel/kernel_path.h349
1 files changed, 237 insertions, 112 deletions
diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h
index 903efc9d6f5..d318a85fcb7 100644
--- a/intern/cycles/kernel/kernel_path.h
+++ b/intern/cycles/kernel/kernel_path.h
@@ -40,6 +40,10 @@
#include "kernel_subsurface.h"
#endif
+#ifdef __VOLUME__
+#include "kernel_volume.h"
+#endif
+
#include "kernel_shadow.h"
CCL_NAMESPACE_BEGIN
@@ -87,6 +91,15 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ra
}
#endif
+#ifdef __VOLUME__
+ /* volume attenuation */
+ if(state.volume_shader != SHADER_NO_ID) {
+ Ray segment_ray = ray;
+ segment_ray.t = (hit)? isect.t: FLT_MAX;
+ throughput *= kernel_volume_get_shadow_attenuation(kg, &state, &segment_ray, state.volume_shader);
+ }
+#endif
+
if(!hit) {
#ifdef __BACKGROUND__
/* sample background shader */
@@ -235,47 +248,73 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ra
#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;
+ if(sd.flag & SD_BSDF) {
+ /* 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);
+ 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;
+ 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);
+ /* 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;
+ /* set labels */
+ if(!(label & LABEL_TRANSPARENT)) {
+ ray_pdf = bsdf_pdf;
#ifdef __LAMP_MIS__
- ray_t = 0.0f;
+ 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
+
+#ifdef __VOLUME__
+ /* enter/exit volume */
+ if(label & LABEL_TRANSMIT)
+ kernel_volume_enter_exit(kg, &sd, &state.volume_shader);
#endif
- min_ray_pdf = fminf(bsdf_pdf, min_ray_pdf);
}
+#ifdef __VOLUME__
+ else if(sd.flag & SD_HAS_ONLY_VOLUME) {
+ /* no surface shader but have a volume shader? act transparent */
- /* update path state */
- path_state_next(kg, &state, label);
+ /* update path state, count as transparent */
+ path_state_next(kg, &state, LABEL_TRANSPARENT);
- /* setup ray */
- ray.P = ray_offset(sd.P, (label & LABEL_TRANSMIT)? -sd.Ng: sd.Ng);
- ray.D = bsdf_omega_in;
- ray.t = FLT_MAX;
+ /* setup ray position, direction stays unchanged */
+ ray.P = ray_offset(sd.P, -sd.Ng);
#ifdef __RAY_DIFFERENTIALS__
- ray.dP = sd.dP;
- ray.dD = bsdf_domega_in;
+ ray.dP = sd.dP;
#endif
+
+ /* enter/exit volume */
+ kernel_volume_enter_exit(kg, &sd, &state.volume_shader);
+ }
+#endif
+ else {
+ /* no bsdf or volume? we're done */
+ break;
+ }
}
}
@@ -324,54 +363,80 @@ ccl_device_inline bool kernel_path_integrate_lighting(KernelGlobals *kg, RNG *rn
#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;
+ if(sd->flag & SD_BSDF) {
+ /* 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);
+ 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;
+ 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);
+ /* 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;
+ /* set labels */
+ if(!(label & LABEL_TRANSPARENT)) {
+ *ray_pdf = bsdf_pdf;
#ifdef __LAMP_MIS__
- *ray_t = 0.0f;
+ *ray_t = 0.0f;
#endif
- *min_ray_pdf = fminf(bsdf_pdf, *min_ray_pdf);
- }
+ *min_ray_pdf = fminf(bsdf_pdf, *min_ray_pdf);
+ }
- /* update path state */
- path_state_next(kg, state, label);
+ /* 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;
+ /* 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;
+ 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
+
+#ifdef __VOLUME__
+ /* enter/exit volume */
+ if(label & LABEL_TRANSMIT)
+ kernel_volume_enter_exit(kg, sd, &state->volume_shader);
+#endif
+ return true;
+ }
+#ifdef __VOLUME__
+ else if(sd->flag & SD_HAS_ONLY_VOLUME) {
+ /* no surface shader but have a volume shader? act transparent */
+
+ /* update path state, count as transparent */
+ path_state_next(kg, state, LABEL_TRANSPARENT);
+ /* setup ray position, direction stays unchanged */
+ ray->P = ray_offset(sd->P, -sd->Ng);
#ifdef __RAY_DIFFERENTIALS__
- ray->dP = sd->dP;
- ray->dD = bsdf_domega_in;
+ ray->dP = sd->dP;
+#endif
+
+ /* enter/exit volume */
+ kernel_volume_enter_exit(kg, sd, &state->volume_shader);
+ return true;
+ }
#endif
-
- return true;
+ else {
+ /* no bsdf or volume? */
+ return false;
+ }
}
#endif
@@ -398,7 +463,7 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample,
int num_samples = 0;
#endif
- path_state_init(&state);
+ path_state_init(kg, &state);
/* path iteration */
for(;; rng_offset += PRNG_BOUNCE_NUM) {
@@ -448,6 +513,15 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample,
}
#endif
+#ifdef __VOLUME__
+ /* volume attenuation */
+ if(state.volume_shader != SHADER_NO_ID) {
+ Ray segment_ray = ray;
+ segment_ray.t = (hit)? isect.t: FLT_MAX;
+ throughput *= kernel_volume_get_shadow_attenuation(kg, &state, &segment_ray, state.volume_shader);
+ }
+#endif
+
if(!hit) {
/* eval background shader if nothing hit */
if(kernel_data.background.transparent && (state.flag & PATH_RAY_CAMERA)) {
@@ -652,53 +726,80 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample,
}
#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_samples, rng_offset + PRNG_BSDF_U, &bsdf_u, &bsdf_v);
- int label;
+ if(sd.flag & SD_BSDF) {
+ /* 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);
+ 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;
+ 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);
+ /* 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;
+ /* set labels */
+ if(!(label & LABEL_TRANSPARENT)) {
+ ray_pdf = bsdf_pdf;
#ifdef __LAMP_MIS__
- ray_t = 0.0f;
+ 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;
+
+#ifdef __RAY_DIFFERENTIALS__
+ ray.dP = sd.dP;
+ ray.dD = bsdf_domega_in;
#endif
- min_ray_pdf = fminf(bsdf_pdf, min_ray_pdf);
+
+#ifdef __VOLUME__
+ /* enter/exit volume */
+ if(label & LABEL_TRANSMIT)
+ kernel_volume_enter_exit(kg, &sd, &state.volume_shader);
+#endif
+
}
+#ifdef __VOLUME__
+ else if(sd.flag & SD_HAS_ONLY_VOLUME) {
+ /* no surface shader but have a volume shader? act transparent */
- /* update path state */
- path_state_next(kg, &state, label);
+ /* update path state, count as transparent */
+ path_state_next(kg, &state, LABEL_TRANSPARENT);
- /* setup ray */
- ray.P = ray_offset(sd.P, (label & LABEL_TRANSMIT)? -sd.Ng: sd.Ng);
- ray.D = bsdf_omega_in;
+ /* setup ray position, direction stays unchanged */
+ ray.P = ray_offset(sd.P, -sd.Ng);
+#ifdef __RAY_DIFFERENTIALS__
+ ray.dP = sd.dP;
+#endif
+
+ /* enter/exit volume */
+ kernel_volume_enter_exit(kg, &sd, &state.volume_shader);
+ }
+#endif
+ else {
+ /* no bsdf or volume? we're done */
+ break;
+ }
+ /* adjust ray distance for clipping */
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
}
float3 L_sum = path_radiance_sum(kg, &L);
@@ -853,6 +954,12 @@ ccl_device_noinline void kernel_branched_path_integrate_lighting(KernelGlobals *
bsdf_ray.time = sd->time;
#endif
+#ifdef __VOLUME__
+ /* enter/exit volume */
+ if(label & LABEL_TRANSMIT)
+ kernel_volume_enter_exit(kg, sd, &ps.volume_shader);
+#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);
@@ -883,7 +990,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
int aa_samples = 0;
#endif
- path_state_init(&state);
+ path_state_init(kg, &state);
for(;; rng_offset += PRNG_BOUNCE_NUM) {
/* intersect scene */
@@ -905,10 +1012,21 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
lcg_state = lcg_init(*rng + rng_offset + sample*0x51633e2d);
}
- if(!scene_intersect(kg, &ray, visibility, &isect, &lcg_state, difl, extmax)) {
+ bool hit = scene_intersect(kg, &ray, visibility, &isect, &lcg_state, difl, extmax);
#else
- if(!scene_intersect(kg, &ray, visibility, &isect)) {
+ bool hit = scene_intersect(kg, &ray, visibility, &isect);
#endif
+
+#ifdef __VOLUME__
+ /* volume attenuation */
+ if(state.volume_shader != SHADER_NO_ID) {
+ Ray segment_ray = ray;
+ segment_ray.t = (hit)? isect.t: FLT_MAX;
+ throughput *= kernel_volume_get_shadow_attenuation(kg, &state, &segment_ray, state.volume_shader);
+ }
+#endif
+
+ if(!hit) {
/* eval background shader if nothing hit */
if(kernel_data.background.transparent) {
L_transparent += average(throughput);
@@ -1062,19 +1180,26 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
}
#endif
- /* lighting */
- kernel_branched_path_integrate_lighting(kg, rng, sample, aa_samples,
- &sd, throughput, 1.0f, ray_pdf, ray_pdf, state, rng_offset, &L, buffer);
+ if(!(sd.flag & SD_HAS_ONLY_VOLUME)) {
+ /* lighting */
+ kernel_branched_path_integrate_lighting(kg, rng, sample, aa_samples,
+ &sd, throughput, 1.0f, ray_pdf, ray_pdf, state, rng_offset, &L, buffer);
- /* continue in case of transparency */
- throughput *= shader_bsdf_transparency(kg, &sd);
+ /* continue in case of transparency */
+ throughput *= shader_bsdf_transparency(kg, &sd);
- if(is_zero(throughput))
- break;
+ if(is_zero(throughput))
+ break;
+ }
path_state_next(kg, &state, LABEL_TRANSPARENT);
ray.P = ray_offset(sd.P, -sd.Ng);
ray.t -= sd.ray_length; /* clipping works through transparent */
+
+#ifdef __VOLUME__
+ /* enter/exit volume */
+ kernel_volume_enter_exit(kg, &sd, &state.volume_shader);
+#endif
}
float3 L_sum = path_radiance_sum(kg, &L);
@@ -1139,7 +1264,7 @@ ccl_device void kernel_path_trace(KernelGlobals *kg,
/* integrate */
float4 L;
- if (ray.t != 0.0f)
+ 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);
@@ -1171,7 +1296,7 @@ ccl_device void kernel_branched_path_trace(KernelGlobals *kg,
/* integrate */
float4 L;
- if (ray.t != 0.0f)
+ if(ray.t != 0.0f)
L = kernel_branched_path_integrate(kg, &rng, sample, ray, buffer);
else
L = make_float4(0.0f, 0.0f, 0.0f, 0.0f);