Cycles: ambient occlusion support, with AO factor and distance, and a render pass.
[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
37                 if(type == CLOSURE_BSDF_TRANSPARENT_ID)
38                         eval->transparent = value;
39                 else if(CLOSURE_IS_BSDF_DIFFUSE(type))
40                         eval->diffuse = value;
41                 else if(CLOSURE_IS_BSDF_GLOSSY(type))
42                         eval->glossy = value;
43                 else
44                         eval->transmission = value;
45         }
46         else
47                 eval->diffuse = value;
48 #else
49         *eval = value;
50 #endif
51 }
52
53 __device_inline void bsdf_eval_accum(BsdfEval *eval, ClosureType type, float3 value)
54 {
55 #ifdef __PASSES__
56         if(eval->use_light_pass) {
57                 if(CLOSURE_IS_BSDF_DIFFUSE(type))
58                         eval->diffuse += value;
59                 else if(CLOSURE_IS_BSDF_GLOSSY(type))
60                         eval->glossy += value;
61                 else
62                         eval->transmission += value;
63
64                 /* skipping transparent, this function is used by for eval(), will be zero then */
65         }
66         else
67                 eval->diffuse += value;
68 #else
69         *eval += value;
70 #endif
71 }
72
73 __device_inline bool bsdf_eval_is_zero(BsdfEval *eval)
74 {
75 #ifdef __PASSES__
76         if(eval->use_light_pass) {
77                 return is_zero(eval->diffuse)
78                         && is_zero(eval->glossy)
79                         && is_zero(eval->transmission)
80                         && is_zero(eval->transparent);
81         }
82         else
83                 return is_zero(eval->diffuse);
84 #else
85         return is_zero(*eval);
86 #endif
87 }
88
89 __device_inline void bsdf_eval_mul(BsdfEval *eval, float3 value)
90 {
91 #ifdef __PASSES__
92         if(eval->use_light_pass) {
93                 eval->diffuse *= value;
94                 eval->glossy *= value;
95                 eval->transmission *= value;
96
97                 /* skipping transparent, this function is used by for eval(), will be zero then */
98         }
99         else
100                 eval->diffuse *= value;
101 #else
102         *eval *= value;
103 #endif
104 }
105
106 /* Path Radiance
107  *
108  * We accumulate different render passes separately. After summing at the end
109  * to get the combined result, it should be identical. We definte directly
110  * visible as the first non-transparent hit, while indirectly visible are the
111  * bounces after that. */
112
113 __device_inline void path_radiance_init(PathRadiance *L, int use_light_pass)
114 {
115         /* clear all */
116 #ifdef __PASSES__
117         L->use_light_pass = use_light_pass;
118
119         if(use_light_pass) {
120                 L->indirect = make_float3(0.0f, 0.0f, 0.0f);
121                 L->direct_throughput = make_float3(0.0f, 0.0f, 0.0f);
122                 L->direct_emission = make_float3(0.0f, 0.0f, 0.0f);
123
124                 L->color_diffuse = make_float3(0.0f, 0.0f, 0.0f);
125                 L->color_glossy = make_float3(0.0f, 0.0f, 0.0f);
126                 L->color_transmission = make_float3(0.0f, 0.0f, 0.0f);
127
128                 L->direct_diffuse = make_float3(0.0f, 0.0f, 0.0f);
129                 L->direct_glossy = make_float3(0.0f, 0.0f, 0.0f);
130                 L->direct_transmission = make_float3(0.0f, 0.0f, 0.0f);
131
132                 L->indirect_diffuse = make_float3(0.0f, 0.0f, 0.0f);
133                 L->indirect_glossy = make_float3(0.0f, 0.0f, 0.0f);
134                 L->indirect_transmission = make_float3(0.0f, 0.0f, 0.0f);
135
136                 L->emission = make_float3(0.0f, 0.0f, 0.0f);
137                 L->background = make_float3(0.0f, 0.0f, 0.0f);
138                 L->ao = make_float3(0.0f, 0.0f, 0.0f);
139         }
140         else
141                 L->emission = make_float3(0.0f, 0.0f, 0.0f);
142 #else
143         *L = make_float3(0.0f, 0.0f, 0.0f);
144 #endif
145 }
146
147 __device_inline void path_radiance_bsdf_bounce(PathRadiance *L, float3 *throughput,
148         BsdfEval *bsdf_eval, float bsdf_pdf, int bounce, int bsdf_label)
149 {
150         float inverse_pdf = 1.0f/bsdf_pdf;
151
152 #ifdef __PASSES__
153         if(L->use_light_pass) {
154                 if(bounce == 0) {
155                         if(bsdf_label & LABEL_TRANSPARENT) {
156                                 /* transparent bounce before first hit */
157                                 *throughput *= bsdf_eval->transparent*inverse_pdf;
158                         }
159                         else {
160                                 /* first on directly visible surface */
161                                 float3 value = *throughput*inverse_pdf;
162
163                                 L->indirect_diffuse = bsdf_eval->diffuse*value;
164                                 L->indirect_glossy = bsdf_eval->glossy*value;
165                                 L->indirect_transmission = bsdf_eval->transmission*value;
166
167                                 *throughput = L->indirect_diffuse + L->indirect_glossy + L->indirect_transmission;
168                                 
169                                 L->direct_throughput = *throughput;
170                         }
171                 }
172                 else {
173                         /* indirectly visible through BSDF */
174                         float3 sum = (bsdf_eval->diffuse + bsdf_eval->glossy + bsdf_eval->transmission + bsdf_eval->transparent)*inverse_pdf;
175                         *throughput *= sum;
176                 }
177         }
178         else
179                 *throughput *= bsdf_eval->diffuse*inverse_pdf;
180 #else
181         *throughput *= *bsdf_eval*inverse_pdf;
182 #endif
183 }
184
185 __device_inline void path_radiance_accum_emission(PathRadiance *L, float3 throughput, float3 value, int bounce)
186 {
187 #ifdef __PASSES__
188         if(L->use_light_pass) {
189                 if(bounce == 0)
190                         L->emission += throughput*value;
191                 else if(bounce == 1)
192                         L->direct_emission += throughput*value;
193                 else
194                         L->indirect += throughput*value;
195         }
196         else
197                 L->emission += throughput*value;
198 #else
199         *L += throughput*value;
200 #endif
201 }
202
203 __device_inline void path_radiance_accum_ao(PathRadiance *L, float3 throughput, float3 bsdf, float3 ao, int bounce)
204 {
205 #ifdef __PASSES__
206         if(L->use_light_pass) {
207                 if(bounce == 0) {
208                         /* directly visible lighting */
209                         L->direct_diffuse += throughput*bsdf*ao;
210                         L->ao += throughput*ao;
211                 }
212                 else {
213                         /* indirectly visible lighting after BSDF bounce */
214                         L->indirect += throughput*bsdf*ao;
215                 }
216         }
217         else
218                 L->emission += throughput*bsdf*ao;
219 #else
220         *L += throughput*bsdf*ao;
221 #endif
222 }
223
224 __device_inline void path_radiance_accum_light(PathRadiance *L, float3 throughput, BsdfEval *bsdf_eval, int bounce)
225 {
226 #ifdef __PASSES__
227         if(L->use_light_pass) {
228                 if(bounce == 0) {
229                         /* directly visible lighting */
230                         L->direct_diffuse += throughput*bsdf_eval->diffuse;
231                         L->direct_glossy += throughput*bsdf_eval->glossy;
232                         L->direct_transmission += throughput*bsdf_eval->transmission;
233                 }
234                 else {
235                         /* indirectly visible lighting after BSDF bounce */
236                         float3 sum = bsdf_eval->diffuse + bsdf_eval->glossy + bsdf_eval->transmission;
237                         L->indirect += throughput*sum;
238                 }
239         }
240         else
241                 L->emission += throughput*bsdf_eval->diffuse;
242 #else
243         *L += throughput*(*bsdf_eval);
244 #endif
245 }
246
247 __device_inline void path_radiance_accum_background(PathRadiance *L, float3 throughput, float3 value, int bounce)
248 {
249 #ifdef __PASSES__
250         if(L->use_light_pass) {
251                 if(bounce == 0)
252                         L->background += throughput*value;
253                 else if(bounce == 1)
254                         L->direct_emission += throughput*value;
255                 else
256                         L->indirect += throughput*value;
257         }
258         else
259                 L->emission += throughput*value;
260 #else
261         *L += throughput*value;
262 #endif
263 }
264
265 __device_inline float3 safe_divide_color(float3 a, float3 b)
266 {
267         float x, y, z;
268
269         x = (b.x != 0.0f)? a.x/b.x: 0.0f;
270         y = (b.y != 0.0f)? a.y/b.y: 0.0f;
271         z = (b.z != 0.0f)? a.z/b.z: 0.0f;
272
273         return make_float3(x, y, z);
274 }
275
276 __device_inline float3 path_radiance_sum(PathRadiance *L)
277 {
278 #ifdef __PASSES__
279         if(L->use_light_pass) {
280                 /* this division is a bit ugly, but means we only have to keep track of
281                    only a single throughput further along the path, here we recover just
282                    the indirect parth that is not influenced by any particular BSDF type */
283                 L->direct_emission = safe_divide_color(L->direct_emission, L->direct_throughput);
284                 L->direct_diffuse += L->indirect_diffuse*L->direct_emission;
285                 L->direct_glossy += L->indirect_glossy*L->direct_emission;
286                 L->direct_transmission += L->indirect_transmission*L->direct_emission;
287
288                 L->indirect = safe_divide_color(L->indirect, L->direct_throughput);
289                 L->indirect_diffuse *= L->indirect;
290                 L->indirect_glossy *= L->indirect;
291                 L->indirect_transmission *= L->indirect;
292
293                 return L->emission + L->background
294                         + L->direct_diffuse + L->direct_glossy + L->direct_transmission
295                         + L->indirect_diffuse + L->indirect_glossy + L->indirect_transmission;
296         }
297         else
298                 return L->emission;
299 #else
300         return *L;
301 #endif
302 }
303
304 CCL_NAMESPACE_END
305