diff options
author | Brecht Van Lommel <brechtvanlommel@gmail.com> | 2013-12-29 18:49:16 +0400 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@gmail.com> | 2013-12-30 03:04:02 +0400 |
commit | 30aa0c2482367fd5a99f2b791206b9e72d9ca7e3 (patch) | |
tree | 5cd2ab2810b93cc4e2d71c39ccc1d61557953f7e /intern | |
parent | 5d3adafcbb72f3c4273d80d36b34364313ae8c49 (diff) |
Code refactor: better distinguish scatter and absorption for volume integration.
Diffstat (limited to 'intern')
-rw-r--r-- | intern/cycles/kernel/closure/volume.h | 4 | ||||
-rw-r--r-- | intern/cycles/kernel/kernel_path.h | 21 | ||||
-rw-r--r-- | intern/cycles/kernel/kernel_types.h | 25 | ||||
-rw-r--r-- | intern/cycles/kernel/kernel_volume.h | 75 |
4 files changed, 68 insertions, 57 deletions
diff --git a/intern/cycles/kernel/closure/volume.h b/intern/cycles/kernel/closure/volume.h index 4cf918f32b8..951a03bce71 100644 --- a/intern/cycles/kernel/closure/volume.h +++ b/intern/cycles/kernel/closure/volume.h @@ -39,7 +39,7 @@ ccl_device int volume_henyey_greenstein_setup(ShaderClosure *sc) /* clamp anisotropy to avoid delta function */ sc->data0 = signf(sc->data0) * min(fabsf(sc->data0), 1.0f - 1e-3f); - return SD_BSDF|SD_BSDF_HAS_EVAL|SD_VOLUME; + return SD_BSDF|SD_BSDF_HAS_EVAL|SD_SCATTER; } ccl_device float3 volume_henyey_greenstein_eval_phase(const ShaderClosure *sc, const float3 I, float3 omega_in, float *pdf) @@ -98,7 +98,7 @@ ccl_device int volume_absorption_setup(ShaderClosure *sc) { sc->type = CLOSURE_VOLUME_ABSORPTION_ID; - return SD_VOLUME; + return SD_ABSORPTION; } /* VOLUME CLOSURE */ diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h index 7aea673528a..204f782e5f4 100644 --- a/intern/cycles/kernel/kernel_path.h +++ b/intern/cycles/kernel/kernel_path.h @@ -92,11 +92,10 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ra #endif #ifdef __VOLUME__ - /* volume attenuation */ + /* volume attenuation, emission, scatter */ if(state.volume_stack[0].shader != SHADER_NO_ID) { - Ray segment_ray = ray; - segment_ray.t = (hit)? isect.t: FLT_MAX; - kernel_volume_integrate(kg, &state, &segment_ray, L, &throughput); + ray.t = (hit)? isect.t: FLT_MAX; + kernel_volume_integrate(kg, &state, &ray, L, &throughput); } #endif @@ -514,11 +513,10 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, #endif #ifdef __VOLUME__ - /* volume attenuation */ + /* volume attenuation, emission, scatter */ if(state.volume_stack[0].shader != SHADER_NO_ID) { - Ray segment_ray = ray; - segment_ray.t = (hit)? isect.t: FLT_MAX; - kernel_volume_integrate(kg, &state, &segment_ray, &L, &throughput); + ray.t = (hit)? isect.t: FLT_MAX; + kernel_volume_integrate(kg, &state, &ray, &L, &throughput); } #endif @@ -1018,11 +1016,10 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in #endif #ifdef __VOLUME__ - /* volume attenuation */ + /* volume attenuation, emission, scatter */ if(state.volume_stack[0].shader != SHADER_NO_ID) { - Ray segment_ray = ray; - segment_ray.t = (hit)? isect.t: FLT_MAX; - kernel_volume_integrate(kg, &state, &segment_ray, &L, &throughput); + ray.t = (hit)? isect.t: FLT_MAX; + kernel_volume_integrate(kg, &state, &ray, &L, &throughput); } #endif diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index 3091defd465..63cd2b223a3 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -500,25 +500,26 @@ enum ShaderDataFlag { SD_BSDF_GLOSSY = 16, /* have glossy bsdf */ SD_BSSRDF = 32, /* have bssrdf */ SD_HOLDOUT = 64, /* have holdout closure? */ - SD_VOLUME = 128, /* have volume closure? */ - SD_AO = 256, /* have ao closure? */ + SD_ABSORPTION = 128, /* have volume absorption closure? */ + SD_SCATTER = 256, /* have volume scattering closure? */ + SD_AO = 512, /* have ao closure? */ - SD_CLOSURE_FLAGS = (SD_EMISSION|SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_GLOSSY|SD_BSSRDF|SD_HOLDOUT|SD_VOLUME|SD_AO), + SD_CLOSURE_FLAGS = (SD_EMISSION|SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_GLOSSY|SD_BSSRDF|SD_HOLDOUT|SD_ABSORPTION|SD_SCATTER|SD_AO), /* shader flags */ - SD_USE_MIS = 512, /* direct light sample */ - SD_HAS_TRANSPARENT_SHADOW = 1024, /* has transparent shadow */ - SD_HAS_VOLUME = 2048, /* has volume shader */ - SD_HAS_ONLY_VOLUME = 4096, /* has only volume shader, no surface */ - SD_HOMOGENEOUS_VOLUME = 8192, /* has homogeneous volume */ - SD_HAS_BSSRDF_BUMP = 16384, /* bssrdf normal uses bump */ + SD_USE_MIS = 1024, /* direct light sample */ + SD_HAS_TRANSPARENT_SHADOW = 2048, /* has transparent shadow */ + SD_HAS_VOLUME = 4096, /* has volume shader */ + SD_HAS_ONLY_VOLUME = 8192, /* has only volume shader, no surface */ + SD_HOMOGENEOUS_VOLUME = 16384, /* has homogeneous volume */ + SD_HAS_BSSRDF_BUMP = 32768, /* bssrdf normal uses bump */ SD_SHADER_FLAGS = (SD_USE_MIS|SD_HAS_TRANSPARENT_SHADOW|SD_HAS_VOLUME|SD_HAS_ONLY_VOLUME|SD_HOMOGENEOUS_VOLUME|SD_HAS_BSSRDF_BUMP), /* object flags */ - SD_HOLDOUT_MASK = 32768, /* holdout for camera rays */ - SD_OBJECT_MOTION = 65536, /* has object motion blur */ - SD_TRANSFORM_APPLIED = 131072, /* vertices have transform applied */ + SD_HOLDOUT_MASK = 65536, /* holdout for camera rays */ + SD_OBJECT_MOTION = 131072, /* has object motion blur */ + SD_TRANSFORM_APPLIED = 262144, /* vertices have transform applied */ SD_OBJECT_FLAGS = (SD_HOLDOUT_MASK|SD_OBJECT_MOTION|SD_TRANSFORM_APPLIED) }; diff --git a/intern/cycles/kernel/kernel_volume.h b/intern/cycles/kernel/kernel_volume.h index 6b198ed9173..ee9e28999ed 100644 --- a/intern/cycles/kernel/kernel_volume.h +++ b/intern/cycles/kernel/kernel_volume.h @@ -16,16 +16,23 @@ CCL_NAMESPACE_BEGIN +typedef enum VolumeIntegrateResult { + VOLUME_PATH_TERMINATED = 0, + VOLUME_PATH_SCATTERED = 1, + VOLUME_PATH_ATTENUATED = 2, + VOLUME_PATH_MISSED = 3 +} VolumeIntegrateResult; + /* Volume shader properties * * extinction coefficient = absorption coefficient + scattering coefficient * sigma_t = sigma_a + sigma_s */ -typedef struct VolumeShaderSample { +typedef struct VolumeShaderCoefficients { float3 sigma_a; float3 sigma_s; float3 emission; -} VolumeShaderSample; +} VolumeShaderCoefficients; /* evaluate shader to get extinction coefficient at P */ ccl_device bool volume_shader_extinction_sample(KernelGlobals *kg, ShaderData *sd, VolumeStack *stack, int path_flag, ShaderContext ctx, float3 P, float3 *extinction) @@ -33,7 +40,7 @@ ccl_device bool volume_shader_extinction_sample(KernelGlobals *kg, ShaderData *s sd->P = P; shader_eval_volume(kg, sd, stack, 0.0f, path_flag, ctx); - if(!(sd->flag & SD_VOLUME)) + if(!(sd->flag & (SD_ABSORPTION|SD_SCATTER))) return false; float3 sigma_t = make_float3(0.0f, 0.0f, 0.0f); @@ -50,12 +57,12 @@ ccl_device bool volume_shader_extinction_sample(KernelGlobals *kg, ShaderData *s } /* evaluate shader to get absorption, scattering and emission at P */ -ccl_device bool volume_shader_sample(KernelGlobals *kg, ShaderData *sd, VolumeStack *stack, int path_flag, ShaderContext ctx, float3 P, VolumeShaderSample *sample) +ccl_device bool volume_shader_sample(KernelGlobals *kg, ShaderData *sd, VolumeStack *stack, int path_flag, ShaderContext ctx, float3 P, VolumeShaderCoefficients *sample) { sd->P = P; shader_eval_volume(kg, sd, stack, 0.0f, path_flag, ctx); - if(!(sd->flag & (SD_VOLUME|SD_EMISSION))) + if(!(sd->flag & (SD_ABSORPTION|SD_SCATTER|SD_EMISSION))) return false; sample->sigma_a = make_float3(0.0f, 0.0f, 0.0f); @@ -83,12 +90,12 @@ ccl_device float3 volume_color_attenuation(float3 sigma, float t) /* Volumetric Shadows */ -/* get the volume attenuation over line segment defined by segment_ray, with the +/* get the volume attenuation over line segment defined by ray, with the * assumption that there are no surfaces blocking light between the endpoints */ -ccl_device void kernel_volume_get_shadow_attenuation(KernelGlobals *kg, PathState *state, Ray *segment_ray, float3 *throughput) +ccl_device void kernel_volume_get_shadow_attenuation(KernelGlobals *kg, PathState *state, Ray *ray, float3 *throughput) { ShaderData sd; - shader_setup_from_volume(kg, &sd, segment_ray, state->bounce); + shader_setup_from_volume(kg, &sd, ray, state->bounce); ShaderContext ctx = SHADER_CONTEXT_SHADOW; int path_flag = PATH_RAY_SHADOW; @@ -96,54 +103,58 @@ ccl_device void kernel_volume_get_shadow_attenuation(KernelGlobals *kg, PathStat /* homogenous volume: assume shader evaluation at the starts gives * the extinction coefficient for the entire line segment */ - if(!volume_shader_extinction_sample(kg, &sd, state->volume_stack, path_flag, ctx, segment_ray->P, &sigma_t)) + if(!volume_shader_extinction_sample(kg, &sd, state->volume_stack, path_flag, ctx, ray->P, &sigma_t)) return; - *throughput *= volume_color_attenuation(sigma_t, segment_ray->t); + *throughput *= volume_color_attenuation(sigma_t, ray->t); } /* Volumetric Path */ /* get the volume attenuation and emission over line segment defined by - * segment_ray, with the assumption that there are no surfaces blocking light + * ray, with the assumption that there are no surfaces blocking light * between the endpoints */ -ccl_device void kernel_volume_integrate(KernelGlobals *kg, PathState *state, Ray *segment_ray, PathRadiance *L, float3 *throughput) +ccl_device VolumeIntegrateResult kernel_volume_integrate(KernelGlobals *kg, PathState *state, Ray *ray, PathRadiance *L, float3 *throughput) { ShaderData sd; - shader_setup_from_volume(kg, &sd, segment_ray, state->bounce); + shader_setup_from_volume(kg, &sd, ray, state->bounce); ShaderContext ctx = SHADER_CONTEXT_VOLUME; int path_flag = PATH_RAY_SHADOW; - VolumeShaderSample sample; + VolumeShaderCoefficients coeff; /* homogenous volume: assume shader evaluation at the starts gives * the extinction coefficient for the entire line segment */ - if(!volume_shader_sample(kg, &sd, state->volume_stack, path_flag, ctx, segment_ray->P, &sample)) - return; + if(!volume_shader_sample(kg, &sd, state->volume_stack, path_flag, ctx, ray->P, &coeff)) + return VOLUME_PATH_MISSED; + + /* todo: in principle the SD_EMISSION, SD_ABSORPTION and SD_SCATTER flags + * should ensure that one of the components is > 0 and so no division by + * zero occurs, however this needs to be double-checked and tested */ int closure_flag = sd.flag; - float t = segment_ray->t; + float t = ray->t; /* compute attenuation from absorption (+ scattering for now) */ - float3 sigma_t, attenuation; + float3 attenuation; - if(closure_flag & SD_VOLUME) { - sigma_t = sample.sigma_a + sample.sigma_s; - attenuation = volume_color_attenuation(sigma_t, t); - } + if(closure_flag & SD_ABSORPTION) + attenuation = volume_color_attenuation(coeff.sigma_a, t); /* 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 + * integral E * exp(-sigma_a * t) from 0 to t = E * (1 - exp(-sigma_a * t))/sigma_a + * this goes to E * t as sigma_a goes to zero * - * todo: we should use an epsilon to avoid precision issues near zero sigma_t */ + * todo: we should use an epsilon to avoid precision issues near zero sigma_a */ if(closure_flag & SD_EMISSION) { - float3 emission = sample.emission; + float3 emission = coeff.emission; + + if(closure_flag & SD_ABSORPTION) { + float3 sigma_a = coeff.sigma_a; - if(closure_flag & SD_VOLUME) { - emission.x *= (sigma_t.x > 0.0f)? (1.0f - attenuation.x)/sigma_t.x: t; - emission.y *= (sigma_t.y > 0.0f)? (1.0f - attenuation.y)/sigma_t.y: t; - emission.z *= (sigma_t.z > 0.0f)? (1.0f - attenuation.z)/sigma_t.z: t; + emission.x *= (sigma_a.x > 0.0f)? (1.0f - attenuation.x)/sigma_a.x: t; + emission.y *= (sigma_a.y > 0.0f)? (1.0f - attenuation.y)/sigma_a.y: t; + emission.z *= (sigma_a.z > 0.0f)? (1.0f - attenuation.z)/sigma_a.z: t; } else emission *= t; @@ -152,8 +163,10 @@ ccl_device void kernel_volume_integrate(KernelGlobals *kg, PathState *state, Ray } /* modify throughput */ - if(closure_flag & SD_VOLUME) + if(closure_flag & SD_ABSORPTION) *throughput *= attenuation; + + return VOLUME_PATH_ATTENUATED; } /* Volume Stack */ |