Changeset View
Changeset View
Standalone View
Standalone View
intern/cycles/kernel/kernel_shadow.h
| Show All 10 Lines | |||||
| * distributed under the License is distributed on an "AS IS" BASIS, | * distributed under the License is distributed on an "AS IS" BASIS, | ||||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| * See the License for the specific language governing permissions and | * See the License for the specific language governing permissions and | ||||
| * limitations under the License. | * limitations under the License. | ||||
| */ | */ | ||||
| CCL_NAMESPACE_BEGIN | CCL_NAMESPACE_BEGIN | ||||
| #if defined(__SHADOW_RECORD_ALL__) || defined(__SHADOW_RECORD_ALL_STATIC__) | |||||
| ccl_device_inline void sort_intersections(Intersection *hits, uint num_hits) | |||||
| { | |||||
| #ifdef __KERNEL_GPU__ | |||||
| int i, j; | |||||
| for(i = 0; i < num_hits; ++i) { | |||||
| for(j = 0; j < num_hits - 1; ++j) { | |||||
| if(hits[j].t < hits[j + 1].t) { | |||||
| Intersection tmp = hits[j]; | |||||
| hits[j] = hits[j + 1]; | |||||
| hits[j + 1] = tmp; | |||||
| } | |||||
| } | |||||
| } | |||||
| #else | |||||
| qsort(hits, num_hits, sizeof(Intersection), intersections_compare); | |||||
| #endif | |||||
| } | |||||
| #endif /* defined(__SHADOW_RECORD_ALL__) || defined(__SHADOW_RECORD_ALL_STATIC__) */ | |||||
| #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. | ||||
| * | * | ||||
| * We trace a single ray. If it hits any opaque surface, or more than a given | * 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 | * 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 | * 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 | * will shade them one by one to determine how much light is blocked. This all | ||||
| ▲ Show 20 Lines • Show All 56 Lines • ▼ Show 20 Lines | if(!blocked && num_hits > 0) { | ||||
| float3 Pend = ray->P + ray->D*ray->t; | float3 Pend = ray->P + ray->D*ray->t; | ||||
| float last_t = 0.0f; | float last_t = 0.0f; | ||||
| int bounce = state->transparent_bounce; | int bounce = state->transparent_bounce; | ||||
| Intersection *isect = hits; | Intersection *isect = hits; | ||||
| #ifdef __VOLUME__ | #ifdef __VOLUME__ | ||||
| PathState ps = *state; | PathState ps = *state; | ||||
| #endif | #endif | ||||
| qsort(hits, num_hits, sizeof(Intersection), intersections_compare); | sort_intersections(hits, num_hits); | ||||
| 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 */ | ||||
| Show All 20 Lines | #endif | ||||
| shader_eval_surface(kg, shadow_sd, NULL, state, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW); | shader_eval_surface(kg, shadow_sd, NULL, state, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW); | ||||
| path_state_modify_bounce(state, false); | path_state_modify_bounce(state, false); | ||||
| throughput *= shader_bsdf_transparency(kg, shadow_sd); | throughput *= shader_bsdf_transparency(kg, shadow_sd); | ||||
| } | } | ||||
| /* stop if all light is blocked */ | /* stop if all light is blocked */ | ||||
| if(is_zero(throughput)) { | if(is_zero(throughput)) { | ||||
| /* free dynamic storage */ | |||||
| 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); | ||||
| Show All 28 Lines | #ifdef __VOLUME__ | ||||
| } | } | ||||
| #endif | #endif | ||||
| return blocked; | return blocked; | ||||
| } | } | ||||
| #undef STACK_MAX_HITS | #undef STACK_MAX_HITS | ||||
| #else | #else /* __SHADOW_RECORD_ALL__ */ | ||||
| # ifdef __SHADOW_RECORD_ALL_STATIC__ | |||||
| # define STACK_MAX_HITS 17 | |||||
| # endif | |||||
| /* Shadow function to compute how much light is blocked, GPU variation. | /* Shadow function to compute how much light is blocked, GPU variation. | ||||
| * | * | ||||
| * Here we raytrace from one transparent surface to the next step by step. | * Central entry point is still shadow_blocked(), other functions here are just | ||||
| * To minimize overhead in cases where we don't need transparent shadows, we | * helper functions to avoid function to become too long. | ||||
| * first trace a regular shadow ray. We check if the hit primitive was | * | ||||
| * potentially transparent, and only in that case start marching. this gives | * The idea here is to perform as much optimal intersection as possible and only | ||||
| * one extra ray cast for the cases were we do want transparency. */ | * do slow sorted step-by-step BVH traversal when actually needed. | ||||
| */ | |||||
| ccl_device_noinline bool shadow_blocked(KernelGlobals *kg, | /* This function calculates shadow for scenes without transparent shaders. | ||||
| * | |||||
| * Traces single ray and sees whether it hit something or not. | |||||
| */ | |||||
| ccl_device bool shadow_blocked_opaque(KernelGlobals *kg, | |||||
| ShaderData *shadow_sd, | ShaderData *shadow_sd, | ||||
| ccl_addr_space PathState *state, | ccl_addr_space PathState *state, | ||||
| ccl_addr_space Ray *ray_input, | Ray *ray, | ||||
| Intersection *isect, | |||||
| float3 *shadow) | float3 *shadow) | ||||
| { | { | ||||
| *shadow = make_float3(1.0f, 1.0f, 1.0f); | bool blocked = scene_intersect(kg, | ||||
| ray, | |||||
| if(ray_input->t == 0.0f) | PATH_RAY_SHADOW_OPAQUE, | ||||
| return false; | isect, | ||||
| NULL, | |||||
| #ifdef __SPLIT_KERNEL__ | 0.0f, 0.0f); | ||||
| Ray private_ray = *ray_input; | # ifdef __VOLUME__ | ||||
| Ray *ray = &private_ray; | if(!blocked && state->volume_stack[0].shader != SHADER_NONE) { | ||||
| #else | /* Apply attenuation from current volume shader. */ | ||||
| Ray *ray = ray_input; | kernel_volume_shadow(kg, shadow_sd, state, ray, shadow); | ||||
| #endif | } | ||||
| # endif /* __VOLUME__ */ | |||||
| #ifdef __SPLIT_KERNEL__ | return blocked; | ||||
| Intersection *isect = &kg->isect_shadow[SD_THREAD]; | } | ||||
| #else | |||||
| Intersection isect_object; | |||||
| Intersection *isect = &isect_object; | |||||
| #endif | |||||
| bool blocked = scene_intersect(kg, ray, PATH_RAY_SHADOW_OPAQUE, isect, NULL, 0.0f, 0.0f); | |||||
| #ifdef __TRANSPARENT_SHADOWS__ | # ifdef __TRANSPARENT_SHADOWS__ | ||||
| if(blocked && kernel_data.integrator.transparent_shadows) { | # ifdef __VOLUME__ | ||||
| /* 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 | |||||
| * one extra ray cast for the cases were we do want transparency. | |||||
| * | |||||
| * This function handles cases when both transparent shadows and volume are | |||||
| * in the scene. | |||||
| */ | |||||
| ccl_device bool shadow_blocked_transparent_volume( | |||||
| KernelGlobals *kg, | |||||
| ShaderData *shadow_sd, | |||||
| ccl_addr_space PathState *state, | |||||
| Ray *ray, | |||||
| Intersection *isect, | |||||
| float3 *shadow) | |||||
| { | |||||
| /* Check if we need a slow step-by-step traversal. */ | |||||
| /* TODO(sergey): Could it be faster to shoot transparent ray and if opaque | |||||
| * object was hit return zero throughput? | |||||
| */ | |||||
| bool blocked = scene_intersect(kg, | |||||
| ray, | |||||
| PATH_RAY_SHADOW_OPAQUE, | |||||
| isect, | |||||
| NULL, | |||||
| 0.0f, 0.0f); | |||||
| if(blocked) { | |||||
| if(shader_transparent_shadow(kg, isect)) { | if(shader_transparent_shadow(kg, isect)) { | ||||
| 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__ | |||||
| PathState ps = *state; | PathState ps = *state; | ||||
| #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__ | /* 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, | ||||
| kernel_volume_shadow(kg, shadow_sd, &ps, ray, &throughput); | shadow_sd, | ||||
| #endif | &ps, | ||||
| ray, | |||||
| &throughput); | |||||
| } | |||||
| *shadow *= throughput; | *shadow *= throughput; | ||||
| return false; | return false; | ||||
| } | } | ||||
| if(!shader_transparent_shadow(kg, isect)) { | |||||
| if(!shader_transparent_shadow(kg, isect)) | |||||
| return true; | return true; | ||||
| } | |||||
| #ifdef __VOLUME__ | /* Attenuation between last surface and next surface. */ | ||||
| /* attenuation between last surface and next surface */ | |||||
| if(ps.volume_stack[0].shader != SHADER_NONE) { | if(ps.volume_stack[0].shader != SHADER_NONE) { | ||||
| Ray segment_ray = *ray; | Ray segment_ray = *ray; | ||||
| segment_ray.t = isect->t; | segment_ray.t = isect->t; | ||||
| kernel_volume_shadow(kg, shadow_sd, &ps, &segment_ray, &throughput); | kernel_volume_shadow(kg, | ||||
| shadow_sd, | |||||
| &ps, | |||||
| &segment_ray, | |||||
| &throughput); | |||||
| } | } | ||||
| #endif | /* Setup shader data at surface. */ | ||||
| /* setup shader data at surface */ | |||||
| shader_setup_from_ray(kg, shadow_sd, isect, ray); | shader_setup_from_ray(kg, shadow_sd, isect, ray); | ||||
| /* Attenuation from transparent surface. */ | |||||
| /* attenuation from transparent surface */ | |||||
| if(!(ccl_fetch(shadow_sd, flag) & SD_HAS_ONLY_VOLUME)) { | if(!(ccl_fetch(shadow_sd, flag) & SD_HAS_ONLY_VOLUME)) { | ||||
| path_state_modify_bounce(state, true); | path_state_modify_bounce(state, true); | ||||
| shader_eval_surface(kg, shadow_sd, NULL, state, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW); | shader_eval_surface(kg, | ||||
| shadow_sd, | |||||
| NULL, | |||||
| state, | |||||
| 0.0f, | |||||
| PATH_RAY_SHADOW, | |||||
| SHADER_CONTEXT_SHADOW); | |||||
| path_state_modify_bounce(state, false); | path_state_modify_bounce(state, false); | ||||
| throughput *= shader_bsdf_transparency(kg, shadow_sd); | throughput *= shader_bsdf_transparency(kg, shadow_sd); | ||||
| } | } | ||||
| if(is_zero(throughput)) { | |||||
| 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); | ||||
| /* Exit/enter volume. */ | |||||
| #ifdef __VOLUME__ | |||||
| /* exit/enter volume */ | |||||
| kernel_volume_stack_enter_exit(kg, shadow_sd, ps.volume_stack); | kernel_volume_stack_enter_exit(kg, shadow_sd, ps.volume_stack); | ||||
| #endif | |||||
| bounce++; | bounce++; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| #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); | ||||
| } | } | ||||
| return blocked; | |||||
| } | |||||
| # endif /* __VOLUME__ */ | |||||
| /* This is an optimized version of above which only deals with transparent | |||||
| * shadows without volumes. | |||||
| */ | |||||
| # ifdef __BVH_RECORD_CALLBACK__ | |||||
| typedef struct ShadowState { | |||||
| float3 throughput; | |||||
| int bounce; | |||||
| bool blocked; | |||||
| ccl_addr_space PathState *state; | |||||
| ShaderData *sd; | |||||
| } ShadowState; | |||||
| ccl_device bool shadow_blocked_callback(KernelGlobals *kg, | |||||
| const Ray *ray, | |||||
| Intersection *isect, | |||||
| int object, | |||||
| void *user_data) | |||||
| { | |||||
| ShadowState *shadow_state = (ShadowState *)user_data; | |||||
| if(shadow_state->bounce >= kernel_data.integrator.transparent_max_bounce) { | |||||
| shadow_state->blocked = true; | |||||
| return false; | |||||
| } | |||||
| if(!shader_transparent_shadow(kg, isect)) { | |||||
| shadow_state->blocked = true; | |||||
| return false; | |||||
| } | |||||
| /* Setup shader data at surface. */ | |||||
| shader_setup_from_ray(kg, | |||||
| shadow_state->sd, | |||||
| isect, | |||||
| ray); | |||||
| /* Attenuation from transparent surface. */ | |||||
| if(!(ccl_fetch(shadow_state->sd, flag) & SD_HAS_ONLY_VOLUME)) { | |||||
| path_state_modify_bounce(shadow_state->state, true); | |||||
| shader_eval_surface(kg, | |||||
| shadow_state->sd, | |||||
| NULL, | |||||
| shadow_state->state, | |||||
| 0.0f, | |||||
| PATH_RAY_SHADOW, | |||||
| SHADER_CONTEXT_SHADOW); | |||||
| path_state_modify_bounce(shadow_state->state, false); | |||||
| shadow_state->throughput *= | |||||
| shader_bsdf_transparency(kg, shadow_state->sd); | |||||
| } | |||||
| if(is_zero(shadow_state->throughput)) { | |||||
| shadow_state->blocked = true; | |||||
| return false; | |||||
| } | |||||
| ++shadow_state->bounce; | |||||
| /* Reset intersection distance so we record all other intersections | |||||
| * which might be further away. | |||||
| */ | |||||
| isect->t = ray->t; | |||||
| if(ray->t != FLT_MAX) { | |||||
| if(object != OBJECT_NONE) { | |||||
| Transform itfm; | |||||
| #ifdef __OBJECT_MOTION__ | |||||
| object_fetch_transform_motion_test(kg, object, ray->time, &itfm); | |||||
| #else | |||||
| itfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM); | |||||
| #endif | #endif | ||||
| #endif | float ray_len = len(transform_direction(&itfm, ray->D)); | ||||
| isect->t *= ray_len; | |||||
| } | |||||
| } | |||||
| return true; | |||||
| } | |||||
| ccl_device bool shadow_blocked_transparent( | |||||
| KernelGlobals *kg, | |||||
| ShaderData *shadow_sd, | |||||
| ccl_addr_space PathState *state, | |||||
| Ray *ray, | |||||
| Intersection *isect, | |||||
| float3 *shadow) | |||||
| { | |||||
| ShadowState shadow_state; | |||||
| shadow_state.throughput = make_float3(1.0f, 1.0f, 1.0f); | |||||
| shadow_state.bounce = state->transparent_bounce; | |||||
| shadow_state.blocked = false; | |||||
| shadow_state.state = state; | |||||
| shadow_state.sd = shadow_sd; | |||||
| scene_intersect_callback(kg, | |||||
| ray, | |||||
| PATH_RAY_SHADOW_TRANSPARENT, | |||||
| isect, | |||||
| NULL, | |||||
| 0.0f, 0.0f, | |||||
| shadow_blocked_callback, | |||||
| &shadow_state); | |||||
| if(!shadow_state.blocked) { | |||||
| *shadow = shadow_state.throughput; | |||||
| } | |||||
| return shadow_state.blocked; | |||||
| } | |||||
| # else /* __BVH_RECORD_CALLBACK__ */ | |||||
| ccl_device bool shadow_blocked_transparent( | |||||
| KernelGlobals *kg, | |||||
| ShaderData *shadow_sd, | |||||
| ccl_addr_space PathState *state, | |||||
| Ray *ray, | |||||
| Intersection *isect, | |||||
| float3 *shadow) | |||||
| { | |||||
| bool blocked = scene_intersect(kg, | |||||
| ray, | |||||
| PATH_RAY_SHADOW_OPAQUE, | |||||
| isect, | |||||
| NULL, | |||||
| 0.0f, 0.0f); | |||||
| if(blocked) { | |||||
| if(shader_transparent_shadow(kg, isect)) { | |||||
| float3 throughput = make_float3(1.0f, 1.0f, 1.0f); | |||||
| float3 Pend = ray->P + ray->D*ray->t; | |||||
| int bounce = state->transparent_bounce; | |||||
| 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)) | |||||
| { | |||||
| *shadow *= throughput; | |||||
| return false; | |||||
| } | |||||
| if(!shader_transparent_shadow(kg, isect)) { | |||||
| return true; | |||||
| } | |||||
| /* 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); | |||||
| } | |||||
| if(is_zero(throughput)) { | |||||
| return true; | |||||
| } | |||||
| /* Move ray forward, */ | |||||
| ray->P = ray_offset(ccl_fetch(shadow_sd, P), | |||||
| -ccl_fetch(shadow_sd, Ng)); | |||||
| if(ray->t != FLT_MAX) { | |||||
| ray->D = normalize_len(Pend - ray->P, &ray->t); | |||||
| } | |||||
| bounce++; | |||||
| } | |||||
| } | |||||
| } | |||||
| return blocked; | |||||
| } | |||||
| # endif /* __BVH_RECORD_CALLBACK__ */ | |||||
| # ifdef __SHADOW_RECORD_ALL_STATIC__ | |||||
| /* This function is similar to __SHADOW_RECORD_ALL_, but it doesn't do any | |||||
| * in-kernel allocation/free so watch out the transparent bounces limit! | |||||
| */ | |||||
| ccl_device bool shadow_blocked_transparent_volume_all_static( | |||||
| KernelGlobals *kg, | |||||
| ShaderData *shadow_sd, | |||||
| ccl_addr_space PathState *state, | |||||
| Ray *ray, | |||||
| Intersection *isect, | |||||
| float3 *shadow) { | |||||
| /* check transparent bounces here, for volume scatter which can do | |||||
| * lighting before surface path termination is checked */ | |||||
| if(state->transparent_bounce >= kernel_data.integrator.transparent_max_bounce) { | |||||
| return true; | |||||
| } | |||||
| /* Intersect to find an opaque surface, or record all transparent surface | |||||
| * hits. | |||||
| */ | |||||
| Intersection hits[STACK_MAX_HITS]; | |||||
| const int transparent_max_bounce = kernel_data.integrator.transparent_max_bounce; | |||||
| uint max_hits = transparent_max_bounce - state->transparent_bounce - 1; | |||||
| uint num_hits; | |||||
| bool blocked = scene_intersect_shadow_all(kg, | |||||
| ray, | |||||
| hits, | |||||
| 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; | |||||
| PathState ps = *state; | |||||
| 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; | |||||
| } | |||||
| last_t = new_t; | |||||
| /* Attenuation between last surface and next surface. */ | |||||
| if(ps.volume_stack[0].shader != SHADER_NONE) { | |||||
| Ray segment_ray = *ray; | |||||
| segment_ray.t = isect->t; | |||||
| kernel_volume_shadow(kg, shadow_sd, &ps, &segment_ray, &throughput); | |||||
| } | |||||
| /* 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; | |||||
| } | |||||
| /* Move ray forward. */ | |||||
| ray->P = shadow_sd->P; | |||||
| if(ray->t != FLT_MAX) { | |||||
| ray->D = normalize_len(Pend - ray->P, &ray->t); | |||||
| } | |||||
| /* Exit/enter volume. */ | |||||
| kernel_volume_stack_enter_exit(kg, shadow_sd, ps.volume_stack); | |||||
| bounce++; | |||||
| } | |||||
| /* Attenuation for last line segment towards light. */ | |||||
| if(ps.volume_stack[0].shader != SHADER_NONE) { | |||||
| kernel_volume_shadow(kg, shadow_sd, &ps, ray, &throughput); | |||||
| } | |||||
| *shadow = throughput; | |||||
| return is_zero(throughput); | |||||
| } | |||||
| if(!blocked && state->volume_stack[0].shader != SHADER_NONE) { | |||||
| /* Apply attenuation from current volume shader. */ | |||||
| kernel_volume_shadow(kg, shadow_sd, state, ray, shadow); | |||||
| } | |||||
| return blocked; | return blocked; | ||||
| } | } | ||||
| # endif /* __SHADOW_RECORD_ALL_STATIC__ */ | |||||
| # endif /* __TRANSPARENT_SHADOWS__ */ | |||||
| /* Shadow function to compute how much light is blocked, GPU variation. */ | |||||
| ccl_device_noinline bool shadow_blocked(KernelGlobals *kg, | |||||
| ShaderData *shadow_sd, | |||||
| ccl_addr_space PathState *state, | |||||
| ccl_addr_space Ray *ray_input, | |||||
| float3 *shadow) | |||||
| { | |||||
| /* Some common initialization and early exit checks. */ | |||||
| *shadow = make_float3(1.0f, 1.0f, 1.0f); | |||||
| if(ray_input->t == 0.0f) { | |||||
| return false; | |||||
| } | |||||
| /* Some annoying OpenCL address space conversion when needed. */ | |||||
| # ifdef __SPLIT_KERNEL__ | |||||
| Ray private_ray = *ray_input; | |||||
| Ray *ray = &private_ray; | |||||
| Intersection *isect = &kg->isect_shadow[SD_THREAD]; | |||||
| # else /* __SPLIT_KERNEL__ */ | |||||
| Ray *ray = ray_input; | |||||
| Intersection isect_object; | |||||
| Intersection *isect = &isect_object; | |||||
| # endif /* __SPLIT_KERNEL__ */ | |||||
| /* Perform actual shadow calculation. | |||||
| * Call function which suites current scene most. | |||||
| */ | |||||
| if(kernel_data.integrator.transparent_shadows) { | |||||
| # ifdef __VOLUME__ | |||||
| if(kernel_data.integrator.use_volumes) { | |||||
| # ifdef __SHADOW_RECORD_ALL_STATIC__ | |||||
| const int transparent_max_bounce = kernel_data.integrator.transparent_max_bounce; | |||||
| const uint max_hits = transparent_max_bounce - state->transparent_bounce - 1; | |||||
| if(max_hits + 1 <= STACK_MAX_HITS) { | |||||
| /* It is enough space in static array, so we can run optimal | |||||
| * function here. | |||||
| */ | |||||
| return shadow_blocked_transparent_volume_all_static(kg, | |||||
| shadow_sd, | |||||
| state, | |||||
| ray, | |||||
| isect, | |||||
| shadow); | |||||
| } | |||||
| else | |||||
| # endif /* __SHADOW_RECORD_ALL_STATIC__ */ | |||||
| { | |||||
| /* We are doomed to run the slowest ever version here. | |||||
| * Hopefully it doesn't happen very often. | |||||
| */ | |||||
| return shadow_blocked_transparent_volume(kg, | |||||
| shadow_sd, | |||||
| state, | |||||
| ray, | |||||
| isect, | |||||
| shadow); | |||||
| } | |||||
| } | |||||
| else | |||||
| # endif /* __VOLUME__ */ | |||||
| { | |||||
| return shadow_blocked_transparent(kg, | |||||
| shadow_sd, | |||||
| state, | |||||
| ray, | |||||
| isect, | |||||
| shadow); | |||||
| } | |||||
| } | |||||
| else { | |||||
| return shadow_blocked_opaque(kg, shadow_sd, state, ray, isect, shadow); | |||||
| } | |||||
| } | |||||
| # ifdef __SHADOW_RECORD_ALL_STATIC__ | |||||
| # undef STACK_MAX_HITS | |||||
| #endif | # endif | ||||
| #endif /* __SHADOW_RECORD_ALL__ */ | |||||
| CCL_NAMESPACE_END | CCL_NAMESPACE_END | ||||