ClangFormat: apply to source, most of intern
[blender.git] / intern / cycles / render / camera.cpp
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 #include "render/camera.h"
18 #include "render/mesh.h"
19 #include "render/object.h"
20 #include "render/scene.h"
21 #include "render/tables.h"
22
23 #include "device/device.h"
24
25 #include "util/util_foreach.h"
26 #include "util/util_function.h"
27 #include "util/util_logging.h"
28 #include "util/util_math_cdf.h"
29 #include "util/util_vector.h"
30
31 /* needed for calculating differentials */
32 #include "kernel/kernel_compat_cpu.h"
33 #include "kernel/split/kernel_split_data.h"
34 #include "kernel/kernel_globals.h"
35 #include "kernel/kernel_projection.h"
36 #include "kernel/kernel_differential.h"
37 #include "kernel/kernel_montecarlo.h"
38 #include "kernel/kernel_camera.h"
39
40 CCL_NAMESPACE_BEGIN
41
42 static float shutter_curve_eval(float x, array<float> &shutter_curve)
43 {
44   if (shutter_curve.size() == 0) {
45     return 1.0f;
46   }
47
48   x *= shutter_curve.size();
49   int index = (int)x;
50   float frac = x - index;
51   if (index < shutter_curve.size() - 1) {
52     return lerp(shutter_curve[index], shutter_curve[index + 1], frac);
53   }
54   else {
55     return shutter_curve[shutter_curve.size() - 1];
56   }
57 }
58
59 NODE_DEFINE(Camera)
60 {
61   NodeType *type = NodeType::add("camera", create);
62
63   SOCKET_FLOAT(shuttertime, "Shutter Time", 1.0f);
64
65   static NodeEnum motion_position_enum;
66   motion_position_enum.insert("start", MOTION_POSITION_START);
67   motion_position_enum.insert("center", MOTION_POSITION_CENTER);
68   motion_position_enum.insert("end", MOTION_POSITION_END);
69   SOCKET_ENUM(motion_position, "Motion Position", motion_position_enum, MOTION_POSITION_CENTER);
70
71   static NodeEnum rolling_shutter_type_enum;
72   rolling_shutter_type_enum.insert("none", ROLLING_SHUTTER_NONE);
73   rolling_shutter_type_enum.insert("top", ROLLING_SHUTTER_TOP);
74   SOCKET_ENUM(rolling_shutter_type,
75               "Rolling Shutter Type",
76               rolling_shutter_type_enum,
77               ROLLING_SHUTTER_NONE);
78   SOCKET_FLOAT(rolling_shutter_duration, "Rolling Shutter Duration", 0.1f);
79
80   SOCKET_FLOAT_ARRAY(shutter_curve, "Shutter Curve", array<float>());
81
82   SOCKET_FLOAT(aperturesize, "Aperture Size", 0.0f);
83   SOCKET_FLOAT(focaldistance, "Focal Distance", 10.0f);
84   SOCKET_UINT(blades, "Blades", 0);
85   SOCKET_FLOAT(bladesrotation, "Blades Rotation", 0.0f);
86
87   SOCKET_TRANSFORM(matrix, "Matrix", transform_identity());
88   SOCKET_TRANSFORM_ARRAY(motion, "Motion", array<Transform>());
89
90   SOCKET_FLOAT(aperture_ratio, "Aperture Ratio", 1.0f);
91
92   static NodeEnum type_enum;
93   type_enum.insert("perspective", CAMERA_PERSPECTIVE);
94   type_enum.insert("orthograph", CAMERA_ORTHOGRAPHIC);
95   type_enum.insert("panorama", CAMERA_PANORAMA);
96   SOCKET_ENUM(type, "Type", type_enum, CAMERA_PERSPECTIVE);
97
98   static NodeEnum panorama_type_enum;
99   panorama_type_enum.insert("equirectangular", PANORAMA_EQUIRECTANGULAR);
100   panorama_type_enum.insert("mirrorball", PANORAMA_MIRRORBALL);
101   panorama_type_enum.insert("fisheye_equidistant", PANORAMA_FISHEYE_EQUIDISTANT);
102   panorama_type_enum.insert("fisheye_equisolid", PANORAMA_FISHEYE_EQUISOLID);
103   SOCKET_ENUM(panorama_type, "Panorama Type", panorama_type_enum, PANORAMA_EQUIRECTANGULAR);
104
105   SOCKET_FLOAT(fisheye_fov, "Fisheye FOV", M_PI_F);
106   SOCKET_FLOAT(fisheye_lens, "Fisheye Lens", 10.5f);
107   SOCKET_FLOAT(latitude_min, "Latitude Min", -M_PI_2_F);
108   SOCKET_FLOAT(latitude_max, "Latitude Max", M_PI_2_F);
109   SOCKET_FLOAT(longitude_min, "Longitude Min", -M_PI_F);
110   SOCKET_FLOAT(longitude_max, "Longitude Max", M_PI_F);
111   SOCKET_FLOAT(fov, "FOV", M_PI_4_F);
112   SOCKET_FLOAT(fov_pre, "FOV Pre", M_PI_4_F);
113   SOCKET_FLOAT(fov_post, "FOV Post", M_PI_4_F);
114
115   static NodeEnum stereo_eye_enum;
116   stereo_eye_enum.insert("none", STEREO_NONE);
117   stereo_eye_enum.insert("left", STEREO_LEFT);
118   stereo_eye_enum.insert("right", STEREO_RIGHT);
119   SOCKET_ENUM(stereo_eye, "Stereo Eye", stereo_eye_enum, STEREO_NONE);
120
121   SOCKET_FLOAT(interocular_distance, "Interocular Distance", 0.065f);
122   SOCKET_FLOAT(convergence_distance, "Convergence Distance", 30.0f * 0.065f);
123
124   SOCKET_BOOLEAN(use_pole_merge, "Use Pole Merge", false);
125   SOCKET_FLOAT(pole_merge_angle_from, "Pole Merge Angle From", 60.0f * M_PI_F / 180.0f);
126   SOCKET_FLOAT(pole_merge_angle_to, "Pole Merge Angle To", 75.0f * M_PI_F / 180.0f);
127
128   SOCKET_FLOAT(sensorwidth, "Sensor Width", 0.036f);
129   SOCKET_FLOAT(sensorheight, "Sensor Height", 0.024f);
130
131   SOCKET_FLOAT(nearclip, "Near Clip", 1e-5f);
132   SOCKET_FLOAT(farclip, "Far Clip", 1e5f);
133
134   SOCKET_FLOAT(viewplane.left, "Viewplane Left", 0);
135   SOCKET_FLOAT(viewplane.right, "Viewplane Right", 0);
136   SOCKET_FLOAT(viewplane.bottom, "Viewplane Bottom", 0);
137   SOCKET_FLOAT(viewplane.top, "Viewplane Top", 0);
138
139   SOCKET_FLOAT(border.left, "Border Left", 0);
140   SOCKET_FLOAT(border.right, "Border Right", 0);
141   SOCKET_FLOAT(border.bottom, "Border Bottom", 0);
142   SOCKET_FLOAT(border.top, "Border Top", 0);
143
144   SOCKET_FLOAT(offscreen_dicing_scale, "Offscreen Dicing Scale", 1.0f);
145
146   return type;
147 }
148
149 Camera::Camera() : Node(node_type)
150 {
151   shutter_table_offset = TABLE_OFFSET_INVALID;
152
153   width = 1024;
154   height = 512;
155   resolution = 1;
156
157   use_perspective_motion = false;
158
159   shutter_curve.resize(RAMP_TABLE_SIZE);
160   for (int i = 0; i < shutter_curve.size(); ++i) {
161     shutter_curve[i] = 1.0f;
162   }
163
164   compute_auto_viewplane();
165
166   screentoworld = projection_identity();
167   rastertoworld = projection_identity();
168   ndctoworld = projection_identity();
169   rastertocamera = projection_identity();
170   cameratoworld = transform_identity();
171   worldtoraster = projection_identity();
172
173   full_rastertocamera = projection_identity();
174
175   dx = make_float3(0.0f, 0.0f, 0.0f);
176   dy = make_float3(0.0f, 0.0f, 0.0f);
177
178   need_update = true;
179   need_device_update = true;
180   need_flags_update = true;
181   previous_need_motion = -1;
182
183   memset((void *)&kernel_camera, 0, sizeof(kernel_camera));
184 }
185
186 Camera::~Camera()
187 {
188 }
189
190 void Camera::compute_auto_viewplane()
191 {
192   if (type == CAMERA_PANORAMA) {
193     viewplane.left = 0.0f;
194     viewplane.right = 1.0f;
195     viewplane.bottom = 0.0f;
196     viewplane.top = 1.0f;
197   }
198   else {
199     float aspect = (float)width / (float)height;
200     if (width >= height) {
201       viewplane.left = -aspect;
202       viewplane.right = aspect;
203       viewplane.bottom = -1.0f;
204       viewplane.top = 1.0f;
205     }
206     else {
207       viewplane.left = -1.0f;
208       viewplane.right = 1.0f;
209       viewplane.bottom = -1.0f / aspect;
210       viewplane.top = 1.0f / aspect;
211     }
212   }
213 }
214
215 void Camera::update(Scene *scene)
216 {
217   Scene::MotionType need_motion = scene->need_motion();
218
219   if (previous_need_motion != need_motion) {
220     /* scene's motion model could have been changed since previous device
221      * camera update this could happen for example in case when one render
222      * layer has got motion pass and another not */
223     need_device_update = true;
224   }
225
226   if (!need_update)
227     return;
228
229   /* Full viewport to camera border in the viewport. */
230   Transform fulltoborder = transform_from_viewplane(viewport_camera_border);
231   Transform bordertofull = transform_inverse(fulltoborder);
232
233   /* ndc to raster */
234   Transform ndctoraster = transform_scale(width, height, 1.0f) * bordertofull;
235   Transform full_ndctoraster = transform_scale(full_width, full_height, 1.0f) * bordertofull;
236
237   /* raster to screen */
238   Transform screentondc = fulltoborder * transform_from_viewplane(viewplane);
239
240   Transform screentoraster = ndctoraster * screentondc;
241   Transform rastertoscreen = transform_inverse(screentoraster);
242   Transform full_screentoraster = full_ndctoraster * screentondc;
243   Transform full_rastertoscreen = transform_inverse(full_screentoraster);
244
245   /* screen to camera */
246   ProjectionTransform cameratoscreen;
247   if (type == CAMERA_PERSPECTIVE)
248     cameratoscreen = projection_perspective(fov, nearclip, farclip);
249   else if (type == CAMERA_ORTHOGRAPHIC)
250     cameratoscreen = projection_orthographic(nearclip, farclip);
251   else
252     cameratoscreen = projection_identity();
253
254   ProjectionTransform screentocamera = projection_inverse(cameratoscreen);
255
256   rastertocamera = screentocamera * rastertoscreen;
257   full_rastertocamera = screentocamera * full_rastertoscreen;
258   cameratoraster = screentoraster * cameratoscreen;
259
260   cameratoworld = matrix;
261   screentoworld = cameratoworld * screentocamera;
262   rastertoworld = cameratoworld * rastertocamera;
263   ndctoworld = rastertoworld * ndctoraster;
264
265   /* note we recompose matrices instead of taking inverses of the above, this
266    * is needed to avoid inverting near degenerate matrices that happen due to
267    * precision issues with large scenes */
268   worldtocamera = transform_inverse(matrix);
269   worldtoscreen = cameratoscreen * worldtocamera;
270   worldtondc = screentondc * worldtoscreen;
271   worldtoraster = ndctoraster * worldtondc;
272
273   /* differentials */
274   if (type == CAMERA_ORTHOGRAPHIC) {
275     dx = transform_perspective_direction(&rastertocamera, make_float3(1, 0, 0));
276     dy = transform_perspective_direction(&rastertocamera, make_float3(0, 1, 0));
277     full_dx = transform_perspective_direction(&full_rastertocamera, make_float3(1, 0, 0));
278     full_dy = transform_perspective_direction(&full_rastertocamera, make_float3(0, 1, 0));
279   }
280   else if (type == CAMERA_PERSPECTIVE) {
281     dx = transform_perspective(&rastertocamera, make_float3(1, 0, 0)) -
282          transform_perspective(&rastertocamera, make_float3(0, 0, 0));
283     dy = transform_perspective(&rastertocamera, make_float3(0, 1, 0)) -
284          transform_perspective(&rastertocamera, make_float3(0, 0, 0));
285     full_dx = transform_perspective(&full_rastertocamera, make_float3(1, 0, 0)) -
286               transform_perspective(&full_rastertocamera, make_float3(0, 0, 0));
287     full_dy = transform_perspective(&full_rastertocamera, make_float3(0, 1, 0)) -
288               transform_perspective(&full_rastertocamera, make_float3(0, 0, 0));
289   }
290   else {
291     dx = make_float3(0.0f, 0.0f, 0.0f);
292     dy = make_float3(0.0f, 0.0f, 0.0f);
293   }
294
295   dx = transform_direction(&cameratoworld, dx);
296   dy = transform_direction(&cameratoworld, dy);
297   full_dx = transform_direction(&cameratoworld, full_dx);
298   full_dy = transform_direction(&cameratoworld, full_dy);
299
300   if (type == CAMERA_PERSPECTIVE) {
301     float3 v = transform_perspective(&full_rastertocamera,
302                                      make_float3(full_width, full_height, 1.0f));
303
304     frustum_right_normal = normalize(make_float3(v.z, 0.0f, -v.x));
305     frustum_top_normal = normalize(make_float3(0.0f, v.z, -v.y));
306   }
307
308   /* Compute kernel camera data. */
309   KernelCamera *kcam = &kernel_camera;
310
311   /* store matrices */
312   kcam->screentoworld = screentoworld;
313   kcam->rastertoworld = rastertoworld;
314   kcam->rastertocamera = rastertocamera;
315   kcam->cameratoworld = cameratoworld;
316   kcam->worldtocamera = worldtocamera;
317   kcam->worldtoscreen = worldtoscreen;
318   kcam->worldtoraster = worldtoraster;
319   kcam->worldtondc = worldtondc;
320   kcam->ndctoworld = ndctoworld;
321
322   /* camera motion */
323   kcam->num_motion_steps = 0;
324   kcam->have_perspective_motion = 0;
325   kernel_camera_motion.clear();
326
327   /* Test if any of the transforms are actually different. */
328   bool have_motion = false;
329   for (size_t i = 0; i < motion.size(); i++) {
330     have_motion = have_motion || motion[i] != matrix;
331   }
332
333   if (need_motion == Scene::MOTION_PASS) {
334     /* TODO(sergey): Support perspective (zoom, fov) motion. */
335     if (type == CAMERA_PANORAMA) {
336       if (have_motion) {
337         kcam->motion_pass_pre = transform_inverse(motion[0]);
338         kcam->motion_pass_post = transform_inverse(motion[motion.size() - 1]);
339       }
340       else {
341         kcam->motion_pass_pre = kcam->worldtocamera;
342         kcam->motion_pass_post = kcam->worldtocamera;
343       }
344     }
345     else {
346       if (have_motion) {
347         kcam->perspective_pre = cameratoraster * transform_inverse(motion[0]);
348         kcam->perspective_post = cameratoraster * transform_inverse(motion[motion.size() - 1]);
349       }
350       else {
351         kcam->perspective_pre = worldtoraster;
352         kcam->perspective_post = worldtoraster;
353       }
354     }
355   }
356   else if (need_motion == Scene::MOTION_BLUR) {
357     if (have_motion) {
358       kernel_camera_motion.resize(motion.size());
359       transform_motion_decompose(kernel_camera_motion.data(), motion.data(), motion.size());
360       kcam->num_motion_steps = motion.size();
361     }
362
363     /* TODO(sergey): Support other types of camera. */
364     if (use_perspective_motion && type == CAMERA_PERSPECTIVE) {
365       /* TODO(sergey): Move to an utility function and de-duplicate with
366        * calculation above.
367        */
368       ProjectionTransform screentocamera_pre = projection_inverse(
369           projection_perspective(fov_pre, nearclip, farclip));
370       ProjectionTransform screentocamera_post = projection_inverse(
371           projection_perspective(fov_post, nearclip, farclip));
372
373       kcam->perspective_pre = screentocamera_pre * rastertoscreen;
374       kcam->perspective_post = screentocamera_post * rastertoscreen;
375       kcam->have_perspective_motion = 1;
376     }
377   }
378
379   /* depth of field */
380   kcam->aperturesize = aperturesize;
381   kcam->focaldistance = focaldistance;
382   kcam->blades = (blades < 3) ? 0.0f : blades;
383   kcam->bladesrotation = bladesrotation;
384
385   /* motion blur */
386   kcam->shuttertime = (need_motion == Scene::MOTION_BLUR) ? shuttertime : -1.0f;
387
388   /* type */
389   kcam->type = type;
390
391   /* anamorphic lens bokeh */
392   kcam->inv_aperture_ratio = 1.0f / aperture_ratio;
393
394   /* panorama */
395   kcam->panorama_type = panorama_type;
396   kcam->fisheye_fov = fisheye_fov;
397   kcam->fisheye_lens = fisheye_lens;
398   kcam->equirectangular_range = make_float4(longitude_min - longitude_max,
399                                             -longitude_min,
400                                             latitude_min - latitude_max,
401                                             -latitude_min + M_PI_2_F);
402
403   switch (stereo_eye) {
404     case STEREO_LEFT:
405       kcam->interocular_offset = -interocular_distance * 0.5f;
406       break;
407     case STEREO_RIGHT:
408       kcam->interocular_offset = interocular_distance * 0.5f;
409       break;
410     case STEREO_NONE:
411     default:
412       kcam->interocular_offset = 0.0f;
413       break;
414   }
415
416   kcam->convergence_distance = convergence_distance;
417   if (use_pole_merge) {
418     kcam->pole_merge_angle_from = pole_merge_angle_from;
419     kcam->pole_merge_angle_to = pole_merge_angle_to;
420   }
421   else {
422     kcam->pole_merge_angle_from = -1.0f;
423     kcam->pole_merge_angle_to = -1.0f;
424   }
425
426   /* sensor size */
427   kcam->sensorwidth = sensorwidth;
428   kcam->sensorheight = sensorheight;
429
430   /* render size */
431   kcam->width = width;
432   kcam->height = height;
433   kcam->resolution = resolution;
434
435   /* store differentials */
436   kcam->dx = float3_to_float4(dx);
437   kcam->dy = float3_to_float4(dy);
438
439   /* clipping */
440   kcam->nearclip = nearclip;
441   kcam->cliplength = (farclip == FLT_MAX) ? FLT_MAX : farclip - nearclip;
442
443   /* Camera in volume. */
444   kcam->is_inside_volume = 0;
445
446   /* Rolling shutter effect */
447   kcam->rolling_shutter_type = rolling_shutter_type;
448   kcam->rolling_shutter_duration = rolling_shutter_duration;
449
450   /* Set further update flags */
451   need_update = false;
452   need_device_update = true;
453   need_flags_update = true;
454   previous_need_motion = need_motion;
455 }
456
457 void Camera::device_update(Device * /* device */, DeviceScene *dscene, Scene *scene)
458 {
459   update(scene);
460
461   if (!need_device_update)
462     return;
463
464   scene->lookup_tables->remove_table(&shutter_table_offset);
465   if (kernel_camera.shuttertime != -1.0f) {
466     vector<float> shutter_table;
467     util_cdf_inverted(SHUTTER_TABLE_SIZE,
468                       0.0f,
469                       1.0f,
470                       function_bind(shutter_curve_eval, _1, shutter_curve),
471                       false,
472                       shutter_table);
473     shutter_table_offset = scene->lookup_tables->add_table(dscene, shutter_table);
474     kernel_camera.shutter_table_offset = (int)shutter_table_offset;
475   }
476
477   dscene->data.cam = kernel_camera;
478
479   size_t num_motion_steps = kernel_camera_motion.size();
480   if (num_motion_steps) {
481     DecomposedTransform *camera_motion = dscene->camera_motion.alloc(num_motion_steps);
482     memcpy(camera_motion, kernel_camera_motion.data(), sizeof(*camera_motion) * num_motion_steps);
483     dscene->camera_motion.copy_to_device();
484   }
485   else {
486     dscene->camera_motion.free();
487   }
488 }
489
490 void Camera::device_update_volume(Device * /*device*/, DeviceScene *dscene, Scene *scene)
491 {
492   if (!need_device_update && !need_flags_update) {
493     return;
494   }
495   KernelCamera *kcam = &dscene->data.cam;
496   BoundBox viewplane_boundbox = viewplane_bounds_get();
497   for (size_t i = 0; i < scene->objects.size(); ++i) {
498     Object *object = scene->objects[i];
499     if (object->mesh->has_volume && viewplane_boundbox.intersects(object->bounds)) {
500       /* TODO(sergey): Consider adding more grained check. */
501       VLOG(1) << "Detected camera inside volume.";
502       kcam->is_inside_volume = 1;
503       break;
504     }
505   }
506   if (!kcam->is_inside_volume) {
507     VLOG(1) << "Camera is outside of the volume.";
508   }
509   need_device_update = false;
510   need_flags_update = false;
511 }
512
513 void Camera::device_free(Device * /*device*/, DeviceScene *dscene, Scene *scene)
514 {
515   scene->lookup_tables->remove_table(&shutter_table_offset);
516   dscene->camera_motion.free();
517 }
518
519 bool Camera::modified(const Camera &cam)
520 {
521   return !Node::equals(cam);
522 }
523
524 bool Camera::motion_modified(const Camera &cam)
525 {
526   return !((motion == cam.motion) && (use_perspective_motion == cam.use_perspective_motion));
527 }
528
529 void Camera::tag_update()
530 {
531   need_update = true;
532 }
533
534 float3 Camera::transform_raster_to_world(float raster_x, float raster_y)
535 {
536   float3 D, P;
537   if (type == CAMERA_PERSPECTIVE) {
538     D = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y, 0.0f));
539     float3 Pclip = normalize(D);
540     P = make_float3(0.0f, 0.0f, 0.0f);
541     /* TODO(sergey): Aperture support? */
542     P = transform_point(&cameratoworld, P);
543     D = normalize(transform_direction(&cameratoworld, D));
544     /* TODO(sergey): Clipping is conditional in kernel, and hence it could
545      * be mistakes in here, currently leading to wrong camera-in-volume
546      * detection.
547      */
548     P += nearclip * D / Pclip.z;
549   }
550   else if (type == CAMERA_ORTHOGRAPHIC) {
551     D = make_float3(0.0f, 0.0f, 1.0f);
552     /* TODO(sergey): Aperture support? */
553     P = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y, 0.0f));
554     P = transform_point(&cameratoworld, P);
555     D = normalize(transform_direction(&cameratoworld, D));
556   }
557   else {
558     assert(!"unsupported camera type");
559   }
560   return P;
561 }
562
563 BoundBox Camera::viewplane_bounds_get()
564 {
565   /* TODO(sergey): This is all rather stupid, but is there a way to perform
566    * checks we need in a more clear and smart fasion?
567    */
568   BoundBox bounds = BoundBox::empty;
569
570   if (type == CAMERA_PANORAMA) {
571     if (use_spherical_stereo == false) {
572       bounds.grow(make_float3(cameratoworld.x.w, cameratoworld.y.w, cameratoworld.z.w));
573     }
574     else {
575       float half_eye_distance = interocular_distance * 0.5f;
576
577       bounds.grow(make_float3(
578           cameratoworld.x.w + half_eye_distance, cameratoworld.y.w, cameratoworld.z.w));
579
580       bounds.grow(make_float3(
581           cameratoworld.z.w, cameratoworld.y.w + half_eye_distance, cameratoworld.z.w));
582
583       bounds.grow(make_float3(
584           cameratoworld.x.w - half_eye_distance, cameratoworld.y.w, cameratoworld.z.w));
585
586       bounds.grow(make_float3(
587           cameratoworld.x.w, cameratoworld.y.w - half_eye_distance, cameratoworld.z.w));
588     }
589   }
590   else {
591     bounds.grow(transform_raster_to_world(0.0f, 0.0f));
592     bounds.grow(transform_raster_to_world(0.0f, (float)height));
593     bounds.grow(transform_raster_to_world((float)width, (float)height));
594     bounds.grow(transform_raster_to_world((float)width, 0.0f));
595     if (type == CAMERA_PERSPECTIVE) {
596       /* Center point has the most distance in local Z axis,
597        * use it to construct bounding box/
598        */
599       bounds.grow(transform_raster_to_world(0.5f * width, 0.5f * height));
600     }
601   }
602   return bounds;
603 }
604
605 float Camera::world_to_raster_size(float3 P)
606 {
607   float res = 1.0f;
608
609   if (type == CAMERA_ORTHOGRAPHIC) {
610     res = min(len(full_dx), len(full_dy));
611
612     if (offscreen_dicing_scale > 1.0f) {
613       float3 p = transform_point(&worldtocamera, P);
614       float3 v = transform_perspective(&full_rastertocamera,
615                                        make_float3(full_width, full_height, 0.0f));
616
617       /* Create point clamped to frustum */
618       float3 c;
619       c.x = max(-v.x, min(v.x, p.x));
620       c.y = max(-v.y, min(v.y, p.y));
621       c.z = max(0.0f, p.z);
622
623       float f_dist = len(p - c) / sqrtf((v.x * v.x + v.y * v.y) * 0.5f);
624
625       if (f_dist > 0.0f) {
626         res += res * f_dist * (offscreen_dicing_scale - 1.0f);
627       }
628     }
629   }
630   else if (type == CAMERA_PERSPECTIVE) {
631     /* Calculate as if point is directly ahead of the camera. */
632     float3 raster = make_float3(0.5f * full_width, 0.5f * full_height, 0.0f);
633     float3 Pcamera = transform_perspective(&full_rastertocamera, raster);
634
635     /* dDdx */
636     float3 Ddiff = transform_direction(&cameratoworld, Pcamera);
637     float3 dx = len_squared(full_dx) < len_squared(full_dy) ? full_dx : full_dy;
638     float3 dDdx = normalize(Ddiff + dx) - normalize(Ddiff);
639
640     /* dPdx */
641     float dist = len(transform_point(&worldtocamera, P));
642     float3 D = normalize(Ddiff);
643     res = len(dist * dDdx - dot(dist * dDdx, D) * D);
644
645     /* Decent approx distance to frustum (doesn't handle corners correctly, but not that big of a deal) */
646     float f_dist = 0.0f;
647
648     if (offscreen_dicing_scale > 1.0f) {
649       float3 p = transform_point(&worldtocamera, P);
650
651       /* Distance from the four planes */
652       float r = dot(p, frustum_right_normal);
653       float t = dot(p, frustum_top_normal);
654       p = make_float3(-p.x, -p.y, p.z);
655       float l = dot(p, frustum_right_normal);
656       float b = dot(p, frustum_top_normal);
657       p = make_float3(-p.x, -p.y, p.z);
658
659       if (r <= 0.0f && l <= 0.0f && t <= 0.0f && b <= 0.0f) {
660         /* Point is inside frustum */
661         f_dist = 0.0f;
662       }
663       else if (r > 0.0f && l > 0.0f && t > 0.0f && b > 0.0f) {
664         /* Point is behind frustum */
665         f_dist = len(p);
666       }
667       else {
668         /* Point may be behind or off to the side, need to check */
669         float3 along_right = make_float3(-frustum_right_normal.z, 0.0f, frustum_right_normal.x);
670         float3 along_left = make_float3(frustum_right_normal.z, 0.0f, frustum_right_normal.x);
671         float3 along_top = make_float3(0.0f, -frustum_top_normal.z, frustum_top_normal.y);
672         float3 along_bottom = make_float3(0.0f, frustum_top_normal.z, frustum_top_normal.y);
673
674         float dist[] = {r, l, t, b};
675         float3 along[] = {along_right, along_left, along_top, along_bottom};
676
677         bool test_o = false;
678
679         float *d = dist;
680         float3 *a = along;
681         for (int i = 0; i < 4; i++, d++, a++) {
682           /* Test if we should check this side at all */
683           if (*d > 0.0f) {
684             if (dot(p, *a) >= 0.0f) {
685               /* We are in front of the back edge of this side of the frustum */
686               f_dist = max(f_dist, *d);
687             }
688             else {
689               /* Possibly far enough behind the frustum to use distance to origin instead of edge */
690               test_o = true;
691             }
692           }
693         }
694
695         if (test_o) {
696           f_dist = (f_dist > 0) ? min(f_dist, len(p)) : len(p);
697         }
698       }
699
700       if (f_dist > 0.0f) {
701         res += len(dDdx - dot(dDdx, D) * D) * f_dist * (offscreen_dicing_scale - 1.0f);
702       }
703     }
704   }
705   else if (type == CAMERA_PANORAMA) {
706     float3 D = transform_point(&worldtocamera, P);
707     float dist = len(D);
708
709     Ray ray = {{0}};
710
711     /* Distortion can become so great that the results become meaningless, there
712      * may be a better way to do this, but calculating differentials from the
713      * point directly ahead seems to produce good enough results. */
714 #if 0
715     float2 dir = direction_to_panorama(&kernel_camera, kernel_camera_motion.data(), normalize(D));
716     float3 raster = transform_perspective(&full_cameratoraster, make_float3(dir.x, dir.y, 0.0f));
717
718     ray.t = 1.0f;
719     camera_sample_panorama(&kernel_camera, kernel_camera_motion.data(), raster.x, raster.y, 0.0f, 0.0f, &ray);
720     if(ray.t == 0.0f) {
721       /* No differentials, just use from directly ahead. */
722       camera_sample_panorama(&kernel_camera, kernel_camera_motion.data(), 0.5f*full_width, 0.5f*full_height, 0.0f, 0.0f, &ray);
723     }
724 #else
725     camera_sample_panorama(&kernel_camera,
726                            kernel_camera_motion.data(),
727                            0.5f * full_width,
728                            0.5f * full_height,
729                            0.0f,
730                            0.0f,
731                            &ray);
732 #endif
733
734     differential_transfer(&ray.dP, ray.dP, ray.D, ray.dD, ray.D, dist);
735
736     return max(len(ray.dP.dx), len(ray.dP.dy));
737   }
738
739   return res;
740 }
741
742 bool Camera::use_motion() const
743 {
744   return motion.size() > 1;
745 }
746
747 float Camera::motion_time(int step) const
748 {
749   return (use_motion()) ? 2.0f * step / (motion.size() - 1) - 1.0f : 0.0f;
750 }
751
752 int Camera::motion_step(float time) const
753 {
754   if (use_motion()) {
755     for (int step = 0; step < motion.size(); step++) {
756       if (time == motion_time(step)) {
757         return step;
758       }
759     }
760   }
761
762   return -1;
763 }
764
765 CCL_NAMESPACE_END