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:
-rw-r--r--intern/cycles/kernel/closure/volume.h2
-rw-r--r--intern/cycles/kernel/kernel_path.h6
-rw-r--r--intern/cycles/kernel/kernel_shader.h7
-rw-r--r--intern/cycles/kernel/kernel_shadow.h6
-rw-r--r--intern/cycles/kernel/kernel_volume.h137
5 files changed, 103 insertions, 55 deletions
diff --git a/intern/cycles/kernel/closure/volume.h b/intern/cycles/kernel/closure/volume.h
index dae24fb03fd..4cf918f32b8 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;
+ return SD_BSDF|SD_BSDF_HAS_EVAL|SD_VOLUME;
}
ccl_device float3 volume_henyey_greenstein_eval_phase(const ShaderClosure *sc, const float3 I, float3 omega_in, float *pdf)
diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h
index b7039704c44..7aea673528a 100644
--- a/intern/cycles/kernel/kernel_path.h
+++ b/intern/cycles/kernel/kernel_path.h
@@ -96,7 +96,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ra
if(state.volume_stack[0].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);
+ kernel_volume_integrate(kg, &state, &segment_ray, L, &throughput);
}
#endif
@@ -518,7 +518,7 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample,
if(state.volume_stack[0].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);
+ kernel_volume_integrate(kg, &state, &segment_ray, &L, &throughput);
}
#endif
@@ -1022,7 +1022,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
if(state.volume_stack[0].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);
+ kernel_volume_integrate(kg, &state, &segment_ray, &L, &throughput);
}
#endif
diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h
index 685143b29c3..7b9a4ab12b1 100644
--- a/intern/cycles/kernel/kernel_shader.h
+++ b/intern/cycles/kernel/kernel_shader.h
@@ -412,15 +412,15 @@ ccl_device_inline void shader_setup_from_background(KernelGlobals *kg, ShaderDat
/* ShaderData setup from point inside volume */
-ccl_device_inline void shader_setup_from_volume(KernelGlobals *kg, ShaderData *sd, const Ray *ray, int volume_shader, int bounce)
+ccl_device_inline void shader_setup_from_volume(KernelGlobals *kg, ShaderData *sd, const Ray *ray, int bounce)
{
/* vectors */
sd->P = ray->P;
sd->N = -ray->D;
sd->Ng = -ray->D;
sd->I = -ray->D;
- sd->shader = volume_shader;
- sd->flag = kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*2);
+ sd->shader = SHADER_NO_ID;
+ sd->flag = 0;
#ifdef __OBJECT_MOTION__
sd->time = ray->time;
#endif
@@ -992,6 +992,7 @@ ccl_device void shader_eval_volume(KernelGlobals *kg, ShaderData *sd,
#else
sd->closure.type = NBUILTIN_CLOSURES;
#endif
+ sd->flag = 0;
for(int i = 0; stack[i].shader != SHADER_NO_ID; i++) {
/* setup shaderdata from stack. it's mostly setup already in
diff --git a/intern/cycles/kernel/kernel_shadow.h b/intern/cycles/kernel/kernel_shadow.h
index 80c9da8eab8..4bf063ee185 100644
--- a/intern/cycles/kernel/kernel_shadow.h
+++ b/intern/cycles/kernel/kernel_shadow.h
@@ -74,7 +74,7 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, PathState *state, Ray *
#ifdef __VOLUME__
/* attenuation for last line segment towards light */
if(ps.volume_stack[0].shader != SHADER_NO_ID)
- throughput *= kernel_volume_get_shadow_attenuation(kg, &ps, ray);
+ kernel_volume_get_shadow_attenuation(kg, &ps, ray, &throughput);
#endif
*shadow *= throughput;
@@ -89,7 +89,7 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, PathState *state, Ray *
if(ps.volume_stack[0].shader != SHADER_NO_ID) {
Ray segment_ray = *ray;
segment_ray.t = isect.t;
- throughput *= kernel_volume_get_shadow_attenuation(kg, &ps, &segment_ray);
+ kernel_volume_get_shadow_attenuation(kg, &ps, &segment_ray, &throughput);
}
#endif
@@ -120,7 +120,7 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, PathState *state, Ray *
#ifdef __VOLUME__
else if(!result && state->volume_stack[0].shader != SHADER_NO_ID) {
/* apply attenuation from current volume shader */
- *shadow *= kernel_volume_get_shadow_attenuation(kg, state, ray);
+ kernel_volume_get_shadow_attenuation(kg, state, ray, shadow);
}
#endif
#endif
diff --git a/intern/cycles/kernel/kernel_volume.h b/intern/cycles/kernel/kernel_volume.h
index fa201e1ff46..6b198ed9173 100644
--- a/intern/cycles/kernel/kernel_volume.h
+++ b/intern/cycles/kernel/kernel_volume.h
@@ -21,8 +21,21 @@ CCL_NAMESPACE_BEGIN
* extinction coefficient = absorption coefficient + scattering coefficient
* sigma_t = sigma_a + sigma_s */
-ccl_device float3 volume_shader_get_extinction_coefficient(ShaderData *sd)
+typedef struct VolumeShaderSample {
+ float3 sigma_a;
+ float3 sigma_s;
+ float3 emission;
+} VolumeShaderSample;
+
+/* 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)
{
+ sd->P = P;
+ shader_eval_volume(kg, sd, stack, 0.0f, path_flag, ctx);
+
+ if(!(sd->flag & SD_VOLUME))
+ return false;
+
float3 sigma_t = make_float3(0.0f, 0.0f, 0.0f);
for(int i = 0; i < sd->num_closure; i++) {
@@ -32,45 +45,35 @@ ccl_device float3 volume_shader_get_extinction_coefficient(ShaderData *sd)
sigma_t += sc->weight;
}
- return sigma_t;
+ *extinction = sigma_t;
+ return true;
}
-ccl_device float3 volume_shader_get_scattering_coefficient(ShaderData *sd)
+/* 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)
{
- float3 sigma_s = make_float3(0.0f, 0.0f, 0.0f);
-
- for(int i = 0; i < sd->num_closure; i++) {
- const ShaderClosure *sc = &sd->closure[i];
-
- if(CLOSURE_IS_VOLUME(sc->type) && sc->type != CLOSURE_VOLUME_ABSORPTION_ID)
- sigma_s += sc->weight;
- }
+ sd->P = P;
+ shader_eval_volume(kg, sd, stack, 0.0f, path_flag, ctx);
- return sigma_s;
-}
+ if(!(sd->flag & (SD_VOLUME|SD_EMISSION)))
+ return false;
-ccl_device float3 volume_shader_get_absorption_coefficient(ShaderData *sd)
-{
- float3 sigma_a = make_float3(0.0f, 0.0f, 0.0f);
+ sample->sigma_a = make_float3(0.0f, 0.0f, 0.0f);
+ sample->sigma_s = make_float3(0.0f, 0.0f, 0.0f);
+ sample->emission = make_float3(0.0f, 0.0f, 0.0f);
for(int i = 0; i < sd->num_closure; i++) {
const ShaderClosure *sc = &sd->closure[i];
if(sc->type == CLOSURE_VOLUME_ABSORPTION_ID)
- sigma_a += sc->weight;
+ sample->sigma_a += sc->weight;
+ else if(sc->type == CLOSURE_EMISSION_ID)
+ sample->emission += sc->weight;
+ else if(CLOSURE_IS_VOLUME(sc->type))
+ sample->sigma_s += sc->weight;
}
- return sigma_a;
-}
-
-/* evaluate shader to get extinction coefficient at P */
-ccl_device float3 volume_extinction_sample(KernelGlobals *kg, ShaderData *sd, VolumeStack *stack, int path_flag, ShaderContext ctx, float3 P)
-{
- sd->P = P;
-
- shader_eval_volume(kg, sd, stack, 0.0f, path_flag, ctx);
-
- return volume_shader_get_extinction_coefficient(sd);
+ return true;
}
ccl_device float3 volume_color_attenuation(float3 sigma, float t)
@@ -81,32 +84,76 @@ 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
- * assumption that there are surfaces blocking light between the endpoints */
-ccl_device float3 kernel_volume_get_shadow_attenuation(KernelGlobals *kg, PathState *state, Ray *segment_ray)
+ * 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)
{
ShaderData sd;
- shader_setup_from_volume(kg, &sd, segment_ray, state->volume_stack[0].shader, state->bounce);
-
- /* do we have a volume shader? */
- if(!(sd.flag & SD_HAS_VOLUME))
- return make_float3(1.0f, 1.0f, 1.0f);
+ shader_setup_from_volume(kg, &sd, segment_ray, state->bounce);
- /* single shader evaluation at the start */
ShaderContext ctx = SHADER_CONTEXT_SHADOW;
int path_flag = PATH_RAY_SHADOW;
- float3 attenuation;
+ float3 sigma_t;
+
+ /* 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))
+ return;
+
+ *throughput *= volume_color_attenuation(sigma_t, segment_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
+ * between the endpoints */
+ccl_device void kernel_volume_integrate(KernelGlobals *kg, PathState *state, Ray *segment_ray, PathRadiance *L, float3 *throughput)
+{
+ ShaderData sd;
+ shader_setup_from_volume(kg, &sd, segment_ray, state->bounce);
+
+ ShaderContext ctx = SHADER_CONTEXT_VOLUME;
+ int path_flag = PATH_RAY_SHADOW;
+ VolumeShaderSample sample;
+
+ /* 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;
+
+ int closure_flag = sd.flag;
+ float t = segment_ray->t;
- //if(sd.flag & SD_HOMOGENEOUS_VOLUME) {
- /* homogenous volume: assume shader evaluation at the starts gives
- * the extinction coefficient for the entire line segment */
+ /* compute attenuation from absorption (+ scattering for now) */
+ float3 sigma_t, attenuation;
- /* todo: could this use sigma_t_cache? */
- float3 sigma_t = volume_extinction_sample(kg, &sd, state->volume_stack, path_flag, ctx, segment_ray->P);
+ if(closure_flag & SD_VOLUME) {
+ sigma_t = sample.sigma_a + sample.sigma_s;
+ attenuation = volume_color_attenuation(sigma_t, t);
+ }
- attenuation = volume_color_attenuation(sigma_t, segment_ray->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
+ *
+ * todo: we should use an epsilon to avoid precision issues near zero sigma_t */
+ if(closure_flag & SD_EMISSION) {
+ float3 emission = sample.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;
+ }
+ else
+ emission *= t;
+
+ path_radiance_accum_emission(L, *throughput, emission, state->bounce);
+ }
- return attenuation;
+ /* modify throughput */
+ if(closure_flag & SD_VOLUME)
+ *throughput *= attenuation;
}
/* Volume Stack */