2013-12-28 01:56:53 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2011-2013 Blender Foundation
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
2014-12-25 01:50:24 +00:00
|
|
|
* limitations under the License.
|
2013-12-28 01:56:53 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
CCL_NAMESPACE_BEGIN
|
|
|
|
|
2016-09-21 10:30:52 +00:00
|
|
|
/* Attenuate throughput accordingly to the given intersection event.
|
|
|
|
* Returns true if the throughput is zero and traversal can be aborted.
|
|
|
|
*/
|
2017-01-30 11:08:20 +00:00
|
|
|
ccl_device_forceinline bool shadow_handle_transparent_isect(
|
|
|
|
KernelGlobals *kg,
|
|
|
|
ShaderData *shadow_sd,
|
2017-01-30 11:33:58 +00:00
|
|
|
ccl_addr_space PathState *state,
|
2017-01-30 13:40:37 +00:00
|
|
|
# ifdef __VOLUME__
|
2017-03-08 14:42:26 +00:00
|
|
|
ccl_addr_space struct PathState *volume_state,
|
2017-01-30 13:40:37 +00:00
|
|
|
# endif
|
2017-01-30 11:08:20 +00:00
|
|
|
Intersection *isect,
|
|
|
|
Ray *ray,
|
|
|
|
float3 *throughput)
|
2016-09-21 10:30:52 +00:00
|
|
|
{
|
|
|
|
#ifdef __VOLUME__
|
|
|
|
/* Attenuation between last surface and next surface. */
|
2017-01-30 13:40:37 +00:00
|
|
|
if(volume_state->volume_stack[0].shader != SHADER_NONE) {
|
2016-09-21 10:30:52 +00:00
|
|
|
Ray segment_ray = *ray;
|
|
|
|
segment_ray.t = isect->t;
|
2017-01-30 13:40:37 +00:00
|
|
|
kernel_volume_shadow(kg,
|
|
|
|
shadow_sd,
|
|
|
|
volume_state,
|
|
|
|
&segment_ray,
|
|
|
|
throughput);
|
2016-09-21 10:30:52 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
/* Setup shader data at surface. */
|
|
|
|
shader_setup_from_ray(kg, shadow_sd, isect, ray);
|
|
|
|
/* Attenuation from transparent surface. */
|
2017-02-16 11:24:13 +00:00
|
|
|
if(!(shadow_sd->flag & SD_HAS_ONLY_VOLUME)) {
|
2016-09-21 10:30:52 +00:00
|
|
|
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. */
|
2017-01-30 13:40:37 +00:00
|
|
|
kernel_volume_stack_enter_exit(kg, shadow_sd, volume_state->volume_stack);
|
2016-09-21 10:30:52 +00:00
|
|
|
#endif
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-01-30 11:08:20 +00:00
|
|
|
/* Special version which only handles opaque shadows. */
|
|
|
|
ccl_device bool shadow_blocked_opaque(KernelGlobals *kg,
|
|
|
|
ShaderData *shadow_sd,
|
2017-01-30 11:33:58 +00:00
|
|
|
ccl_addr_space PathState *state,
|
2017-01-30 11:08:20 +00:00
|
|
|
Ray *ray,
|
|
|
|
Intersection *isect,
|
|
|
|
float3 *shadow)
|
|
|
|
{
|
|
|
|
const bool blocked = scene_intersect(kg,
|
|
|
|
*ray,
|
|
|
|
PATH_RAY_SHADOW_OPAQUE,
|
|
|
|
isect,
|
|
|
|
NULL,
|
|
|
|
0.0f, 0.0f);
|
|
|
|
#ifdef __VOLUME__
|
|
|
|
if(!blocked && state->volume_stack[0].shader != SHADER_NONE) {
|
|
|
|
/* Apply attenuation from current volume shader. */
|
|
|
|
kernel_volume_shadow(kg, shadow_sd, state, ray, shadow);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return blocked;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef __TRANSPARENT_SHADOWS__
|
|
|
|
# ifdef __SHADOW_RECORD_ALL__
|
2016-09-21 15:34:15 +00:00
|
|
|
/* Shadow function to compute how much light is blocked,
|
2014-04-19 15:02:30 +00:00
|
|
|
*
|
|
|
|
* We trace a single ray. If it hits any opaque surface, or more than a given
|
|
|
|
* number of transparent surfaces is hit, then we consider the geometry to be
|
|
|
|
* entirely blocked. If not, all transparent surfaces will be recorded and we
|
|
|
|
* will shade them one by one to determine how much light is blocked. This all
|
|
|
|
* happens in one scene intersection function.
|
|
|
|
*
|
|
|
|
* Recording all hits works well in some cases but may be slower in others. If
|
|
|
|
* we have many semi-transparent hairs, one intersection may be faster because
|
|
|
|
* you'd be reinteresecting the same hairs a lot with each step otherwise. If
|
|
|
|
* however there is mostly binary transparency then we may be recording many
|
|
|
|
* unnecessary intersections when one of the first surfaces blocks all light.
|
|
|
|
*
|
|
|
|
* From tests in real scenes it seems the performance loss is either minimal,
|
|
|
|
* or there is a performance increase anyway due to avoiding the need to send
|
|
|
|
* two rays with transparent shadows.
|
|
|
|
*
|
2016-09-21 15:34:15 +00:00
|
|
|
* On CPU it'll handle all transparent bounces (by allocating storage for
|
|
|
|
* intersections when they don't fit into the stack storage).
|
|
|
|
*
|
|
|
|
* On GPU it'll only handle SHADOW_STACK_MAX_HITS-1 intersections, so this
|
|
|
|
* is something to be kept an eye on.
|
|
|
|
*/
|
2014-04-19 15:02:30 +00:00
|
|
|
|
2017-01-30 11:08:20 +00:00
|
|
|
# define SHADOW_STACK_MAX_HITS 64
|
2014-04-19 15:02:30 +00:00
|
|
|
|
2017-01-30 11:08:20 +00:00
|
|
|
/* Actual logic with traversal loop implementation which is free from device
|
|
|
|
* specific tweaks.
|
|
|
|
*
|
|
|
|
* Note that hits array should be as big as max_hits+1.
|
|
|
|
*/
|
|
|
|
ccl_device bool shadow_blocked_transparent_all_loop(KernelGlobals *kg,
|
|
|
|
ShaderData *shadow_sd,
|
2017-01-30 11:33:58 +00:00
|
|
|
ccl_addr_space PathState *state,
|
2017-02-09 13:19:01 +00:00
|
|
|
const int skip_object,
|
2017-01-30 11:08:20 +00:00
|
|
|
Ray *ray,
|
|
|
|
Intersection *hits,
|
|
|
|
uint max_hits,
|
|
|
|
float3 *shadow)
|
2013-12-28 01:56:53 +00:00
|
|
|
{
|
2017-01-30 11:08:20 +00:00
|
|
|
/* Intersect to find an opaque surface, or record all transparent
|
|
|
|
* surface hits.
|
|
|
|
*/
|
|
|
|
uint num_hits;
|
|
|
|
const bool blocked = scene_intersect_shadow_all(kg,
|
|
|
|
ray,
|
|
|
|
hits,
|
2017-02-09 13:19:01 +00:00
|
|
|
skip_object,
|
2017-01-30 11:08:20 +00:00
|
|
|
max_hits,
|
|
|
|
&num_hits);
|
|
|
|
/* If no opaque surface found but we did find transparent hits,
|
|
|
|
* shade them.
|
|
|
|
*/
|
|
|
|
if(!blocked && num_hits > 0) {
|
|
|
|
float3 throughput = make_float3(1.0f, 1.0f, 1.0f);
|
|
|
|
float3 Pend = ray->P + ray->D*ray->t;
|
|
|
|
float last_t = 0.0f;
|
|
|
|
int bounce = state->transparent_bounce;
|
|
|
|
Intersection *isect = hits;
|
|
|
|
# ifdef __VOLUME__
|
2017-03-08 15:26:39 +00:00
|
|
|
# ifdef __SPLIT_KERNEL__
|
|
|
|
ccl_addr_space PathState *ps = &kernel_split_state.state_shadow[ccl_global_id(1) * ccl_global_size(0) + ccl_global_id(0)];
|
|
|
|
# else
|
|
|
|
PathState ps_object;
|
|
|
|
PathState *ps = &ps_object;
|
|
|
|
# endif
|
|
|
|
*ps = *state;
|
2017-01-30 11:08:20 +00:00
|
|
|
# endif
|
|
|
|
sort_intersections(hits, num_hits);
|
|
|
|
for(int hit = 0; hit < num_hits; hit++, isect++) {
|
|
|
|
/* Adjust intersection distance for moving ray forward. */
|
|
|
|
float new_t = isect->t;
|
|
|
|
isect->t -= last_t;
|
|
|
|
/* Skip hit if we did not move forward, step by step raytracing
|
|
|
|
* would have skipped it as well then.
|
|
|
|
*/
|
|
|
|
if(last_t == new_t) {
|
|
|
|
continue;
|
2016-05-17 10:30:46 +00:00
|
|
|
}
|
2017-01-30 11:08:20 +00:00
|
|
|
last_t = new_t;
|
|
|
|
/* Attenuate the throughput. */
|
|
|
|
if(shadow_handle_transparent_isect(kg,
|
|
|
|
shadow_sd,
|
2017-01-30 11:33:58 +00:00
|
|
|
state,
|
2017-01-30 13:40:37 +00:00
|
|
|
#ifdef __VOLUME__
|
2017-03-08 15:26:39 +00:00
|
|
|
ps,
|
2017-01-30 13:40:37 +00:00
|
|
|
#endif
|
2017-01-30 11:08:20 +00:00
|
|
|
isect,
|
|
|
|
ray,
|
|
|
|
&throughput))
|
|
|
|
{
|
|
|
|
return true;
|
2014-04-19 15:02:30 +00:00
|
|
|
}
|
2017-01-30 11:08:20 +00:00
|
|
|
/* Move ray forward. */
|
2017-02-16 11:24:13 +00:00
|
|
|
ray->P = shadow_sd->P;
|
2017-01-30 11:08:20 +00:00
|
|
|
if(ray->t != FLT_MAX) {
|
|
|
|
ray->D = normalize_len(Pend - ray->P, &ray->t);
|
2016-09-21 10:39:14 +00:00
|
|
|
}
|
2017-01-30 11:08:20 +00:00
|
|
|
bounce++;
|
2014-04-19 15:02:30 +00:00
|
|
|
}
|
2017-01-30 11:08:20 +00:00
|
|
|
# ifdef __VOLUME__
|
|
|
|
/* Attenuation for last line segment towards light. */
|
2017-03-08 15:26:39 +00:00
|
|
|
if(ps->volume_stack[0].shader != SHADER_NONE) {
|
|
|
|
kernel_volume_shadow(kg, shadow_sd, ps, ray, &throughput);
|
2017-01-30 11:08:20 +00:00
|
|
|
}
|
|
|
|
# endif
|
|
|
|
*shadow = throughput;
|
|
|
|
return is_zero(throughput);
|
2014-04-19 15:02:30 +00:00
|
|
|
}
|
2017-01-30 11:08:20 +00:00
|
|
|
# ifdef __VOLUME__
|
2014-04-19 15:02:30 +00:00
|
|
|
if(!blocked && state->volume_stack[0].shader != SHADER_NONE) {
|
2016-09-21 10:53:38 +00:00
|
|
|
/* Apply attenuation from current volume shader/ */
|
2016-05-22 20:35:47 +00:00
|
|
|
kernel_volume_shadow(kg, shadow_sd, state, ray, shadow);
|
2014-04-19 15:02:30 +00:00
|
|
|
}
|
2017-01-30 11:08:20 +00:00
|
|
|
# endif
|
2014-04-19 15:02:30 +00:00
|
|
|
return blocked;
|
|
|
|
}
|
|
|
|
|
2017-01-30 11:08:20 +00:00
|
|
|
/* Here we do all device specific trickery before invoking actual traversal
|
|
|
|
* loop to help readability of the actual logic.
|
|
|
|
*/
|
|
|
|
ccl_device bool shadow_blocked_transparent_all(KernelGlobals *kg,
|
|
|
|
ShaderData *shadow_sd,
|
2017-01-30 11:33:58 +00:00
|
|
|
ccl_addr_space PathState *state,
|
2017-02-09 13:19:01 +00:00
|
|
|
const int skip_object,
|
2017-01-30 11:08:20 +00:00
|
|
|
Ray *ray,
|
|
|
|
uint max_hits,
|
|
|
|
float3 *shadow)
|
|
|
|
{
|
2017-03-08 15:26:39 +00:00
|
|
|
# ifdef __SPLIT_KERNEL__
|
|
|
|
Intersection hits_[SHADOW_STACK_MAX_HITS];
|
|
|
|
Intersection *hits = &hits_[0];
|
|
|
|
# elif defined(__KERNEL_CUDA__)
|
2017-01-30 11:08:20 +00:00
|
|
|
Intersection *hits = kg->hits_stack;
|
|
|
|
# else
|
|
|
|
Intersection hits_stack[SHADOW_STACK_MAX_HITS];
|
|
|
|
Intersection *hits = hits_stack;
|
|
|
|
# endif
|
|
|
|
# ifndef __KERNEL_GPU__
|
|
|
|
/* Prefer to use stack but use dynamic allocation if too deep max hits
|
|
|
|
* we need max_hits + 1 storage space due to the logic in
|
|
|
|
* scene_intersect_shadow_all which will first store and then check if
|
|
|
|
* the limit is exceeded.
|
|
|
|
*
|
|
|
|
* Ignore this on GPU because of slow/unavailable malloc().
|
|
|
|
*/
|
|
|
|
if(max_hits + 1 > SHADOW_STACK_MAX_HITS) {
|
|
|
|
if(kg->transparent_shadow_intersections == NULL) {
|
|
|
|
const int transparent_max_bounce = kernel_data.integrator.transparent_max_bounce;
|
|
|
|
kg->transparent_shadow_intersections =
|
|
|
|
(Intersection*)malloc(sizeof(Intersection)*(transparent_max_bounce + 1));
|
|
|
|
}
|
|
|
|
hits = kg->transparent_shadow_intersections;
|
|
|
|
}
|
|
|
|
# endif /* __KERNEL_GPU__ */
|
|
|
|
/* Invoke actual traversal. */
|
|
|
|
return shadow_blocked_transparent_all_loop(kg,
|
|
|
|
shadow_sd,
|
|
|
|
state,
|
2017-02-09 13:19:01 +00:00
|
|
|
skip_object,
|
2017-01-30 11:08:20 +00:00
|
|
|
ray,
|
|
|
|
hits,
|
|
|
|
max_hits,
|
|
|
|
shadow);
|
|
|
|
}
|
|
|
|
# endif /* __SHADOW_RECORD_ALL__ */
|
|
|
|
|
2017-02-22 13:10:02 +00:00
|
|
|
# if defined(__KERNEL_GPU__) || !defined(__SHADOW_RECORD_ALL__)
|
2016-09-21 15:34:15 +00:00
|
|
|
/* Shadow function to compute how much light is blocked,
|
2014-04-19 15:02:30 +00:00
|
|
|
*
|
|
|
|
* Here we raytrace from one transparent surface to the next step by step.
|
|
|
|
* To minimize overhead in cases where we don't need transparent shadows, we
|
|
|
|
* first trace a regular shadow ray. We check if the hit primitive was
|
|
|
|
* potentially transparent, and only in that case start marching. this gives
|
2016-09-21 15:34:15 +00:00
|
|
|
* one extra ray cast for the cases were we do want transparency.
|
|
|
|
*/
|
2017-01-30 13:11:58 +00:00
|
|
|
|
|
|
|
/* This function is only implementing device-independent traversal logic
|
|
|
|
* which requires some precalculation done.
|
|
|
|
*/
|
|
|
|
ccl_device bool shadow_blocked_transparent_stepped_loop(
|
2017-01-30 11:08:20 +00:00
|
|
|
KernelGlobals *kg,
|
|
|
|
ShaderData *shadow_sd,
|
2017-01-30 11:33:58 +00:00
|
|
|
ccl_addr_space PathState *state,
|
2017-02-09 13:19:01 +00:00
|
|
|
const int skip_object,
|
2017-01-30 11:08:20 +00:00
|
|
|
Ray *ray,
|
|
|
|
Intersection *isect,
|
2017-01-30 13:11:58 +00:00
|
|
|
const bool blocked,
|
|
|
|
const bool is_transparent_isect,
|
2017-01-30 11:08:20 +00:00
|
|
|
float3 *shadow)
|
2014-04-19 15:02:30 +00:00
|
|
|
{
|
2017-02-09 13:19:01 +00:00
|
|
|
if((blocked && is_transparent_isect) || skip_object != OBJECT_NONE) {
|
2017-01-30 11:08:20 +00:00
|
|
|
float3 throughput = make_float3(1.0f, 1.0f, 1.0f);
|
|
|
|
float3 Pend = ray->P + ray->D*ray->t;
|
|
|
|
int bounce = state->transparent_bounce;
|
|
|
|
# ifdef __VOLUME__
|
2017-03-08 14:42:26 +00:00
|
|
|
# ifdef __SPLIT_KERNEL__
|
|
|
|
ccl_addr_space PathState *ps = &kernel_split_state.state_shadow[ccl_global_id(1) * ccl_global_size(0) + ccl_global_id(0)];
|
|
|
|
# else
|
|
|
|
PathState ps_object;
|
|
|
|
PathState *ps = &ps_object;
|
|
|
|
# endif
|
|
|
|
*ps = *state;
|
2017-01-30 11:08:20 +00:00
|
|
|
# endif
|
|
|
|
for(;;) {
|
|
|
|
if(bounce >= kernel_data.integrator.transparent_max_bounce) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if(!scene_intersect(kg,
|
|
|
|
*ray,
|
|
|
|
PATH_RAY_SHADOW_TRANSPARENT,
|
|
|
|
isect,
|
|
|
|
NULL,
|
|
|
|
0.0f, 0.0f))
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2017-02-09 13:19:01 +00:00
|
|
|
#ifdef __SHADOW_TRICKS__
|
|
|
|
if(skip_object != OBJECT_NONE) {
|
|
|
|
const int isect_object = (isect->object == PRIM_NONE)
|
|
|
|
? kernel_tex_fetch(__prim_object, isect->prim)
|
|
|
|
: isect->object;
|
|
|
|
if(isect_object == skip_object) {
|
|
|
|
shader_setup_from_ray(kg, shadow_sd, isect, ray);
|
|
|
|
/* Move ray forward. */
|
|
|
|
ray->P = ray_offset(shadow_sd->P, -shadow_sd->Ng);
|
|
|
|
if(ray->t != FLT_MAX) {
|
|
|
|
ray->D = normalize_len(Pend - ray->P, &ray->t);
|
|
|
|
}
|
|
|
|
bounce++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2017-01-30 11:08:20 +00:00
|
|
|
if(!shader_transparent_shadow(kg, isect)) {
|
|
|
|
return true;
|
2013-12-28 01:56:53 +00:00
|
|
|
}
|
2017-01-30 11:08:20 +00:00
|
|
|
/* Attenuate the throughput. */
|
|
|
|
if(shadow_handle_transparent_isect(kg,
|
|
|
|
shadow_sd,
|
2017-01-30 11:33:58 +00:00
|
|
|
state,
|
2017-01-30 13:40:37 +00:00
|
|
|
#ifdef __VOLUME__
|
2017-03-08 14:42:26 +00:00
|
|
|
ps,
|
2017-01-30 13:40:37 +00:00
|
|
|
#endif
|
2017-01-30 11:08:20 +00:00
|
|
|
isect,
|
|
|
|
ray,
|
|
|
|
&throughput))
|
|
|
|
{
|
|
|
|
return true;
|
2016-09-21 10:39:14 +00:00
|
|
|
}
|
2017-01-30 11:08:20 +00:00
|
|
|
/* Move ray forward. */
|
2017-02-16 11:24:13 +00:00
|
|
|
ray->P = ray_offset(shadow_sd->P, -shadow_sd->Ng);
|
2017-01-30 11:08:20 +00:00
|
|
|
if(ray->t != FLT_MAX) {
|
|
|
|
ray->D = normalize_len(Pend - ray->P, &ray->t);
|
|
|
|
}
|
|
|
|
bounce++;
|
|
|
|
}
|
|
|
|
# ifdef __VOLUME__
|
|
|
|
/* Attenuation for last line segment towards light. */
|
2017-03-08 14:42:26 +00:00
|
|
|
if(ps->volume_stack[0].shader != SHADER_NONE) {
|
|
|
|
kernel_volume_shadow(kg, shadow_sd, ps, ray, &throughput);
|
2013-12-28 01:56:53 +00:00
|
|
|
}
|
2017-01-30 11:08:20 +00:00
|
|
|
# endif
|
|
|
|
*shadow *= throughput;
|
|
|
|
return is_zero(throughput);
|
2013-12-28 01:56:53 +00:00
|
|
|
}
|
2017-01-30 11:08:20 +00:00
|
|
|
# ifdef __VOLUME__
|
|
|
|
if(!blocked && state->volume_stack[0].shader != SHADER_NONE) {
|
2016-09-21 10:39:14 +00:00
|
|
|
/* Apply attenuation from current volume shader. */
|
2016-05-22 20:35:47 +00:00
|
|
|
kernel_volume_shadow(kg, shadow_sd, state, ray, shadow);
|
2013-12-28 15:56:19 +00:00
|
|
|
}
|
2017-01-30 11:08:20 +00:00
|
|
|
# endif
|
2014-04-19 15:02:30 +00:00
|
|
|
return blocked;
|
2013-12-28 01:56:53 +00:00
|
|
|
}
|
2017-01-30 13:11:58 +00:00
|
|
|
|
|
|
|
ccl_device bool shadow_blocked_transparent_stepped(
|
|
|
|
KernelGlobals *kg,
|
|
|
|
ShaderData *shadow_sd,
|
|
|
|
ccl_addr_space PathState *state,
|
2017-02-09 13:19:01 +00:00
|
|
|
const int skip_object,
|
2017-01-30 13:11:58 +00:00
|
|
|
Ray *ray,
|
|
|
|
Intersection *isect,
|
|
|
|
float3 *shadow)
|
|
|
|
{
|
2017-02-09 13:19:01 +00:00
|
|
|
bool blocked, is_transparent_isect;
|
2017-04-18 09:39:21 +00:00
|
|
|
if(skip_object == OBJECT_NONE) {
|
2017-02-09 13:19:01 +00:00
|
|
|
blocked = scene_intersect(kg,
|
|
|
|
*ray,
|
|
|
|
PATH_RAY_SHADOW_OPAQUE,
|
|
|
|
isect,
|
|
|
|
NULL,
|
|
|
|
0.0f, 0.0f);
|
|
|
|
is_transparent_isect = blocked
|
|
|
|
? shader_transparent_shadow(kg, isect)
|
|
|
|
: false;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
blocked = false;
|
|
|
|
is_transparent_isect = false;
|
|
|
|
}
|
2017-01-30 13:11:58 +00:00
|
|
|
return shadow_blocked_transparent_stepped_loop(kg,
|
|
|
|
shadow_sd,
|
|
|
|
state,
|
2017-02-09 13:19:01 +00:00
|
|
|
skip_object,
|
2017-01-30 13:11:58 +00:00
|
|
|
ray,
|
|
|
|
isect,
|
|
|
|
blocked,
|
|
|
|
is_transparent_isect,
|
|
|
|
shadow);
|
|
|
|
}
|
|
|
|
|
2017-02-22 13:10:02 +00:00
|
|
|
# endif /* __KERNEL_GPU__ || !__SHADOW_RECORD_ALL__ */
|
2017-01-30 11:08:20 +00:00
|
|
|
#endif /* __TRANSPARENT_SHADOWS__ */
|
2013-12-28 01:56:53 +00:00
|
|
|
|
2016-09-21 15:34:15 +00:00
|
|
|
ccl_device_inline bool shadow_blocked(KernelGlobals *kg,
|
|
|
|
ShaderData *shadow_sd,
|
2017-01-30 11:33:58 +00:00
|
|
|
ccl_addr_space PathState *state,
|
2017-03-08 14:42:26 +00:00
|
|
|
Ray *ray_input,
|
2016-09-21 15:34:15 +00:00
|
|
|
float3 *shadow)
|
|
|
|
{
|
2017-01-30 11:08:20 +00:00
|
|
|
Ray *ray = ray_input;
|
2017-03-08 14:42:26 +00:00
|
|
|
Intersection isect;
|
2017-01-30 11:08:20 +00:00
|
|
|
/* Some common early checks. */
|
|
|
|
*shadow = make_float3(1.0f, 1.0f, 1.0f);
|
|
|
|
if(ray->t == 0.0f) {
|
|
|
|
return false;
|
|
|
|
}
|
2017-02-09 13:19:01 +00:00
|
|
|
#ifdef __SHADOW_TRICKS__
|
2017-03-31 06:38:07 +00:00
|
|
|
const int skip_object = state->catcher_object;
|
2017-02-09 13:19:01 +00:00
|
|
|
#else
|
2017-03-31 06:38:07 +00:00
|
|
|
const int skip_object = OBJECT_NONE;
|
2017-02-09 13:19:01 +00:00
|
|
|
#endif
|
2017-01-30 11:08:20 +00:00
|
|
|
/* Do actual shadow shading. */
|
2017-01-30 13:11:58 +00:00
|
|
|
/* First of all, we check if integrator requires transparent shadows.
|
|
|
|
* if not, we use simplest and fastest ever way to calculate occlusion.
|
2017-02-09 13:19:01 +00:00
|
|
|
*
|
|
|
|
* NOTE: We can't do quick opaque test here if we are on shadow-catcher
|
|
|
|
* path because we don't want catcher object to be casting shadow here.
|
2017-01-30 13:11:58 +00:00
|
|
|
*/
|
2017-01-30 11:08:20 +00:00
|
|
|
#ifdef __TRANSPARENT_SHADOWS__
|
2017-02-09 13:19:01 +00:00
|
|
|
if(!kernel_data.integrator.transparent_shadows &&
|
|
|
|
skip_object == OBJECT_NONE)
|
2017-01-30 11:08:20 +00:00
|
|
|
#endif
|
|
|
|
{
|
|
|
|
return shadow_blocked_opaque(kg,
|
|
|
|
shadow_sd,
|
|
|
|
state,
|
|
|
|
ray,
|
2017-03-08 14:42:26 +00:00
|
|
|
&isect,
|
2017-01-30 11:08:20 +00:00
|
|
|
shadow);
|
|
|
|
}
|
|
|
|
#ifdef __TRANSPARENT_SHADOWS__
|
|
|
|
# ifdef __SHADOW_RECORD_ALL__
|
2017-01-30 13:11:58 +00:00
|
|
|
/* For the transparent shadows we try to use record-all logic on the
|
|
|
|
* devices which supports this.
|
|
|
|
*/
|
2016-09-21 15:34:15 +00:00
|
|
|
const int transparent_max_bounce = kernel_data.integrator.transparent_max_bounce;
|
2017-01-30 11:08:20 +00:00
|
|
|
/* Check transparent bounces here, for volume scatter which can do
|
|
|
|
* lighting before surface path termination is checked.
|
|
|
|
*/
|
|
|
|
if(state->transparent_bounce >= transparent_max_bounce) {
|
|
|
|
return true;
|
|
|
|
}
|
2016-09-21 15:34:15 +00:00
|
|
|
const uint max_hits = transparent_max_bounce - state->transparent_bounce - 1;
|
2017-01-30 11:08:20 +00:00
|
|
|
# ifdef __KERNEL_GPU__
|
2017-01-30 13:11:58 +00:00
|
|
|
/* On GPU we do trickey with tracing opaque ray first, this avoids speed
|
|
|
|
* regressions in some files.
|
|
|
|
*
|
|
|
|
* TODO(sergey): Check why using record-all behavior causes slowdown in such
|
|
|
|
* cases. Could that be caused by a higher spill pressure?
|
|
|
|
*/
|
|
|
|
const bool blocked = scene_intersect(kg,
|
|
|
|
*ray,
|
|
|
|
PATH_RAY_SHADOW_OPAQUE,
|
2017-03-08 14:42:26 +00:00
|
|
|
&isect,
|
2017-01-30 13:11:58 +00:00
|
|
|
NULL,
|
|
|
|
0.0f, 0.0f);
|
|
|
|
const bool is_transparent_isect = blocked
|
2017-03-08 14:42:26 +00:00
|
|
|
? shader_transparent_shadow(kg, &isect)
|
2017-01-30 13:11:58 +00:00
|
|
|
: false;
|
|
|
|
if(!blocked || !is_transparent_isect ||
|
|
|
|
max_hits + 1 >= SHADOW_STACK_MAX_HITS)
|
2017-01-30 11:08:20 +00:00
|
|
|
{
|
2017-01-30 13:11:58 +00:00
|
|
|
return shadow_blocked_transparent_stepped_loop(kg,
|
|
|
|
shadow_sd,
|
|
|
|
state,
|
2017-02-09 13:19:01 +00:00
|
|
|
skip_object,
|
2017-01-30 13:11:58 +00:00
|
|
|
ray,
|
2017-03-08 14:42:26 +00:00
|
|
|
&isect,
|
2017-01-30 13:11:58 +00:00
|
|
|
blocked,
|
|
|
|
is_transparent_isect,
|
|
|
|
shadow);
|
2016-09-21 15:34:15 +00:00
|
|
|
}
|
2017-01-30 13:11:58 +00:00
|
|
|
# endif /* __KERNEL_GPU__ */
|
|
|
|
return shadow_blocked_transparent_all(kg,
|
|
|
|
shadow_sd,
|
|
|
|
state,
|
2017-02-09 13:19:01 +00:00
|
|
|
skip_object,
|
2017-01-30 13:11:58 +00:00
|
|
|
ray,
|
|
|
|
max_hits,
|
|
|
|
shadow);
|
|
|
|
# else /* __SHADOW_RECORD_ALL__ */
|
|
|
|
/* Fallback to a slowest version which works on all devices. */
|
2017-01-30 11:08:20 +00:00
|
|
|
return shadow_blocked_transparent_stepped(kg,
|
|
|
|
shadow_sd,
|
|
|
|
state,
|
2017-02-09 13:19:01 +00:00
|
|
|
skip_object,
|
2017-01-30 11:08:20 +00:00
|
|
|
ray,
|
2017-03-08 14:42:26 +00:00
|
|
|
&isect,
|
2017-01-30 11:08:20 +00:00
|
|
|
shadow);
|
2017-01-30 13:11:58 +00:00
|
|
|
# endif /* __SHADOW_RECORD_ALL__ */
|
2017-01-30 11:08:20 +00:00
|
|
|
#endif /* __TRANSPARENT_SHADOWS__ */
|
2016-09-21 15:34:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#undef SHADOW_STACK_MAX_HITS
|
2014-04-19 15:02:30 +00:00
|
|
|
|
2013-12-28 01:56:53 +00:00
|
|
|
CCL_NAMESPACE_END
|