ClangFormat: apply to source, most of intern
[blender.git] / intern / cycles / kernel / kernel_camera.h
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 /* Perspective Camera */
20
21 ccl_device float2 camera_sample_aperture(ccl_constant KernelCamera *cam, float u, float v)
22 {
23   float blades = cam->blades;
24   float2 bokeh;
25
26   if (blades == 0.0f) {
27     /* sample disk */
28     bokeh = concentric_sample_disk(u, v);
29   }
30   else {
31     /* sample polygon */
32     float rotation = cam->bladesrotation;
33     bokeh = regular_polygon_sample(blades, rotation, u, v);
34   }
35
36   /* anamorphic lens bokeh */
37   bokeh.x *= cam->inv_aperture_ratio;
38
39   return bokeh;
40 }
41
42 ccl_device void camera_sample_perspective(KernelGlobals *kg,
43                                           float raster_x,
44                                           float raster_y,
45                                           float lens_u,
46                                           float lens_v,
47                                           ccl_addr_space Ray *ray)
48 {
49   /* create ray form raster position */
50   ProjectionTransform rastertocamera = kernel_data.cam.rastertocamera;
51   float3 raster = make_float3(raster_x, raster_y, 0.0f);
52   float3 Pcamera = transform_perspective(&rastertocamera, raster);
53
54 #ifdef __CAMERA_MOTION__
55   if (kernel_data.cam.have_perspective_motion) {
56     /* TODO(sergey): Currently we interpolate projected coordinate which
57      * gives nice looking result and which is simple, but is in fact a bit
58      * different comparing to constructing projective matrix from an
59      * interpolated field of view.
60      */
61     if (ray->time < 0.5f) {
62       ProjectionTransform rastertocamera_pre = kernel_data.cam.perspective_pre;
63       float3 Pcamera_pre = transform_perspective(&rastertocamera_pre, raster);
64       Pcamera = interp(Pcamera_pre, Pcamera, ray->time * 2.0f);
65     }
66     else {
67       ProjectionTransform rastertocamera_post = kernel_data.cam.perspective_post;
68       float3 Pcamera_post = transform_perspective(&rastertocamera_post, raster);
69       Pcamera = interp(Pcamera, Pcamera_post, (ray->time - 0.5f) * 2.0f);
70     }
71   }
72 #endif
73
74   float3 P = make_float3(0.0f, 0.0f, 0.0f);
75   float3 D = Pcamera;
76
77   /* modify ray for depth of field */
78   float aperturesize = kernel_data.cam.aperturesize;
79
80   if (aperturesize > 0.0f) {
81     /* sample point on aperture */
82     float2 lensuv = camera_sample_aperture(&kernel_data.cam, lens_u, lens_v) * aperturesize;
83
84     /* compute point on plane of focus */
85     float ft = kernel_data.cam.focaldistance / D.z;
86     float3 Pfocus = D * ft;
87
88     /* update ray for effect of lens */
89     P = make_float3(lensuv.x, lensuv.y, 0.0f);
90     D = normalize(Pfocus - P);
91   }
92
93   /* transform ray from camera to world */
94   Transform cameratoworld = kernel_data.cam.cameratoworld;
95
96 #ifdef __CAMERA_MOTION__
97   if (kernel_data.cam.num_motion_steps) {
98     transform_motion_array_interpolate(&cameratoworld,
99                                        kernel_tex_array(__camera_motion),
100                                        kernel_data.cam.num_motion_steps,
101                                        ray->time);
102   }
103 #endif
104
105   P = transform_point(&cameratoworld, P);
106   D = normalize(transform_direction(&cameratoworld, D));
107
108   bool use_stereo = kernel_data.cam.interocular_offset != 0.0f;
109   if (!use_stereo) {
110     /* No stereo */
111     ray->P = P;
112     ray->D = D;
113
114 #ifdef __RAY_DIFFERENTIALS__
115     float3 Dcenter = transform_direction(&cameratoworld, Pcamera);
116
117     ray->dP = differential3_zero();
118     ray->dD.dx = normalize(Dcenter + float4_to_float3(kernel_data.cam.dx)) - normalize(Dcenter);
119     ray->dD.dy = normalize(Dcenter + float4_to_float3(kernel_data.cam.dy)) - normalize(Dcenter);
120 #endif
121   }
122   else {
123     /* Spherical stereo */
124     spherical_stereo_transform(&kernel_data.cam, &P, &D);
125     ray->P = P;
126     ray->D = D;
127
128 #ifdef __RAY_DIFFERENTIALS__
129     /* Ray differentials, computed from scratch using the raster coordinates
130      * because we don't want to be affected by depth of field. We compute
131      * ray origin and direction for the center and two neighbouring pixels
132      * and simply take their differences. */
133     float3 Pnostereo = transform_point(&cameratoworld, make_float3(0.0f, 0.0f, 0.0f));
134
135     float3 Pcenter = Pnostereo;
136     float3 Dcenter = Pcamera;
137     Dcenter = normalize(transform_direction(&cameratoworld, Dcenter));
138     spherical_stereo_transform(&kernel_data.cam, &Pcenter, &Dcenter);
139
140     float3 Px = Pnostereo;
141     float3 Dx = transform_perspective(&rastertocamera,
142                                       make_float3(raster_x + 1.0f, raster_y, 0.0f));
143     Dx = normalize(transform_direction(&cameratoworld, Dx));
144     spherical_stereo_transform(&kernel_data.cam, &Px, &Dx);
145
146     ray->dP.dx = Px - Pcenter;
147     ray->dD.dx = Dx - Dcenter;
148
149     float3 Py = Pnostereo;
150     float3 Dy = transform_perspective(&rastertocamera,
151                                       make_float3(raster_x, raster_y + 1.0f, 0.0f));
152     Dy = normalize(transform_direction(&cameratoworld, Dy));
153     spherical_stereo_transform(&kernel_data.cam, &Py, &Dy);
154
155     ray->dP.dy = Py - Pcenter;
156     ray->dD.dy = Dy - Dcenter;
157 #endif
158   }
159
160 #ifdef __CAMERA_CLIPPING__
161   /* clipping */
162   float z_inv = 1.0f / normalize(Pcamera).z;
163   float nearclip = kernel_data.cam.nearclip * z_inv;
164   ray->P += nearclip * ray->D;
165   ray->dP.dx += nearclip * ray->dD.dx;
166   ray->dP.dy += nearclip * ray->dD.dy;
167   ray->t = kernel_data.cam.cliplength * z_inv;
168 #else
169   ray->t = FLT_MAX;
170 #endif
171 }
172
173 /* Orthographic Camera */
174 ccl_device void camera_sample_orthographic(KernelGlobals *kg,
175                                            float raster_x,
176                                            float raster_y,
177                                            float lens_u,
178                                            float lens_v,
179                                            ccl_addr_space Ray *ray)
180 {
181   /* create ray form raster position */
182   ProjectionTransform rastertocamera = kernel_data.cam.rastertocamera;
183   float3 Pcamera = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y, 0.0f));
184
185   float3 P;
186   float3 D = make_float3(0.0f, 0.0f, 1.0f);
187
188   /* modify ray for depth of field */
189   float aperturesize = kernel_data.cam.aperturesize;
190
191   if (aperturesize > 0.0f) {
192     /* sample point on aperture */
193     float2 lensuv = camera_sample_aperture(&kernel_data.cam, lens_u, lens_v) * aperturesize;
194
195     /* compute point on plane of focus */
196     float3 Pfocus = D * kernel_data.cam.focaldistance;
197
198     /* update ray for effect of lens */
199     float3 lensuvw = make_float3(lensuv.x, lensuv.y, 0.0f);
200     P = Pcamera + lensuvw;
201     D = normalize(Pfocus - lensuvw);
202   }
203   else {
204     P = Pcamera;
205   }
206   /* transform ray from camera to world */
207   Transform cameratoworld = kernel_data.cam.cameratoworld;
208
209 #ifdef __CAMERA_MOTION__
210   if (kernel_data.cam.num_motion_steps) {
211     transform_motion_array_interpolate(&cameratoworld,
212                                        kernel_tex_array(__camera_motion),
213                                        kernel_data.cam.num_motion_steps,
214                                        ray->time);
215   }
216 #endif
217
218   ray->P = transform_point(&cameratoworld, P);
219   ray->D = normalize(transform_direction(&cameratoworld, D));
220
221 #ifdef __RAY_DIFFERENTIALS__
222   /* ray differential */
223   ray->dP.dx = float4_to_float3(kernel_data.cam.dx);
224   ray->dP.dy = float4_to_float3(kernel_data.cam.dy);
225
226   ray->dD = differential3_zero();
227 #endif
228
229 #ifdef __CAMERA_CLIPPING__
230   /* clipping */
231   ray->t = kernel_data.cam.cliplength;
232 #else
233   ray->t = FLT_MAX;
234 #endif
235 }
236
237 /* Panorama Camera */
238
239 ccl_device_inline void camera_sample_panorama(ccl_constant KernelCamera *cam,
240                                               const ccl_global DecomposedTransform *cam_motion,
241                                               float raster_x,
242                                               float raster_y,
243                                               float lens_u,
244                                               float lens_v,
245                                               ccl_addr_space Ray *ray)
246 {
247   ProjectionTransform rastertocamera = cam->rastertocamera;
248   float3 Pcamera = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y, 0.0f));
249
250   /* create ray form raster position */
251   float3 P = make_float3(0.0f, 0.0f, 0.0f);
252   float3 D = panorama_to_direction(cam, Pcamera.x, Pcamera.y);
253
254   /* indicates ray should not receive any light, outside of the lens */
255   if (is_zero(D)) {
256     ray->t = 0.0f;
257     return;
258   }
259
260   /* modify ray for depth of field */
261   float aperturesize = cam->aperturesize;
262
263   if (aperturesize > 0.0f) {
264     /* sample point on aperture */
265     float2 lensuv = camera_sample_aperture(cam, lens_u, lens_v) * aperturesize;
266
267     /* compute point on plane of focus */
268     float3 Dfocus = normalize(D);
269     float3 Pfocus = Dfocus * cam->focaldistance;
270
271     /* calculate orthonormal coordinates perpendicular to Dfocus */
272     float3 U, V;
273     U = normalize(make_float3(1.0f, 0.0f, 0.0f) - Dfocus.x * Dfocus);
274     V = normalize(cross(Dfocus, U));
275
276     /* update ray for effect of lens */
277     P = U * lensuv.x + V * lensuv.y;
278     D = normalize(Pfocus - P);
279   }
280
281   /* transform ray from camera to world */
282   Transform cameratoworld = cam->cameratoworld;
283
284 #ifdef __CAMERA_MOTION__
285   if (cam->num_motion_steps) {
286     transform_motion_array_interpolate(
287         &cameratoworld, cam_motion, cam->num_motion_steps, ray->time);
288   }
289 #endif
290
291   P = transform_point(&cameratoworld, P);
292   D = normalize(transform_direction(&cameratoworld, D));
293
294   /* Stereo transform */
295   bool use_stereo = cam->interocular_offset != 0.0f;
296   if (use_stereo) {
297     spherical_stereo_transform(cam, &P, &D);
298   }
299
300   ray->P = P;
301   ray->D = D;
302
303 #ifdef __RAY_DIFFERENTIALS__
304   /* Ray differentials, computed from scratch using the raster coordinates
305    * because we don't want to be affected by depth of field. We compute
306    * ray origin and direction for the center and two neighbouring pixels
307    * and simply take their differences. */
308   float3 Pcenter = Pcamera;
309   float3 Dcenter = panorama_to_direction(cam, Pcenter.x, Pcenter.y);
310   Pcenter = transform_point(&cameratoworld, Pcenter);
311   Dcenter = normalize(transform_direction(&cameratoworld, Dcenter));
312   if (use_stereo) {
313     spherical_stereo_transform(cam, &Pcenter, &Dcenter);
314   }
315
316   float3 Px = transform_perspective(&rastertocamera, make_float3(raster_x + 1.0f, raster_y, 0.0f));
317   float3 Dx = panorama_to_direction(cam, Px.x, Px.y);
318   Px = transform_point(&cameratoworld, Px);
319   Dx = normalize(transform_direction(&cameratoworld, Dx));
320   if (use_stereo) {
321     spherical_stereo_transform(cam, &Px, &Dx);
322   }
323
324   ray->dP.dx = Px - Pcenter;
325   ray->dD.dx = Dx - Dcenter;
326
327   float3 Py = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y + 1.0f, 0.0f));
328   float3 Dy = panorama_to_direction(cam, Py.x, Py.y);
329   Py = transform_point(&cameratoworld, Py);
330   Dy = normalize(transform_direction(&cameratoworld, Dy));
331   if (use_stereo) {
332     spherical_stereo_transform(cam, &Py, &Dy);
333   }
334
335   ray->dP.dy = Py - Pcenter;
336   ray->dD.dy = Dy - Dcenter;
337 #endif
338
339 #ifdef __CAMERA_CLIPPING__
340   /* clipping */
341   float nearclip = cam->nearclip;
342   ray->P += nearclip * ray->D;
343   ray->dP.dx += nearclip * ray->dD.dx;
344   ray->dP.dy += nearclip * ray->dD.dy;
345   ray->t = cam->cliplength;
346 #else
347   ray->t = FLT_MAX;
348 #endif
349 }
350
351 /* Common */
352
353 ccl_device_inline void camera_sample(KernelGlobals *kg,
354                                      int x,
355                                      int y,
356                                      float filter_u,
357                                      float filter_v,
358                                      float lens_u,
359                                      float lens_v,
360                                      float time,
361                                      ccl_addr_space Ray *ray)
362 {
363   /* pixel filter */
364   int filter_table_offset = kernel_data.film.filter_table_offset;
365   float raster_x = x + lookup_table_read(kg, filter_u, filter_table_offset, FILTER_TABLE_SIZE);
366   float raster_y = y + lookup_table_read(kg, filter_v, filter_table_offset, FILTER_TABLE_SIZE);
367
368 #ifdef __CAMERA_MOTION__
369   /* motion blur */
370   if (kernel_data.cam.shuttertime == -1.0f) {
371     ray->time = 0.5f;
372   }
373   else {
374     /* TODO(sergey): Such lookup is unneeded when there's rolling shutter
375      * effect in use but rolling shutter duration is set to 0.0.
376      */
377     const int shutter_table_offset = kernel_data.cam.shutter_table_offset;
378     ray->time = lookup_table_read(kg, time, shutter_table_offset, SHUTTER_TABLE_SIZE);
379     /* TODO(sergey): Currently single rolling shutter effect type only
380      * where scanlines are acquired from top to bottom and whole scanline
381      * is acquired at once (no delay in acquisition happens between pixels
382      * of single scanline).
383      *
384      * Might want to support more models in the future.
385      */
386     if (kernel_data.cam.rolling_shutter_type) {
387       /* Time corresponding to a fully rolling shutter only effect:
388        * top of the frame is time 0.0, bottom of the frame is time 1.0.
389        */
390       const float time = 1.0f - (float)y / kernel_data.cam.height;
391       const float duration = kernel_data.cam.rolling_shutter_duration;
392       if (duration != 0.0f) {
393         /* This isn't fully physical correct, but lets us to have simple
394          * controls in the interface. The idea here is basically sort of
395          * linear interpolation between how much rolling shutter effect
396          * exist on the frame and how much of it is a motion blur effect.
397          */
398         ray->time = (ray->time - 0.5f) * duration;
399         ray->time += (time - 0.5f) * (1.0f - duration) + 0.5f;
400       }
401       else {
402         ray->time = time;
403       }
404     }
405   }
406 #endif
407
408   /* sample */
409   if (kernel_data.cam.type == CAMERA_PERSPECTIVE) {
410     camera_sample_perspective(kg, raster_x, raster_y, lens_u, lens_v, ray);
411   }
412   else if (kernel_data.cam.type == CAMERA_ORTHOGRAPHIC) {
413     camera_sample_orthographic(kg, raster_x, raster_y, lens_u, lens_v, ray);
414   }
415   else {
416     const ccl_global DecomposedTransform *cam_motion = kernel_tex_array(__camera_motion);
417     camera_sample_panorama(&kernel_data.cam, cam_motion, raster_x, raster_y, lens_u, lens_v, ray);
418   }
419 }
420
421 /* Utilities */
422
423 ccl_device_inline float3 camera_position(KernelGlobals *kg)
424 {
425   Transform cameratoworld = kernel_data.cam.cameratoworld;
426   return make_float3(cameratoworld.x.w, cameratoworld.y.w, cameratoworld.z.w);
427 }
428
429 ccl_device_inline float camera_distance(KernelGlobals *kg, float3 P)
430 {
431   Transform cameratoworld = kernel_data.cam.cameratoworld;
432   float3 camP = make_float3(cameratoworld.x.w, cameratoworld.y.w, cameratoworld.z.w);
433
434   if (kernel_data.cam.type == CAMERA_ORTHOGRAPHIC) {
435     float3 camD = make_float3(cameratoworld.x.z, cameratoworld.y.z, cameratoworld.z.z);
436     return fabsf(dot((P - camP), camD));
437   }
438   else
439     return len(P - camP);
440 }
441
442 ccl_device_inline float3 camera_direction_from_point(KernelGlobals *kg, float3 P)
443 {
444   Transform cameratoworld = kernel_data.cam.cameratoworld;
445
446   if (kernel_data.cam.type == CAMERA_ORTHOGRAPHIC) {
447     float3 camD = make_float3(cameratoworld.x.z, cameratoworld.y.z, cameratoworld.z.z);
448     return -camD;
449   }
450   else {
451     float3 camP = make_float3(cameratoworld.x.w, cameratoworld.y.w, cameratoworld.z.w);
452     return normalize(camP - P);
453   }
454 }
455
456 ccl_device_inline float3 camera_world_to_ndc(KernelGlobals *kg, ShaderData *sd, float3 P)
457 {
458   if (kernel_data.cam.type != CAMERA_PANORAMA) {
459     /* perspective / ortho */
460     if (sd->object == PRIM_NONE && kernel_data.cam.type == CAMERA_PERSPECTIVE)
461       P += camera_position(kg);
462
463     ProjectionTransform tfm = kernel_data.cam.worldtondc;
464     return transform_perspective(&tfm, P);
465   }
466   else {
467     /* panorama */
468     Transform tfm = kernel_data.cam.worldtocamera;
469
470     if (sd->object != OBJECT_NONE)
471       P = normalize(transform_point(&tfm, P));
472     else
473       P = normalize(transform_direction(&tfm, P));
474
475     float2 uv = direction_to_panorama(&kernel_data.cam, P);
476
477     return make_float3(uv.x, uv.y, 0.0f);
478   }
479 }
480
481 CCL_NAMESPACE_END