Code refactor: better distinguish scatter and absorption for volume integration.

This commit is contained in:
Brecht Van Lommel
2013-12-29 15:49:16 +01:00
parent 5d3adafcbb
commit 30aa0c2482
4 changed files with 68 additions and 57 deletions

View File

@@ -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 */

View File

@@ -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

View File

@@ -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)
};

View File

@@ -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_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;
if(closure_flag & SD_ABSORPTION) {
float3 sigma_a = coeff.sigma_a;
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 */