Cycles / SSS Render Passes:
[blender.git] / intern / cycles / kernel / kernel_accumulate.h
1 /*
2  * Copyright 2011, Blender Foundation.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18
19 CCL_NAMESPACE_BEGIN
20
21 /* BSDF Eval
22  *
23  * BSDF evaluation result, split per BSDF type. This is used to accumulate
24  * render passes separately. */
25
26 __device_inline void bsdf_eval_init(BsdfEval *eval, ClosureType type, float3 value, int use_light_pass)
27 {
28 #ifdef __PASSES__
29         eval->use_light_pass = use_light_pass;
30
31         if(eval->use_light_pass) {
32                 eval->diffuse = make_float3(0.0f, 0.0f, 0.0f);
33                 eval->glossy = make_float3(0.0f, 0.0f, 0.0f);
34                 eval->transmission = make_float3(0.0f, 0.0f, 0.0f);
35                 eval->transparent = make_float3(0.0f, 0.0f, 0.0f);
36                 eval->subsurface = make_float3(0.0f, 0.0f, 0.0f);
37
38                 if(type == CLOSURE_BSDF_TRANSPARENT_ID)
39                         eval->transparent = value;
40                 else if(CLOSURE_IS_BSDF_DIFFUSE(type))
41                         eval->diffuse = value;
42                 else if(CLOSURE_IS_BSDF_GLOSSY(type))
43                         eval->glossy = value;
44                 else if(CLOSURE_IS_BSDF_TRANSMISSION(type))
45                         eval->transmission = value;
46                 else if(CLOSURE_IS_BSDF_BSSRDF(type))
47                         eval->subsurface = value;
48         }
49         else
50                 eval->diffuse = value;
51 #else
52         *eval = value;
53 #endif
54 }
55
56 __device_inline void bsdf_eval_accum(BsdfEval *eval, ClosureType type, float3 value)
57 {
58 #ifdef __PASSES__
59         if(eval->use_light_pass) {
60                 if(CLOSURE_IS_BSDF_DIFFUSE(type))
61                         eval->diffuse += value;
62                 else if(CLOSURE_IS_BSDF_GLOSSY(type))
63                         eval->glossy += value;
64                 else if(CLOSURE_IS_BSDF_TRANSMISSION(type))
65                         eval->transmission += value;
66                 else if(CLOSURE_IS_BSDF_BSSRDF(type))
67                         eval->subsurface += value;
68
69                 /* skipping transparent, this function is used by for eval(), will be zero then */
70         }
71         else
72                 eval->diffuse += value;
73 #else
74         *eval += value;
75 #endif
76 }
77
78 __device_inline bool bsdf_eval_is_zero(BsdfEval *eval)
79 {
80 #ifdef __PASSES__
81         if(eval->use_light_pass) {
82                 return is_zero(eval->diffuse)
83                         && is_zero(eval->glossy)
84                         && is_zero(eval->transmission)
85                         && is_zero(eval->transparent)
86                         && is_zero(eval->subsurface);
87         }
88         else
89                 return is_zero(eval->diffuse);
90 #else
91         return is_zero(*eval);
92 #endif
93 }
94
95 __device_inline void bsdf_eval_mul(BsdfEval *eval, float3 value)
96 {
97 #ifdef __PASSES__
98         if(eval->use_light_pass) {
99                 eval->diffuse *= value;
100                 eval->glossy *= value;
101                 eval->transmission *= value;
102                 eval->subsurface *= value;
103
104                 /* skipping transparent, this function is used by for eval(), will be zero then */
105         }
106         else
107                 eval->diffuse *= value;
108 #else
109         *eval *= value;
110 #endif
111 }
112
113 /* Path Radiance
114  *
115  * We accumulate different render passes separately. After summing at the end
116  * to get the combined result, it should be identical. We definte directly
117  * visible as the first non-transparent hit, while indirectly visible are the
118  * bounces after that. */
119
120 __device_inline void path_radiance_init(PathRadiance *L, int use_light_pass)
121 {
122         /* clear all */
123 #ifdef __PASSES__
124         L->use_light_pass = use_light_pass;
125
126         if(use_light_pass) {
127                 L->indirect = make_float3(0.0f, 0.0f, 0.0f);
128                 L->direct_throughput = make_float3(0.0f, 0.0f, 0.0f);
129                 L->direct_emission = make_float3(0.0f, 0.0f, 0.0f);
130
131                 L->color_diffuse = make_float3(0.0f, 0.0f, 0.0f);
132                 L->color_glossy = make_float3(0.0f, 0.0f, 0.0f);
133                 L->color_transmission = make_float3(0.0f, 0.0f, 0.0f);
134                 L->color_subsurface = make_float3(0.0f, 0.0f, 0.0f);
135
136                 L->direct_diffuse = make_float3(0.0f, 0.0f, 0.0f);
137                 L->direct_glossy = make_float3(0.0f, 0.0f, 0.0f);
138                 L->direct_transmission = make_float3(0.0f, 0.0f, 0.0f);
139                 L->direct_subsurface = make_float3(0.0f, 0.0f, 0.0f);
140
141                 L->indirect_diffuse = make_float3(0.0f, 0.0f, 0.0f);
142                 L->indirect_glossy = make_float3(0.0f, 0.0f, 0.0f);
143                 L->indirect_transmission = make_float3(0.0f, 0.0f, 0.0f);
144                 L->indirect_subsurface = make_float3(0.0f, 0.0f, 0.0f);
145
146                 L->path_diffuse = make_float3(0.0f, 0.0f, 0.0f);
147                 L->path_glossy = make_float3(0.0f, 0.0f, 0.0f);
148                 L->path_transmission = make_float3(0.0f, 0.0f, 0.0f);
149                 L->path_subsurface = make_float3(0.0f, 0.0f, 0.0f);
150
151                 L->emission = make_float3(0.0f, 0.0f, 0.0f);
152                 L->background = make_float3(0.0f, 0.0f, 0.0f);
153                 L->ao = make_float3(0.0f, 0.0f, 0.0f);
154                 L->shadow = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
155                 L->mist = 0.0f;
156         }
157         else
158                 L->emission = make_float3(0.0f, 0.0f, 0.0f);
159 #else
160         *L = make_float3(0.0f, 0.0f, 0.0f);
161 #endif
162 }
163
164 __device_inline void path_radiance_bsdf_bounce(PathRadiance *L, float3 *throughput,
165         BsdfEval *bsdf_eval, float bsdf_pdf, int bounce, int bsdf_label)
166 {
167         float inverse_pdf = 1.0f/bsdf_pdf;
168
169 #ifdef __PASSES__
170         if(L->use_light_pass) {
171                 if(bounce == 0 && !(bsdf_label & LABEL_TRANSPARENT)) {
172                         /* first on directly visible surface */
173                         float3 value = *throughput*inverse_pdf;
174
175                         L->path_diffuse = bsdf_eval->diffuse*value;
176                         L->path_glossy = bsdf_eval->glossy*value;
177                         L->path_transmission = bsdf_eval->transmission*value;
178                         L->path_subsurface = bsdf_eval->subsurface*value;
179
180                         *throughput = L->path_diffuse + L->path_glossy + L->path_transmission + L->path_subsurface;
181                         
182                         L->direct_throughput = *throughput;
183                 }
184                 else {
185                         /* transparent bounce before first hit, or indirectly visible through BSDF */
186                         float3 sum = (bsdf_eval->diffuse + bsdf_eval->glossy + bsdf_eval->transmission + bsdf_eval->transparent + bsdf_eval->subsurface)*inverse_pdf;
187                         *throughput *= sum;
188                 }
189         }
190         else
191                 *throughput *= bsdf_eval->diffuse*inverse_pdf;
192 #else
193         *throughput *= *bsdf_eval*inverse_pdf;
194 #endif
195 }
196
197 __device_inline void path_radiance_accum_emission(PathRadiance *L, float3 throughput, float3 value, int bounce)
198 {
199 #ifdef __PASSES__
200         if(L->use_light_pass) {
201                 if(bounce == 0)
202                         L->emission += throughput*value;
203                 else if(bounce == 1)
204                         L->direct_emission += throughput*value;
205                 else
206                         L->indirect += throughput*value;
207         }
208         else
209                 L->emission += throughput*value;
210 #else
211         *L += throughput*value;
212 #endif
213 }
214
215 __device_inline void path_radiance_accum_ao(PathRadiance *L, float3 throughput, float3 bsdf, float3 ao, int bounce)
216 {
217 #ifdef __PASSES__
218         if(L->use_light_pass) {
219                 if(bounce == 0) {
220                         /* directly visible lighting */
221                         L->direct_diffuse += throughput*bsdf*ao;
222                         L->ao += throughput*ao;
223                 }
224                 else {
225                         /* indirectly visible lighting after BSDF bounce */
226                         L->indirect += throughput*bsdf*ao;
227                 }
228         }
229         else
230                 L->emission += throughput*bsdf*ao;
231 #else
232         *L += throughput*bsdf*ao;
233 #endif
234 }
235
236 __device_inline void path_radiance_accum_light(PathRadiance *L, float3 throughput, BsdfEval *bsdf_eval, float3 shadow, float shadow_fac, int bounce, bool is_lamp)
237 {
238 #ifdef __PASSES__
239         if(L->use_light_pass) {
240                 if(bounce == 0) {
241                         /* directly visible lighting */
242                         L->direct_diffuse += throughput*bsdf_eval->diffuse*shadow;
243                         L->direct_glossy += throughput*bsdf_eval->glossy*shadow;
244                         L->direct_transmission += throughput*bsdf_eval->transmission*shadow;
245                         L->direct_subsurface += throughput*bsdf_eval->subsurface*shadow;
246
247                         if(is_lamp) {
248                                 L->shadow.x += shadow.x*shadow_fac;
249                                 L->shadow.y += shadow.y*shadow_fac;
250                                 L->shadow.z += shadow.z*shadow_fac;
251                         }
252                 }
253                 else {
254                         /* indirectly visible lighting after BSDF bounce */
255                         float3 sum = bsdf_eval->diffuse + bsdf_eval->glossy + bsdf_eval->transmission + bsdf_eval->subsurface;
256                         L->indirect += throughput*sum*shadow;
257                 }
258         }
259         else
260                 L->emission += throughput*bsdf_eval->diffuse*shadow;
261 #else
262         *L += throughput*(*bsdf_eval)*shadow;
263 #endif
264 }
265
266 __device_inline void path_radiance_accum_background(PathRadiance *L, float3 throughput, float3 value, int bounce)
267 {
268 #ifdef __PASSES__
269         if(L->use_light_pass) {
270                 if(bounce == 0)
271                         L->background += throughput*value;
272                 else if(bounce == 1)
273                         L->direct_emission += throughput*value;
274                 else
275                         L->indirect += throughput*value;
276         }
277         else
278                 L->emission += throughput*value;
279 #else
280         *L += throughput*value;
281 #endif
282 }
283
284 __device_inline void path_radiance_sum_indirect(PathRadiance *L)
285 {
286 #ifdef __PASSES__
287         /* this division is a bit ugly, but means we only have to keep track of
288          * only a single throughput further along the path, here we recover just
289          * the indirect parth that is not influenced by any particular BSDF type */
290         if(L->use_light_pass) {
291                 L->direct_emission = safe_divide_color(L->direct_emission, L->direct_throughput);
292                 L->direct_diffuse += L->path_diffuse*L->direct_emission;
293                 L->direct_glossy += L->path_glossy*L->direct_emission;
294                 L->direct_transmission += L->path_transmission*L->direct_emission;
295                 L->direct_subsurface += L->path_subsurface*L->direct_emission;
296
297                 L->indirect = safe_divide_color(L->indirect, L->direct_throughput);
298                 L->indirect_diffuse += L->path_diffuse*L->indirect;
299                 L->indirect_glossy += L->path_glossy*L->indirect;
300                 L->indirect_transmission += L->path_transmission*L->indirect;
301                 L->indirect_subsurface += L->path_subsurface*L->indirect;
302         }
303 #endif
304 }
305
306 __device_inline void path_radiance_reset_indirect(PathRadiance *L)
307 {
308 #ifdef __PASSES__
309         if(L->use_light_pass) {
310                 L->path_diffuse = make_float3(0.0f, 0.0f, 0.0f);
311                 L->path_glossy = make_float3(0.0f, 0.0f, 0.0f);
312                 L->path_transmission = make_float3(0.0f, 0.0f, 0.0f);
313                 L->path_subsurface = make_float3(0.0f, 0.0f, 0.0f);
314
315                 L->direct_emission = make_float3(0.0f, 0.0f, 0.0f);
316                 L->indirect = make_float3(0.0f, 0.0f, 0.0f);
317         }
318 #endif
319 }
320
321 __device_inline float3 path_radiance_sum(KernelGlobals *kg, PathRadiance *L)
322 {
323 #ifdef __PASSES__
324         if(L->use_light_pass) {
325                 path_radiance_sum_indirect(L);
326
327                 float3 L_sum = L->emission
328                         + L->direct_diffuse + L->direct_glossy + L->direct_transmission + L->direct_subsurface
329                         + L->indirect_diffuse + L->indirect_glossy + L->indirect_transmission + L->indirect_subsurface;
330
331                 if(!kernel_data.background.transparent)
332                         L_sum += L->background;
333
334                 return L_sum;
335         }
336         else
337                 return L->emission;
338 #else
339         return *L;
340 #endif
341 }
342
343 __device_inline void path_radiance_clamp(PathRadiance *L, float3 *L_sum, float clamp)
344 {
345         float sum = fabsf((*L_sum).x) + fabsf((*L_sum).y) + fabsf((*L_sum).z);
346
347         if(!isfinite(sum)) {
348                 /* invalid value, reject */
349                 *L_sum = make_float3(0.0f, 0.0f, 0.0f);
350
351 #ifdef __PASSES__
352                 if(L->use_light_pass) {
353                         L->direct_diffuse = make_float3(0.0f, 0.0f, 0.0f);
354                         L->direct_glossy = make_float3(0.0f, 0.0f, 0.0f);
355                         L->direct_transmission = make_float3(0.0f, 0.0f, 0.0f);
356                         L->direct_subsurface = make_float3(0.0f, 0.0f, 0.0f);
357
358                         L->indirect_diffuse = make_float3(0.0f, 0.0f, 0.0f);
359                         L->indirect_glossy = make_float3(0.0f, 0.0f, 0.0f);
360                         L->indirect_transmission = make_float3(0.0f, 0.0f, 0.0f);
361                         L->indirect_subsurface = make_float3(0.0f, 0.0f, 0.0f);
362
363                         L->emission = make_float3(0.0f, 0.0f, 0.0f);
364                 }
365 #endif
366         }
367         else if(sum > clamp) {
368                 /* value to high, scale down */
369                 float scale = clamp/sum;
370
371                 *L_sum *= scale;
372
373 #ifdef __PASSES__
374                 if(L->use_light_pass) {
375                         L->direct_diffuse *= scale;
376                         L->direct_glossy *= scale;
377                         L->direct_transmission *= scale;
378                         L->direct_subsurface *= scale;
379
380                         L->indirect_diffuse *= scale;
381                         L->indirect_glossy *= scale;
382                         L->indirect_transmission *= scale;
383                         L->indirect_subsurface *= scale;
384
385                         L->emission *= scale;
386                 }
387 #endif
388         }
389 }
390
391 CCL_NAMESPACE_END
392