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,
191 *shadow = make_float3(1.0f, 1.0f, 1.0f);
193 if(ray_input->t == 0.0f)
196 #ifdef __SPLIT_KERNEL__
197 Ray private_ray = *ray_input;
198 Ray *ray = &private_ray;
200 Ray *ray = ray_input;
203 #ifdef __SPLIT_KERNEL__
204 Intersection *isect = &kg->isect_shadow[TIDX];
206 Intersection isect_object;
207 Intersection *isect = &isect_object;
210 bool blocked = scene_intersect(kg, ray, PATH_RAY_SHADOW_OPAQUE, isect, NULL, 0.0f, 0.0f);
212 #ifdef __TRANSPARENT_SHADOWS__
213 if(blocked && kernel_data.integrator.transparent_shadows) {
214 if(shader_transparent_shadow(kg, isect)) {
215 float3 throughput = make_float3(1.0f, 1.0f, 1.0f);
216 float3 Pend = ray->P + ray->D*ray->t;
217 int bounce = state->transparent_bounce;
219 PathState ps = *state;
223 if(bounce >= kernel_data.integrator.transparent_max_bounce)
226 if(!scene_intersect(kg, ray, PATH_RAY_SHADOW_TRANSPARENT, isect, NULL, 0.0f, 0.0f))
229 /* attenuation for last line segment towards light */
230 if(ps.volume_stack[0].shader != SHADER_NONE)
231 kernel_volume_shadow(kg, &ps, ray, &throughput);
234 *shadow *= throughput;
239 if(!shader_transparent_shadow(kg, isect))
243 /* attenuation between last surface and next surface */
244 if(ps.volume_stack[0].shader != SHADER_NONE) {
245 Ray segment_ray = *ray;
246 segment_ray.t = isect->t;
247 kernel_volume_shadow(kg, &ps, &segment_ray, &throughput);
251 /* setup shader data at surface */
252 #ifdef __SPLIT_KERNEL__
253 ShaderData *sd = kg->sd_input;
255 ShaderData sd_object;
256 ShaderData *sd = &sd_object;
258 shader_setup_from_ray(kg, sd, isect, ray);
260 /* attenuation from transparent surface */
261 if(!(ccl_fetch(sd, flag) & SD_HAS_ONLY_VOLUME)) {
262 path_state_modify_bounce(state, true);
263 shader_eval_surface(kg, sd, state, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW);
264 path_state_modify_bounce(state, false);
266 throughput *= shader_bsdf_transparency(kg, sd);
269 if(is_zero(throughput))
272 /* move ray forward */
273 ray->P = ray_offset(ccl_fetch(sd, P), -ccl_fetch(sd, Ng));
274 if(ray->t != FLT_MAX)
275 ray->D = normalize_len(Pend - ray->P, &ray->t);
278 /* exit/enter volume */
279 kernel_volume_stack_enter_exit(kg, sd, ps.volume_stack);
287 else if(!blocked && state->volume_stack[0].shader != SHADER_NONE) {
288 /* apply attenuation from current volume shader */
289 kernel_volume_shadow(kg, state, ray, shadow);