2 * Copyright 2011-2013 Blender Foundation
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #ifdef __SHADOW_RECORD_ALL__
21 /* Shadow function to compute how much light is blocked, CPU variation.
23 * We trace a single ray. If it hits any opaque surface, or more than a given
24 * number of transparent surfaces is hit, then we consider the geometry to be
25 * entirely blocked. If not, all transparent surfaces will be recorded and we
26 * will shade them one by one to determine how much light is blocked. This all
27 * happens in one scene intersection function.
29 * Recording all hits works well in some cases but may be slower in others. If
30 * we have many semi-transparent hairs, one intersection may be faster because
31 * you'd be reinteresecting the same hairs a lot with each step otherwise. If
32 * however there is mostly binary transparency then we may be recording many
33 * unnecessary intersections when one of the first surfaces blocks all light.
35 * From tests in real scenes it seems the performance loss is either minimal,
36 * or there is a performance increase anyway due to avoiding the need to send
37 * two rays with transparent shadows.
39 * This is CPU only because of qsort, and malloc or high stack space usage to
40 * record all these intersections. */
42 #define STACK_MAX_HITS 64
44 ccl_device_inline bool shadow_blocked(KernelGlobals *kg, PathState *state, Ray *ray, float3 *shadow)
46 *shadow = make_float3(1.0f, 1.0f, 1.0f);
53 if(kernel_data.integrator.transparent_shadows) {
54 /* check transparent bounces here, for volume scatter which can do
55 * lighting before surface path termination is checked */
56 if(state->transparent_bounce >= kernel_data.integrator.transparent_max_bounce)
59 /* intersect to find an opaque surface, or record all transparent surface hits */
60 Intersection hits_stack[STACK_MAX_HITS];
61 Intersection *hits = hits_stack;
62 uint max_hits = kernel_data.integrator.transparent_max_bounce - state->transparent_bounce - 1;
64 /* prefer to use stack but use dynamic allocation if too deep max hits
65 * we need max_hits + 1 storage space due to the logic in
66 * scene_intersect_shadow_all which will first store and then check if
67 * the limit is exceeded */
68 if(max_hits + 1 > STACK_MAX_HITS)
69 hits = (Intersection*)malloc(sizeof(Intersection)*(max_hits + 1));
72 blocked = scene_intersect_shadow_all(kg, ray, hits, max_hits, &num_hits);
74 /* if no opaque surface found but we did find transparent hits, shade them */
75 if(!blocked && num_hits > 0) {
76 float3 throughput = make_float3(1.0f, 1.0f, 1.0f);
77 float3 Pend = ray->P + ray->D*ray->t;
79 int bounce = state->transparent_bounce;
80 Intersection *isect = hits;
82 PathState ps = *state;
85 qsort(hits, num_hits, sizeof(Intersection), intersections_compare);
87 for(int hit = 0; hit < num_hits; hit++, isect++) {
88 /* adjust intersection distance for moving ray forward */
89 float new_t = isect->t;
92 /* skip hit if we did not move forward, step by step raytracing
93 * would have skipped it as well then */
100 /* attenuation between last surface and next surface */
101 if(ps.volume_stack[0].shader != SHADER_NONE) {
102 Ray segment_ray = *ray;
103 segment_ray.t = isect->t;
104 kernel_volume_shadow(kg, &ps, &segment_ray, &throughput);
108 /* setup shader data at surface */
110 shader_setup_from_ray(kg, &sd, isect, ray);
112 /* attenuation from transparent surface */
113 if(!(sd.flag & SD_HAS_ONLY_VOLUME)) {
114 path_state_modify_bounce(state, true);
115 shader_eval_surface(kg, &sd, state, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW);
116 path_state_modify_bounce(state, false);
118 throughput *= shader_bsdf_transparency(kg, &sd);
121 /* stop if all light is blocked */
122 if(is_zero(throughput)) {
123 /* free dynamic storage */
124 if(hits != hits_stack)
129 /* move ray forward */
131 if(ray->t != FLT_MAX)
132 ray->D = normalize_len(Pend - ray->P, &ray->t);
135 /* exit/enter volume */
136 kernel_volume_stack_enter_exit(kg, &sd, ps.volume_stack);
143 /* attenuation for last line segment towards light */
144 if(ps.volume_stack[0].shader != SHADER_NONE)
145 kernel_volume_shadow(kg, &ps, ray, &throughput);
148 *shadow = throughput;
150 if(hits != hits_stack)
152 return is_zero(throughput);
155 /* free dynamic storage */
156 if(hits != hits_stack)
161 blocked = scene_intersect(kg, ray, PATH_RAY_SHADOW_OPAQUE, &isect, NULL, 0.0f, 0.0f);
165 if(!blocked && state->volume_stack[0].shader != SHADER_NONE) {
166 /* apply attenuation from current volume shader */
167 kernel_volume_shadow(kg, state, ray, shadow);
174 #undef STACK_MAX_HITS
178 /* Shadow function to compute how much light is blocked, GPU variation.
180 * Here we raytrace from one transparent surface to the next step by step.
181 * To minimize overhead in cases where we don't need transparent shadows, we
182 * first trace a regular shadow ray. We check if the hit primitive was
183 * potentially transparent, and only in that case start marching. this gives
184 * one extra ray cast for the cases were we do want transparency. */
186 ccl_device_noinline bool shadow_blocked(KernelGlobals *kg,
187 ccl_addr_space PathState *state,
188 ccl_addr_space Ray *ray_input,
190 #ifdef __SPLIT_KERNEL__
191 , ShaderData *sd_mem, Intersection *isect_mem
195 *shadow = make_float3(1.0f, 1.0f, 1.0f);
197 if(ray_input->t == 0.0f)
200 #ifdef __SPLIT_KERNEL__
201 Ray private_ray = *ray_input;
202 Ray *ray = &private_ray;
204 Ray *ray = ray_input;
207 #ifdef __SPLIT_KERNEL__
208 Intersection *isect = isect_mem;
210 Intersection isect_object;
211 Intersection *isect = &isect_object;
214 bool blocked = scene_intersect(kg, ray, PATH_RAY_SHADOW_OPAQUE, isect, NULL, 0.0f, 0.0f);
216 #ifdef __TRANSPARENT_SHADOWS__
217 if(blocked && kernel_data.integrator.transparent_shadows) {
218 if(shader_transparent_shadow(kg, isect)) {
219 float3 throughput = make_float3(1.0f, 1.0f, 1.0f);
220 float3 Pend = ray->P + ray->D*ray->t;
221 int bounce = state->transparent_bounce;
223 PathState ps = *state;
227 if(bounce >= kernel_data.integrator.transparent_max_bounce)
230 if(!scene_intersect(kg, ray, PATH_RAY_SHADOW_TRANSPARENT, isect, NULL, 0.0f, 0.0f))
233 /* attenuation for last line segment towards light */
234 if(ps.volume_stack[0].shader != SHADER_NONE)
235 kernel_volume_shadow(kg, &ps, ray, &throughput);
238 *shadow *= throughput;
243 if(!shader_transparent_shadow(kg, isect))
247 /* attenuation between last surface and next surface */
248 if(ps.volume_stack[0].shader != SHADER_NONE) {
249 Ray segment_ray = *ray;
250 segment_ray.t = isect->t;
251 kernel_volume_shadow(kg, &ps, &segment_ray, &throughput);
255 /* setup shader data at surface */
256 #ifdef __SPLIT_KERNEL__
257 ShaderData *sd = sd_mem;
259 ShaderData sd_object;
260 ShaderData *sd = &sd_object;
262 shader_setup_from_ray(kg, sd, isect, ray);
264 /* attenuation from transparent surface */
265 if(!(ccl_fetch(sd, flag) & SD_HAS_ONLY_VOLUME)) {
266 path_state_modify_bounce(state, true);
267 shader_eval_surface(kg, sd, state, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW);
268 path_state_modify_bounce(state, false);
270 throughput *= shader_bsdf_transparency(kg, sd);
273 if(is_zero(throughput))
276 /* move ray forward */
277 ray->P = ray_offset(ccl_fetch(sd, P), -ccl_fetch(sd, Ng));
278 if(ray->t != FLT_MAX)
279 ray->D = normalize_len(Pend - ray->P, &ray->t);
282 /* exit/enter volume */
283 kernel_volume_stack_enter_exit(kg, sd, ps.volume_stack);
291 else if(!blocked && state->volume_stack[0].shader != SHADER_NONE) {
292 /* apply attenuation from current volume shader */
293 kernel_volume_shadow(kg, state, ray, shadow);