1 /*
2  * Copyright 2011-2013 Blender Foundation
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 
17 CCL_NAMESPACE_BEGIN
18 
19 #ifdef __VOLUME_SCATTER__
20 
kernel_path_volume_connect_light(KernelGlobals * kg,ShaderData * sd,ShaderData * emission_sd,float3 throughput,ccl_addr_space PathState * state,PathRadiance * L)21 ccl_device_inline void kernel_path_volume_connect_light(KernelGlobals *kg,
22                                                         ShaderData *sd,
23                                                         ShaderData *emission_sd,
24                                                         float3 throughput,
25                                                         ccl_addr_space PathState *state,
26                                                         PathRadiance *L)
27 {
28 #  ifdef __EMISSION__
29   /* sample illumination from lights to find path contribution */
30   Ray light_ray ccl_optional_struct_init;
31   BsdfEval L_light ccl_optional_struct_init;
32   bool is_lamp = false;
33   bool has_emission = false;
34 
35   light_ray.t = 0.0f;
36 #    ifdef __OBJECT_MOTION__
37   /* connect to light from given point where shader has been evaluated */
38   light_ray.time = sd->time;
39 #    endif
40 
41   if (kernel_data.integrator.use_direct_light) {
42     float light_u, light_v;
43     path_state_rng_2D(kg, state, PRNG_LIGHT_U, &light_u, &light_v);
44 
45     LightSample ls ccl_optional_struct_init;
46     if (light_sample(kg, -1, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) {
47       float terminate = path_state_rng_light_termination(kg, state);
48       has_emission = direct_emission(
49           kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp, terminate);
50     }
51   }
52 
53   /* trace shadow ray */
54   float3 shadow;
55 
56   const bool blocked = shadow_blocked(kg, sd, emission_sd, state, &light_ray, &shadow);
57 
58   if (has_emission && !blocked) {
59     /* accumulate */
60     path_radiance_accum_light(kg, L, state, throughput, &L_light, shadow, 1.0f, is_lamp);
61   }
62 #  endif /* __EMISSION__ */
63 }
64 
kernel_path_volume_bounce(KernelGlobals * kg,ShaderData * sd,ccl_addr_space float3 * throughput,ccl_addr_space PathState * state,PathRadianceState * L_state,ccl_addr_space Ray * ray)65 ccl_device_noinline_cpu bool kernel_path_volume_bounce(KernelGlobals *kg,
66                                                        ShaderData *sd,
67                                                        ccl_addr_space float3 *throughput,
68                                                        ccl_addr_space PathState *state,
69                                                        PathRadianceState *L_state,
70                                                        ccl_addr_space Ray *ray)
71 {
72   /* sample phase function */
73   float phase_pdf;
74   BsdfEval phase_eval ccl_optional_struct_init;
75   float3 phase_omega_in ccl_optional_struct_init;
76   differential3 phase_domega_in ccl_optional_struct_init;
77   float phase_u, phase_v;
78   path_state_rng_2D(kg, state, PRNG_BSDF_U, &phase_u, &phase_v);
79   int label;
80 
81   label = shader_volume_phase_sample(
82       kg, sd, phase_u, phase_v, &phase_eval, &phase_omega_in, &phase_domega_in, &phase_pdf);
83 
84   if (phase_pdf == 0.0f || bsdf_eval_is_zero(&phase_eval))
85     return false;
86 
87   /* modify throughput */
88   path_radiance_bsdf_bounce(kg, L_state, throughput, &phase_eval, phase_pdf, state->bounce, label);
89 
90   /* set labels */
91   state->ray_pdf = phase_pdf;
92 #  ifdef __LAMP_MIS__
93   state->ray_t = 0.0f;
94 #  endif
95   state->min_ray_pdf = fminf(phase_pdf, state->min_ray_pdf);
96 
97   /* update path state */
98   path_state_next(kg, state, label);
99 
100   /* Russian roulette termination of volume ray scattering. */
101   float probability = path_state_continuation_probability(kg, state, *throughput);
102 
103   if (probability == 0.0f) {
104     return false;
105   }
106   else if (probability != 1.0f) {
107     /* Use dimension from the previous bounce, has not been used yet. */
108     float terminate = path_state_rng_1D(kg, state, PRNG_TERMINATE - PRNG_BOUNCE_NUM);
109 
110     if (terminate >= probability) {
111       return false;
112     }
113 
114     *throughput /= probability;
115   }
116 
117   /* setup ray */
118   ray->P = sd->P;
119   ray->D = phase_omega_in;
120   ray->t = FLT_MAX;
121 
122 #  ifdef __RAY_DIFFERENTIALS__
123   ray->dP = sd->dP;
124   ray->dD = phase_domega_in;
125 #  endif
126 
127   return true;
128 }
129 
130 #  if !defined(__SPLIT_KERNEL__) && (defined(__BRANCHED_PATH__) || defined(__VOLUME_DECOUPLED__))
kernel_branched_path_volume_connect_light(KernelGlobals * kg,ShaderData * sd,ShaderData * emission_sd,float3 throughput,ccl_addr_space PathState * state,PathRadiance * L,bool sample_all_lights,Ray * ray,const VolumeSegment * segment)131 ccl_device void kernel_branched_path_volume_connect_light(KernelGlobals *kg,
132                                                           ShaderData *sd,
133                                                           ShaderData *emission_sd,
134                                                           float3 throughput,
135                                                           ccl_addr_space PathState *state,
136                                                           PathRadiance *L,
137                                                           bool sample_all_lights,
138                                                           Ray *ray,
139                                                           const VolumeSegment *segment)
140 {
141 #    ifdef __EMISSION__
142   BsdfEval L_light ccl_optional_struct_init;
143 
144   int num_lights = 1;
145   if (sample_all_lights) {
146     num_lights = kernel_data.integrator.num_all_lights;
147     if (kernel_data.integrator.pdf_triangles != 0.0f) {
148       num_lights += 1;
149     }
150   }
151 
152   for (int i = 0; i < num_lights; ++i) {
153     /* sample one light at random */
154     int num_samples = 1;
155     int num_all_lights = 1;
156     uint lamp_rng_hash = state->rng_hash;
157     bool double_pdf = false;
158     bool is_mesh_light = false;
159     bool is_lamp = false;
160 
161     if (sample_all_lights) {
162       /* lamp sampling */
163       is_lamp = i < kernel_data.integrator.num_all_lights;
164       if (is_lamp) {
165         if (UNLIKELY(light_select_reached_max_bounces(kg, i, state->bounce))) {
166           continue;
167         }
168         num_samples = light_select_num_samples(kg, i);
169         num_all_lights = kernel_data.integrator.num_all_lights;
170         lamp_rng_hash = cmj_hash(state->rng_hash, i);
171         double_pdf = kernel_data.integrator.pdf_triangles != 0.0f;
172       }
173       /* mesh light sampling */
174       else {
175         num_samples = kernel_data.integrator.mesh_light_samples;
176         double_pdf = kernel_data.integrator.num_all_lights != 0;
177         is_mesh_light = true;
178       }
179     }
180 
181     float num_samples_inv = 1.0f / (num_samples * num_all_lights);
182 
183     for (int j = 0; j < num_samples; j++) {
184       Ray light_ray ccl_optional_struct_init;
185       light_ray.t = 0.0f; /* reset ray */
186 #      ifdef __OBJECT_MOTION__
187       light_ray.time = sd->time;
188 #      endif
189       bool has_emission = false;
190 
191       float3 tp = throughput;
192 
193       if (kernel_data.integrator.use_direct_light) {
194         /* sample random position on random light/triangle */
195         float light_u, light_v;
196         path_branched_rng_2D(
197             kg, lamp_rng_hash, state, j, num_samples, PRNG_LIGHT_U, &light_u, &light_v);
198 
199         /* only sample triangle lights */
200         if (is_mesh_light && double_pdf) {
201           light_u = 0.5f * light_u;
202         }
203 
204         LightSample ls ccl_optional_struct_init;
205         const int lamp = is_lamp ? i : -1;
206         light_sample(kg, lamp, light_u, light_v, sd->time, ray->P, state->bounce, &ls);
207 
208         /* sample position on volume segment */
209         float rphase = path_branched_rng_1D(
210             kg, state->rng_hash, state, j, num_samples, PRNG_PHASE_CHANNEL);
211         float rscatter = path_branched_rng_1D(
212             kg, state->rng_hash, state, j, num_samples, PRNG_SCATTER_DISTANCE);
213 
214         VolumeIntegrateResult result = kernel_volume_decoupled_scatter(kg,
215                                                                        state,
216                                                                        ray,
217                                                                        sd,
218                                                                        &tp,
219                                                                        rphase,
220                                                                        rscatter,
221                                                                        segment,
222                                                                        (ls.t != FLT_MAX) ? &ls.P :
223                                                                                            NULL,
224                                                                        false);
225 
226         if (result == VOLUME_PATH_SCATTERED) {
227           /* todo: split up light_sample so we don't have to call it again with new position */
228           if (light_sample(kg, lamp, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) {
229             if (double_pdf) {
230               ls.pdf *= 2.0f;
231             }
232 
233             /* sample random light */
234             float terminate = path_branched_rng_light_termination(
235                 kg, state->rng_hash, state, j, num_samples);
236             has_emission = direct_emission(
237                 kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp, terminate);
238           }
239         }
240       }
241 
242       /* trace shadow ray */
243       float3 shadow;
244 
245       const bool blocked = shadow_blocked(kg, sd, emission_sd, state, &light_ray, &shadow);
246 
247       if (has_emission && !blocked) {
248         /* accumulate */
249         path_radiance_accum_light(
250             kg, L, state, tp * num_samples_inv, &L_light, shadow, num_samples_inv, is_lamp);
251       }
252     }
253   }
254 #    endif /* __EMISSION__ */
255 }
256 #  endif /* __SPLIT_KERNEL__ */
257 
258 #endif /* __VOLUME_SCATTER__ */
259 
260 CCL_NAMESPACE_END
261