Cycles: De-duplicate transparent shadows attenuation

Fair amount of code was duplicated for CPU and GPU, now we are
using inlined function to avoid such duplication.
This commit is contained in:
Sergey Sharybin 2016-09-21 12:30:52 +02:00
parent 8cda364d6f
commit 98a1855803

@ -16,6 +16,55 @@
CCL_NAMESPACE_BEGIN CCL_NAMESPACE_BEGIN
/* Attenuate throughput accordingly to the given intersection event.
* Returns true if the throughput is zero and traversal can be aborted.
*/
ccl_device_inline bool shadow_handle_transparent_isect(KernelGlobals *kg,
ShaderData *shadow_sd,
PathState *state,
Intersection *isect,
Ray *ray,
float3 *throughput)
{
#ifdef __VOLUME__
/* Attenuation between last surface and next surface. */
if(state->volume_stack[0].shader != SHADER_NONE) {
Ray segment_ray = *ray;
segment_ray.t = isect->t;
kernel_volume_shadow(kg, shadow_sd, state, &segment_ray, throughput);
}
#endif
/* Setup shader data at surface. */
shader_setup_from_ray(kg, shadow_sd, isect, ray);
/* Attenuation from transparent surface. */
if(!(shadow_sd->flag & SD_HAS_ONLY_VOLUME)) {
path_state_modify_bounce(state, true);
shader_eval_surface(kg,
shadow_sd,
NULL,
state,
0.0f,
PATH_RAY_SHADOW,
SHADER_CONTEXT_SHADOW);
path_state_modify_bounce(state, false);
*throughput *= shader_bsdf_transparency(kg, shadow_sd);
}
/* Stop if all light is blocked. */
if(is_zero(*throughput)) {
return true;
}
#ifdef __VOLUME__
/* Exit/enter volume. */
kernel_volume_stack_enter_exit(kg, shadow_sd, state->volume_stack);
#endif
return false;
}
#ifdef __SHADOW_RECORD_ALL__ #ifdef __SHADOW_RECORD_ALL__
/* Shadow function to compute how much light is blocked, CPU variation. /* Shadow function to compute how much light is blocked, CPU variation.
@ -91,59 +140,36 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, ShaderData *shadow_sd,
qsort(hits, num_hits, sizeof(Intersection), intersections_compare); qsort(hits, num_hits, sizeof(Intersection), intersections_compare);
for(int hit = 0; hit < num_hits; hit++, isect++) { for(int hit = 0; hit < num_hits; hit++, isect++) {
/* adjust intersection distance for moving ray forward */ /* Adjust intersection distance for moving ray forward. */
float new_t = isect->t; float new_t = isect->t;
isect->t -= last_t; isect->t -= last_t;
/* Skip hit if we did not move forward, step by step raytracing
/* skip hit if we did not move forward, step by step raytracing * would have skipped it as well then.
* would have skipped it as well then */ */
if(last_t == new_t) if(last_t == new_t) {
continue; continue;
}
last_t = new_t; last_t = new_t;
/* Attenuate the throughput. */
#ifdef __VOLUME__ if(shadow_handle_transparent_isect(kg,
/* attenuation between last surface and next surface */ shadow_sd,
if(ps.volume_stack[0].shader != SHADER_NONE) { &ps,
Ray segment_ray = *ray; isect,
segment_ray.t = isect->t; ray,
kernel_volume_shadow(kg, shadow_sd, &ps, &segment_ray, &throughput); &throughput))
} {
#endif
/* setup shader data at surface */
shader_setup_from_ray(kg, shadow_sd, isect, ray);
/* attenuation from transparent surface */
if(!(shadow_sd->flag & SD_HAS_ONLY_VOLUME)) {
path_state_modify_bounce(state, true);
shader_eval_surface(kg, shadow_sd, NULL, state, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW);
path_state_modify_bounce(state, false);
throughput *= shader_bsdf_transparency(kg, shadow_sd);
}
/* stop if all light is blocked */
if(is_zero(throughput)) {
return true; return true;
} }
/* Move ray forward. */
/* move ray forward */
ray->P = shadow_sd->P; ray->P = shadow_sd->P;
if(ray->t != FLT_MAX) { if(ray->t != FLT_MAX) {
ray->D = normalize_len(Pend - ray->P, &ray->t); ray->D = normalize_len(Pend - ray->P, &ray->t);
} }
#ifdef __VOLUME__
/* exit/enter volume */
kernel_volume_stack_enter_exit(kg, shadow_sd, ps.volume_stack);
#endif
bounce++; bounce++;
} }
#ifdef __VOLUME__ #ifdef __VOLUME__
/* attenuation for last line segment towards light */ /* Attenuation for last line segment towards light. */
if(ps.volume_stack[0].shader != SHADER_NONE) if(ps.volume_stack[0].shader != SHADER_NONE)
kernel_volume_shadow(kg, shadow_sd, &ps, ray, &throughput); kernel_volume_shadow(kg, shadow_sd, &ps, ray, &throughput);
#endif #endif
@ -213,78 +239,53 @@ ccl_device_noinline bool shadow_blocked(KernelGlobals *kg,
float3 throughput = make_float3(1.0f, 1.0f, 1.0f); float3 throughput = make_float3(1.0f, 1.0f, 1.0f);
float3 Pend = ray->P + ray->D*ray->t; float3 Pend = ray->P + ray->D*ray->t;
int bounce = state->transparent_bounce; int bounce = state->transparent_bounce;
#ifdef __VOLUME__ # ifdef __VOLUME__
PathState ps = *state; PathState ps = *state;
#endif # endif
for(;;) { for(;;) {
if(bounce >= kernel_data.integrator.transparent_max_bounce) if(bounce >= kernel_data.integrator.transparent_max_bounce)
return true; return true;
if(!scene_intersect(kg, *ray, PATH_RAY_SHADOW_TRANSPARENT, isect, NULL, 0.0f, 0.0f)) if(!scene_intersect(kg, *ray, PATH_RAY_SHADOW_TRANSPARENT, isect, NULL, 0.0f, 0.0f))
{ {
#ifdef __VOLUME__ # ifdef __VOLUME__
/* attenuation for last line segment towards light */ /* Attenuation for last line segment towards light. */
if(ps.volume_stack[0].shader != SHADER_NONE) if(ps.volume_stack[0].shader != SHADER_NONE)
kernel_volume_shadow(kg, shadow_sd, &ps, ray, &throughput); kernel_volume_shadow(kg, shadow_sd, &ps, ray, &throughput);
#endif # endif
*shadow *= throughput; *shadow *= throughput;
return false; return false;
} }
if(!shader_transparent_shadow(kg, isect)) { if(!shader_transparent_shadow(kg, isect)) {
return true; return true;
} }
/* Attenuate the throughput. */
#ifdef __VOLUME__ if(shadow_handle_transparent_isect(kg,
/* attenuation between last surface and next surface */ shadow_sd,
if(ps.volume_stack[0].shader != SHADER_NONE) { &ps,
Ray segment_ray = *ray; isect,
segment_ray.t = isect->t; ray,
kernel_volume_shadow(kg, shadow_sd, &ps, &segment_ray, &throughput); &throughput))
} {
#endif
/* setup shader data at surface */
shader_setup_from_ray(kg, shadow_sd, isect, ray);
/* attenuation from transparent surface */
if(!(ccl_fetch(shadow_sd, flag) & SD_HAS_ONLY_VOLUME)) {
path_state_modify_bounce(state, true);
shader_eval_surface(kg, shadow_sd, NULL, state, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW);
path_state_modify_bounce(state, false);
throughput *= shader_bsdf_transparency(kg, shadow_sd);
}
/* stop if all light is blocked */
if(is_zero(throughput)) {
return true; return true;
} }
/* Move ray forward. */
/* move ray forward */
ray->P = ray_offset(ccl_fetch(shadow_sd, P), -ccl_fetch(shadow_sd, Ng)); ray->P = ray_offset(ccl_fetch(shadow_sd, P), -ccl_fetch(shadow_sd, Ng));
if(ray->t != FLT_MAX) { if(ray->t != FLT_MAX) {
ray->D = normalize_len(Pend - ray->P, &ray->t); ray->D = normalize_len(Pend - ray->P, &ray->t);
} }
#ifdef __VOLUME__
/* exit/enter volume */
kernel_volume_stack_enter_exit(kg, shadow_sd, ps.volume_stack);
#endif
bounce++; bounce++;
} }
} }
} }
#ifdef __VOLUME__ # ifdef __VOLUME__
else if(!blocked && state->volume_stack[0].shader != SHADER_NONE) { else if(!blocked && state->volume_stack[0].shader != SHADER_NONE) {
/* apply attenuation from current volume shader */ /* apply attenuation from current volume shader */
kernel_volume_shadow(kg, shadow_sd, state, ray, shadow); kernel_volume_shadow(kg, shadow_sd, state, ray, shadow);
} }
#endif # endif
#endif #endif
return blocked; return blocked;