Fix T70177: Crash when calling to_track_quat() without arguments
[blender.git] / intern / cycles / blender / blender_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/scene.h"
19
20 #include "blender/blender_sync.h"
21 #include "blender/blender_util.h"
22
23 #include "util/util_logging.h"
24
25 CCL_NAMESPACE_BEGIN
26
27 /* Blender Camera Intermediate: we first convert both the offline and 3d view
28  * render camera to this, and from there convert to our native camera format. */
29
30 struct BlenderCamera {
31   float nearclip;
32   float farclip;
33
34   CameraType type;
35   float ortho_scale;
36
37   float lens;
38   float shuttertime;
39   Camera::MotionPosition motion_position;
40   array<float> shutter_curve;
41
42   Camera::RollingShutterType rolling_shutter_type;
43   float rolling_shutter_duration;
44
45   float aperturesize;
46   uint apertureblades;
47   float aperturerotation;
48   float focaldistance;
49
50   float2 shift;
51   float2 offset;
52   float zoom;
53
54   float2 pixelaspect;
55
56   float aperture_ratio;
57
58   PanoramaType panorama_type;
59   float fisheye_fov;
60   float fisheye_lens;
61   float latitude_min;
62   float latitude_max;
63   float longitude_min;
64   float longitude_max;
65   bool use_spherical_stereo;
66   float interocular_distance;
67   float convergence_distance;
68   bool use_pole_merge;
69   float pole_merge_angle_from;
70   float pole_merge_angle_to;
71
72   enum { AUTO, HORIZONTAL, VERTICAL } sensor_fit;
73   float sensor_width;
74   float sensor_height;
75
76   int full_width;
77   int full_height;
78
79   BoundBox2D border;
80   BoundBox2D pano_viewplane;
81   BoundBox2D viewport_camera_border;
82
83   Transform matrix;
84
85   float offscreen_dicing_scale;
86
87   int motion_steps;
88 };
89
90 static void blender_camera_init(BlenderCamera *bcam, BL::RenderSettings &b_render)
91 {
92   memset((void *)bcam, 0, sizeof(BlenderCamera));
93
94   bcam->nearclip = 1e-5f;
95   bcam->farclip = 1e5f;
96
97   bcam->type = CAMERA_PERSPECTIVE;
98   bcam->ortho_scale = 1.0f;
99
100   bcam->lens = 50.0f;
101   bcam->shuttertime = 1.0f;
102
103   bcam->rolling_shutter_type = Camera::ROLLING_SHUTTER_NONE;
104   bcam->rolling_shutter_duration = 0.1f;
105
106   bcam->aperturesize = 0.0f;
107   bcam->apertureblades = 0;
108   bcam->aperturerotation = 0.0f;
109   bcam->focaldistance = 10.0f;
110
111   bcam->zoom = 1.0f;
112   bcam->pixelaspect = make_float2(1.0f, 1.0f);
113   bcam->aperture_ratio = 1.0f;
114
115   bcam->sensor_width = 36.0f;
116   bcam->sensor_height = 24.0f;
117   bcam->sensor_fit = BlenderCamera::AUTO;
118   bcam->motion_position = Camera::MOTION_POSITION_CENTER;
119   bcam->border.right = 1.0f;
120   bcam->border.top = 1.0f;
121   bcam->pano_viewplane.right = 1.0f;
122   bcam->pano_viewplane.top = 1.0f;
123   bcam->viewport_camera_border.right = 1.0f;
124   bcam->viewport_camera_border.top = 1.0f;
125   bcam->offscreen_dicing_scale = 1.0f;
126   bcam->matrix = transform_identity();
127
128   /* render resolution */
129   bcam->full_width = render_resolution_x(b_render);
130   bcam->full_height = render_resolution_y(b_render);
131 }
132
133 static float blender_camera_focal_distance(BL::RenderEngine &b_engine,
134                                            BL::Object &b_ob,
135                                            BL::Camera &b_camera,
136                                            BlenderCamera *bcam)
137 {
138   BL::Object b_dof_object = b_camera.dof().focus_object();
139
140   if (!b_dof_object)
141     return b_camera.dof().focus_distance();
142
143   /* for dof object, return distance along camera Z direction */
144   BL::Array<float, 16> b_ob_matrix;
145   b_engine.camera_model_matrix(b_ob, bcam->use_spherical_stereo, b_ob_matrix);
146   Transform obmat = transform_clear_scale(get_transform(b_ob_matrix));
147   Transform dofmat = get_transform(b_dof_object.matrix_world());
148   float3 view_dir = normalize(transform_get_column(&obmat, 2));
149   float3 dof_dir = transform_get_column(&obmat, 3) - transform_get_column(&dofmat, 3);
150   return fabsf(dot(view_dir, dof_dir));
151 }
152
153 static void blender_camera_from_object(BlenderCamera *bcam,
154                                        BL::RenderEngine &b_engine,
155                                        BL::Object &b_ob,
156                                        bool skip_panorama = false)
157 {
158   BL::ID b_ob_data = b_ob.data();
159
160   if (b_ob_data.is_a(&RNA_Camera)) {
161     BL::Camera b_camera(b_ob_data);
162     PointerRNA ccamera = RNA_pointer_get(&b_camera.ptr, "cycles");
163
164     bcam->nearclip = b_camera.clip_start();
165     bcam->farclip = b_camera.clip_end();
166
167     switch (b_camera.type()) {
168       case BL::Camera::type_ORTHO:
169         bcam->type = CAMERA_ORTHOGRAPHIC;
170         break;
171       case BL::Camera::type_PANO:
172         if (!skip_panorama)
173           bcam->type = CAMERA_PANORAMA;
174         else
175           bcam->type = CAMERA_PERSPECTIVE;
176         break;
177       case BL::Camera::type_PERSP:
178       default:
179         bcam->type = CAMERA_PERSPECTIVE;
180         break;
181     }
182
183     bcam->panorama_type = (PanoramaType)get_enum(
184         ccamera, "panorama_type", PANORAMA_NUM_TYPES, PANORAMA_EQUIRECTANGULAR);
185
186     bcam->fisheye_fov = RNA_float_get(&ccamera, "fisheye_fov");
187     bcam->fisheye_lens = RNA_float_get(&ccamera, "fisheye_lens");
188     bcam->latitude_min = RNA_float_get(&ccamera, "latitude_min");
189     bcam->latitude_max = RNA_float_get(&ccamera, "latitude_max");
190     bcam->longitude_min = RNA_float_get(&ccamera, "longitude_min");
191     bcam->longitude_max = RNA_float_get(&ccamera, "longitude_max");
192
193     bcam->interocular_distance = b_camera.stereo().interocular_distance();
194     if (b_camera.stereo().convergence_mode() == BL::CameraStereoData::convergence_mode_PARALLEL) {
195       bcam->convergence_distance = FLT_MAX;
196     }
197     else {
198       bcam->convergence_distance = b_camera.stereo().convergence_distance();
199     }
200     bcam->use_spherical_stereo = b_engine.use_spherical_stereo(b_ob);
201
202     bcam->use_pole_merge = b_camera.stereo().use_pole_merge();
203     bcam->pole_merge_angle_from = b_camera.stereo().pole_merge_angle_from();
204     bcam->pole_merge_angle_to = b_camera.stereo().pole_merge_angle_to();
205
206     bcam->ortho_scale = b_camera.ortho_scale();
207
208     bcam->lens = b_camera.lens();
209
210     if (b_camera.dof().use_dof()) {
211       /* allow f/stop number to change aperture_size but still
212        * give manual control over aperture radius */
213       float fstop = b_camera.dof().aperture_fstop();
214       fstop = max(fstop, 1e-5f);
215
216       if (bcam->type == CAMERA_ORTHOGRAPHIC)
217         bcam->aperturesize = 1.0f / (2.0f * fstop);
218       else
219         bcam->aperturesize = (bcam->lens * 1e-3f) / (2.0f * fstop);
220
221       bcam->apertureblades = b_camera.dof().aperture_blades();
222       bcam->aperturerotation = b_camera.dof().aperture_rotation();
223       bcam->focaldistance = blender_camera_focal_distance(b_engine, b_ob, b_camera, bcam);
224       bcam->aperture_ratio = b_camera.dof().aperture_ratio();
225     }
226     else {
227       /* DOF is turned of for the camera. */
228       bcam->aperturesize = 0.0f;
229       bcam->apertureblades = 0;
230       bcam->aperturerotation = 0.0f;
231       bcam->focaldistance = 0.0f;
232       bcam->aperture_ratio = 1.0f;
233     }
234
235     bcam->shift.x = b_engine.camera_shift_x(b_ob, bcam->use_spherical_stereo);
236     bcam->shift.y = b_camera.shift_y();
237
238     bcam->sensor_width = b_camera.sensor_width();
239     bcam->sensor_height = b_camera.sensor_height();
240
241     if (b_camera.sensor_fit() == BL::Camera::sensor_fit_AUTO)
242       bcam->sensor_fit = BlenderCamera::AUTO;
243     else if (b_camera.sensor_fit() == BL::Camera::sensor_fit_HORIZONTAL)
244       bcam->sensor_fit = BlenderCamera::HORIZONTAL;
245     else
246       bcam->sensor_fit = BlenderCamera::VERTICAL;
247   }
248   else if (b_ob_data.is_a(&RNA_Light)) {
249     /* Can also look through spot light. */
250     BL::SpotLight b_light(b_ob_data);
251     float lens = 16.0f / tanf(b_light.spot_size() * 0.5f);
252     if (lens > 0.0f) {
253       bcam->lens = lens;
254     }
255   }
256
257   bcam->motion_steps = object_motion_steps(b_ob, b_ob);
258 }
259
260 static Transform blender_camera_matrix(const Transform &tfm,
261                                        const CameraType type,
262                                        const PanoramaType panorama_type)
263 {
264   Transform result;
265
266   if (type == CAMERA_PANORAMA) {
267     if (panorama_type == PANORAMA_MIRRORBALL) {
268       /* Mirror ball camera is looking into the negative Y direction
269        * which matches texture mirror ball mapping.
270        */
271       result = tfm * make_transform(
272                          1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f);
273     }
274     else {
275       /* Make it so environment camera needs to be pointed in the direction
276        * of the positive x-axis to match an environment texture, this way
277        * it is looking at the center of the texture
278        */
279       result = tfm * make_transform(
280                          0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f);
281     }
282   }
283   else {
284     /* note the blender camera points along the negative z-axis */
285     result = tfm * transform_scale(1.0f, 1.0f, -1.0f);
286   }
287
288   return transform_clear_scale(result);
289 }
290
291 static void blender_camera_viewplane(BlenderCamera *bcam,
292                                      int width,
293                                      int height,
294                                      BoundBox2D *viewplane,
295                                      float *aspectratio,
296                                      float *sensor_size)
297 {
298   /* dimensions */
299   float xratio = (float)width * bcam->pixelaspect.x;
300   float yratio = (float)height * bcam->pixelaspect.y;
301
302   /* compute x/y aspect and ratio */
303   float xaspect, yaspect;
304   bool horizontal_fit;
305
306   /* sensor fitting */
307   if (bcam->sensor_fit == BlenderCamera::AUTO) {
308     horizontal_fit = (xratio > yratio);
309     if (sensor_size != NULL) {
310       *sensor_size = bcam->sensor_width;
311     }
312   }
313   else if (bcam->sensor_fit == BlenderCamera::HORIZONTAL) {
314     horizontal_fit = true;
315     if (sensor_size != NULL) {
316       *sensor_size = bcam->sensor_width;
317     }
318   }
319   else {
320     horizontal_fit = false;
321     if (sensor_size != NULL) {
322       *sensor_size = bcam->sensor_height;
323     }
324   }
325
326   if (horizontal_fit) {
327     if (aspectratio != NULL) {
328       *aspectratio = xratio / yratio;
329     }
330     xaspect = *aspectratio;
331     yaspect = 1.0f;
332   }
333   else {
334     if (aspectratio != NULL) {
335       *aspectratio = yratio / xratio;
336     }
337     xaspect = 1.0f;
338     yaspect = *aspectratio;
339   }
340
341   /* modify aspect for orthographic scale */
342   if (bcam->type == CAMERA_ORTHOGRAPHIC) {
343     xaspect = xaspect * bcam->ortho_scale / (*aspectratio * 2.0f);
344     yaspect = yaspect * bcam->ortho_scale / (*aspectratio * 2.0f);
345     if (aspectratio != NULL) {
346       *aspectratio = bcam->ortho_scale / 2.0f;
347     }
348   }
349
350   if (bcam->type == CAMERA_PANORAMA) {
351     /* set viewplane */
352     if (viewplane != NULL) {
353       *viewplane = bcam->pano_viewplane;
354     }
355   }
356   else {
357     /* set viewplane */
358     if (viewplane != NULL) {
359       viewplane->left = -xaspect;
360       viewplane->right = xaspect;
361       viewplane->bottom = -yaspect;
362       viewplane->top = yaspect;
363
364       /* zoom for 3d camera view */
365       *viewplane = (*viewplane) * bcam->zoom;
366
367       /* modify viewplane with camera shift and 3d camera view offset */
368       float dx = 2.0f * (*aspectratio * bcam->shift.x + bcam->offset.x * xaspect * 2.0f);
369       float dy = 2.0f * (*aspectratio * bcam->shift.y + bcam->offset.y * yaspect * 2.0f);
370
371       viewplane->left += dx;
372       viewplane->right += dx;
373       viewplane->bottom += dy;
374       viewplane->top += dy;
375     }
376   }
377 }
378
379 static void blender_camera_sync(Camera *cam,
380                                 BlenderCamera *bcam,
381                                 int width,
382                                 int height,
383                                 const char *viewname,
384                                 PointerRNA *cscene)
385 {
386   /* copy camera to compare later */
387   Camera prevcam = *cam;
388   float aspectratio, sensor_size;
389
390   /* viewplane */
391   blender_camera_viewplane(bcam, width, height, &cam->viewplane, &aspectratio, &sensor_size);
392
393   cam->width = bcam->full_width;
394   cam->height = bcam->full_height;
395
396   cam->full_width = width;
397   cam->full_height = height;
398
399   /* panorama sensor */
400   if (bcam->type == CAMERA_PANORAMA && bcam->panorama_type == PANORAMA_FISHEYE_EQUISOLID) {
401     float fit_xratio = (float)bcam->full_width * bcam->pixelaspect.x;
402     float fit_yratio = (float)bcam->full_height * bcam->pixelaspect.y;
403     bool horizontal_fit;
404     float sensor_size;
405
406     if (bcam->sensor_fit == BlenderCamera::AUTO) {
407       horizontal_fit = (fit_xratio > fit_yratio);
408       sensor_size = bcam->sensor_width;
409     }
410     else if (bcam->sensor_fit == BlenderCamera::HORIZONTAL) {
411       horizontal_fit = true;
412       sensor_size = bcam->sensor_width;
413     }
414     else { /* vertical */
415       horizontal_fit = false;
416       sensor_size = bcam->sensor_height;
417     }
418
419     if (horizontal_fit) {
420       cam->sensorwidth = sensor_size;
421       cam->sensorheight = sensor_size * fit_yratio / fit_xratio;
422     }
423     else {
424       cam->sensorwidth = sensor_size * fit_xratio / fit_yratio;
425       cam->sensorheight = sensor_size;
426     }
427   }
428
429   /* clipping distances */
430   cam->nearclip = bcam->nearclip;
431   cam->farclip = bcam->farclip;
432
433   /* type */
434   cam->type = bcam->type;
435
436   /* panorama */
437   cam->panorama_type = bcam->panorama_type;
438   cam->fisheye_fov = bcam->fisheye_fov;
439   cam->fisheye_lens = bcam->fisheye_lens;
440   cam->latitude_min = bcam->latitude_min;
441   cam->latitude_max = bcam->latitude_max;
442
443   cam->longitude_min = bcam->longitude_min;
444   cam->longitude_max = bcam->longitude_max;
445
446   /* panorama stereo */
447   cam->interocular_distance = bcam->interocular_distance;
448   cam->convergence_distance = bcam->convergence_distance;
449   cam->use_spherical_stereo = bcam->use_spherical_stereo;
450
451   if (cam->use_spherical_stereo) {
452     if (strcmp(viewname, "left") == 0)
453       cam->stereo_eye = Camera::STEREO_LEFT;
454     else if (strcmp(viewname, "right") == 0)
455       cam->stereo_eye = Camera::STEREO_RIGHT;
456     else
457       cam->stereo_eye = Camera::STEREO_NONE;
458   }
459
460   cam->use_pole_merge = bcam->use_pole_merge;
461   cam->pole_merge_angle_from = bcam->pole_merge_angle_from;
462   cam->pole_merge_angle_to = bcam->pole_merge_angle_to;
463
464   /* anamorphic lens bokeh */
465   cam->aperture_ratio = bcam->aperture_ratio;
466
467   /* perspective */
468   cam->fov = 2.0f * atanf((0.5f * sensor_size) / bcam->lens / aspectratio);
469   cam->focaldistance = bcam->focaldistance;
470   cam->aperturesize = bcam->aperturesize;
471   cam->blades = bcam->apertureblades;
472   cam->bladesrotation = bcam->aperturerotation;
473
474   /* transform */
475   cam->matrix = blender_camera_matrix(bcam->matrix, bcam->type, bcam->panorama_type);
476   cam->motion.clear();
477   cam->motion.resize(bcam->motion_steps, cam->matrix);
478   cam->use_perspective_motion = false;
479   cam->shuttertime = bcam->shuttertime;
480   cam->fov_pre = cam->fov;
481   cam->fov_post = cam->fov;
482   cam->motion_position = bcam->motion_position;
483
484   cam->rolling_shutter_type = bcam->rolling_shutter_type;
485   cam->rolling_shutter_duration = bcam->rolling_shutter_duration;
486
487   cam->shutter_curve = bcam->shutter_curve;
488
489   /* border */
490   cam->border = bcam->border;
491   cam->viewport_camera_border = bcam->viewport_camera_border;
492
493   bcam->offscreen_dicing_scale = RNA_float_get(cscene, "offscreen_dicing_scale");
494   cam->offscreen_dicing_scale = bcam->offscreen_dicing_scale;
495
496   /* set update flag */
497   if (cam->modified(prevcam))
498     cam->tag_update();
499 }
500
501 /* Sync Render Camera */
502
503 void BlenderSync::sync_camera(BL::RenderSettings &b_render,
504                               BL::Object &b_override,
505                               int width,
506                               int height,
507                               const char *viewname)
508 {
509   BlenderCamera bcam;
510   blender_camera_init(&bcam, b_render);
511
512   /* pixel aspect */
513   bcam.pixelaspect.x = b_render.pixel_aspect_x();
514   bcam.pixelaspect.y = b_render.pixel_aspect_y();
515   bcam.shuttertime = b_render.motion_blur_shutter();
516
517   BL::CurveMapping b_shutter_curve(b_render.motion_blur_shutter_curve());
518   curvemapping_to_array(b_shutter_curve, bcam.shutter_curve, RAMP_TABLE_SIZE);
519
520   PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
521   bcam.motion_position = (Camera::MotionPosition)get_enum(cscene,
522                                                           "motion_blur_position",
523                                                           Camera::MOTION_NUM_POSITIONS,
524                                                           Camera::MOTION_POSITION_CENTER);
525   bcam.rolling_shutter_type = (Camera::RollingShutterType)get_enum(
526       cscene,
527       "rolling_shutter_type",
528       Camera::ROLLING_SHUTTER_NUM_TYPES,
529       Camera::ROLLING_SHUTTER_NONE);
530   bcam.rolling_shutter_duration = RNA_float_get(&cscene, "rolling_shutter_duration");
531
532   /* border */
533   if (b_render.use_border()) {
534     bcam.border.left = b_render.border_min_x();
535     bcam.border.right = b_render.border_max_x();
536     bcam.border.bottom = b_render.border_min_y();
537     bcam.border.top = b_render.border_max_y();
538   }
539
540   /* camera object */
541   BL::Object b_ob = b_scene.camera();
542
543   if (b_override)
544     b_ob = b_override;
545
546   if (b_ob) {
547     BL::Array<float, 16> b_ob_matrix;
548     blender_camera_from_object(&bcam, b_engine, b_ob);
549     b_engine.camera_model_matrix(b_ob, bcam.use_spherical_stereo, b_ob_matrix);
550     bcam.matrix = get_transform(b_ob_matrix);
551   }
552
553   /* sync */
554   Camera *cam = scene->camera;
555   blender_camera_sync(cam, &bcam, width, height, viewname, &cscene);
556
557   /* dicing camera */
558   b_ob = BL::Object(RNA_pointer_get(&cscene, "dicing_camera"));
559   if (b_ob) {
560     BL::Array<float, 16> b_ob_matrix;
561     blender_camera_from_object(&bcam, b_engine, b_ob);
562     b_engine.camera_model_matrix(b_ob, bcam.use_spherical_stereo, b_ob_matrix);
563     bcam.matrix = get_transform(b_ob_matrix);
564
565     blender_camera_sync(scene->dicing_camera, &bcam, width, height, viewname, &cscene);
566   }
567   else {
568     *scene->dicing_camera = *cam;
569   }
570 }
571
572 void BlenderSync::sync_camera_motion(
573     BL::RenderSettings &b_render, BL::Object &b_ob, int width, int height, float motion_time)
574 {
575   if (!b_ob)
576     return;
577
578   Camera *cam = scene->camera;
579   BL::Array<float, 16> b_ob_matrix;
580   b_engine.camera_model_matrix(b_ob, cam->use_spherical_stereo, b_ob_matrix);
581   Transform tfm = get_transform(b_ob_matrix);
582   tfm = blender_camera_matrix(tfm, cam->type, cam->panorama_type);
583
584   if (motion_time == 0.0f) {
585     /* When motion blur is not centered in frame, cam->matrix gets reset. */
586     cam->matrix = tfm;
587   }
588
589   /* Set transform in motion array. */
590   int motion_step = cam->motion_step(motion_time);
591   if (motion_step >= 0) {
592     cam->motion[motion_step] = tfm;
593   }
594
595   if (cam->type == CAMERA_PERSPECTIVE) {
596     BlenderCamera bcam;
597     float aspectratio, sensor_size;
598     blender_camera_init(&bcam, b_render);
599
600     /* TODO(sergey): Consider making it a part of blender_camera_init(). */
601     bcam.pixelaspect.x = b_render.pixel_aspect_x();
602     bcam.pixelaspect.y = b_render.pixel_aspect_y();
603
604     blender_camera_from_object(&bcam, b_engine, b_ob);
605     blender_camera_viewplane(&bcam, width, height, NULL, &aspectratio, &sensor_size);
606     /* TODO(sergey): De-duplicate calculation with camera sync. */
607     float fov = 2.0f * atanf((0.5f * sensor_size) / bcam.lens / aspectratio);
608     if (fov != cam->fov) {
609       VLOG(1) << "Camera " << b_ob.name() << " FOV change detected.";
610       if (motion_time == 0.0f) {
611         cam->fov = fov;
612       }
613       else if (motion_time == -1.0f) {
614         cam->fov_pre = fov;
615         cam->use_perspective_motion = true;
616       }
617       else if (motion_time == 1.0f) {
618         cam->fov_post = fov;
619         cam->use_perspective_motion = true;
620       }
621     }
622   }
623 }
624
625 /* Sync 3D View Camera */
626
627 static void blender_camera_view_subset(BL::RenderEngine &b_engine,
628                                        BL::RenderSettings &b_render,
629                                        BL::Scene &b_scene,
630                                        BL::Object &b_ob,
631                                        BL::SpaceView3D &b_v3d,
632                                        BL::RegionView3D &b_rv3d,
633                                        int width,
634                                        int height,
635                                        BoundBox2D *view_box,
636                                        BoundBox2D *cam_box);
637
638 static void blender_camera_from_view(BlenderCamera *bcam,
639                                      BL::RenderEngine &b_engine,
640                                      BL::Scene &b_scene,
641                                      BL::SpaceView3D &b_v3d,
642                                      BL::RegionView3D &b_rv3d,
643                                      int width,
644                                      int height,
645                                      bool skip_panorama = false)
646 {
647   /* 3d view parameters */
648   bcam->nearclip = b_v3d.clip_start();
649   bcam->farclip = b_v3d.clip_end();
650   bcam->lens = b_v3d.lens();
651   bcam->shuttertime = b_scene.render().motion_blur_shutter();
652
653   BL::CurveMapping b_shutter_curve(b_scene.render().motion_blur_shutter_curve());
654   curvemapping_to_array(b_shutter_curve, bcam->shutter_curve, RAMP_TABLE_SIZE);
655
656   if (b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_CAMERA) {
657     /* camera view */
658     BL::Object b_ob = (b_v3d.use_local_camera()) ? b_v3d.camera() : b_scene.camera();
659
660     if (b_ob) {
661       blender_camera_from_object(bcam, b_engine, b_ob, skip_panorama);
662
663       if (!skip_panorama && bcam->type == CAMERA_PANORAMA) {
664         /* in panorama camera view, we map viewplane to camera border */
665         BoundBox2D view_box, cam_box;
666
667         BL::RenderSettings b_render_settings(b_scene.render());
668         blender_camera_view_subset(b_engine,
669                                    b_render_settings,
670                                    b_scene,
671                                    b_ob,
672                                    b_v3d,
673                                    b_rv3d,
674                                    width,
675                                    height,
676                                    &view_box,
677                                    &cam_box);
678
679         bcam->pano_viewplane = view_box.make_relative_to(cam_box);
680       }
681       else {
682         /* magic zoom formula */
683         bcam->zoom = (float)b_rv3d.view_camera_zoom();
684         bcam->zoom = (1.41421f + bcam->zoom / 50.0f);
685         bcam->zoom *= bcam->zoom;
686         bcam->zoom = 2.0f / bcam->zoom;
687
688         /* offset */
689         bcam->offset = get_float2(b_rv3d.view_camera_offset());
690       }
691     }
692   }
693   else if (b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_ORTHO) {
694     /* orthographic view */
695     bcam->farclip *= 0.5f;
696     bcam->nearclip = -bcam->farclip;
697
698     float sensor_size;
699     if (bcam->sensor_fit == BlenderCamera::VERTICAL)
700       sensor_size = bcam->sensor_height;
701     else
702       sensor_size = bcam->sensor_width;
703
704     bcam->type = CAMERA_ORTHOGRAPHIC;
705     bcam->ortho_scale = b_rv3d.view_distance() * sensor_size / b_v3d.lens();
706   }
707
708   bcam->zoom *= 2.0f;
709
710   /* 3d view transform */
711   bcam->matrix = transform_inverse(get_transform(b_rv3d.view_matrix()));
712 }
713
714 static void blender_camera_view_subset(BL::RenderEngine &b_engine,
715                                        BL::RenderSettings &b_render,
716                                        BL::Scene &b_scene,
717                                        BL::Object &b_ob,
718                                        BL::SpaceView3D &b_v3d,
719                                        BL::RegionView3D &b_rv3d,
720                                        int width,
721                                        int height,
722                                        BoundBox2D *view_box,
723                                        BoundBox2D *cam_box)
724 {
725   BoundBox2D cam, view;
726   float view_aspect, cam_aspect, sensor_size;
727
728   /* get viewport viewplane */
729   BlenderCamera view_bcam;
730   blender_camera_init(&view_bcam, b_render);
731   blender_camera_from_view(&view_bcam, b_engine, b_scene, b_v3d, b_rv3d, width, height, true);
732
733   blender_camera_viewplane(&view_bcam, width, height, &view, &view_aspect, &sensor_size);
734
735   /* get camera viewplane */
736   BlenderCamera cam_bcam;
737   blender_camera_init(&cam_bcam, b_render);
738   blender_camera_from_object(&cam_bcam, b_engine, b_ob, true);
739
740   blender_camera_viewplane(
741       &cam_bcam, cam_bcam.full_width, cam_bcam.full_height, &cam, &cam_aspect, &sensor_size);
742
743   /* return */
744   *view_box = view * (1.0f / view_aspect);
745   *cam_box = cam * (1.0f / cam_aspect);
746 }
747
748 static void blender_camera_border_subset(BL::RenderEngine &b_engine,
749                                          BL::RenderSettings &b_render,
750                                          BL::Scene &b_scene,
751                                          BL::SpaceView3D &b_v3d,
752                                          BL::RegionView3D &b_rv3d,
753                                          BL::Object &b_ob,
754                                          int width,
755                                          int height,
756                                          const BoundBox2D &border,
757                                          BoundBox2D *result)
758 {
759   /* Determine camera viewport subset. */
760   BoundBox2D view_box, cam_box;
761   blender_camera_view_subset(
762       b_engine, b_render, b_scene, b_ob, b_v3d, b_rv3d, width, height, &view_box, &cam_box);
763
764   /* Determine viewport subset matching given border. */
765   cam_box = cam_box.make_relative_to(view_box);
766   *result = cam_box.subset(border);
767 }
768
769 static void blender_camera_border(BlenderCamera *bcam,
770                                   BL::RenderEngine &b_engine,
771                                   BL::RenderSettings &b_render,
772                                   BL::Scene &b_scene,
773                                   BL::SpaceView3D &b_v3d,
774                                   BL::RegionView3D &b_rv3d,
775                                   int width,
776                                   int height)
777 {
778   bool is_camera_view;
779
780   /* camera view? */
781   is_camera_view = b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_CAMERA;
782
783   if (!is_camera_view) {
784     /* for non-camera view check whether render border is enabled for viewport
785      * and if so use border from 3d viewport
786      * assume viewport has got correctly clamped border already
787      */
788     if (b_v3d.use_render_border()) {
789       bcam->border.left = b_v3d.render_border_min_x();
790       bcam->border.right = b_v3d.render_border_max_x();
791       bcam->border.bottom = b_v3d.render_border_min_y();
792       bcam->border.top = b_v3d.render_border_max_y();
793     }
794     return;
795   }
796
797   BL::Object b_ob = (b_v3d.use_local_camera()) ? b_v3d.camera() : b_scene.camera();
798
799   if (!b_ob)
800     return;
801
802   /* Determine camera border inside the viewport. */
803   BoundBox2D full_border;
804   blender_camera_border_subset(b_engine,
805                                b_render,
806                                b_scene,
807                                b_v3d,
808                                b_rv3d,
809                                b_ob,
810                                width,
811                                height,
812                                full_border,
813                                &bcam->viewport_camera_border);
814
815   if (!b_render.use_border()) {
816     return;
817   }
818
819   bcam->border.left = b_render.border_min_x();
820   bcam->border.right = b_render.border_max_x();
821   bcam->border.bottom = b_render.border_min_y();
822   bcam->border.top = b_render.border_max_y();
823
824   /* Determine viewport subset matching camera border. */
825   blender_camera_border_subset(b_engine,
826                                b_render,
827                                b_scene,
828                                b_v3d,
829                                b_rv3d,
830                                b_ob,
831                                width,
832                                height,
833                                bcam->border,
834                                &bcam->border);
835   bcam->border = bcam->border.clamp();
836 }
837
838 void BlenderSync::sync_view(BL::SpaceView3D &b_v3d,
839                             BL::RegionView3D &b_rv3d,
840                             int width,
841                             int height)
842 {
843   BlenderCamera bcam;
844   BL::RenderSettings b_render_settings(b_scene.render());
845   blender_camera_init(&bcam, b_render_settings);
846   blender_camera_from_view(&bcam, b_engine, b_scene, b_v3d, b_rv3d, width, height);
847   blender_camera_border(&bcam, b_engine, b_render_settings, b_scene, b_v3d, b_rv3d, width, height);
848   PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
849   blender_camera_sync(scene->camera, &bcam, width, height, "", &cscene);
850
851   /* dicing camera */
852   BL::Object b_ob = BL::Object(RNA_pointer_get(&cscene, "dicing_camera"));
853   if (b_ob) {
854     BL::Array<float, 16> b_ob_matrix;
855     blender_camera_from_object(&bcam, b_engine, b_ob);
856     b_engine.camera_model_matrix(b_ob, bcam.use_spherical_stereo, b_ob_matrix);
857     bcam.matrix = get_transform(b_ob_matrix);
858
859     blender_camera_sync(scene->dicing_camera, &bcam, width, height, "", &cscene);
860   }
861   else {
862     *scene->dicing_camera = *scene->camera;
863   }
864 }
865
866 BufferParams BlenderSync::get_buffer_params(BL::RenderSettings &b_render,
867                                             BL::SpaceView3D &b_v3d,
868                                             BL::RegionView3D &b_rv3d,
869                                             Camera *cam,
870                                             int width,
871                                             int height)
872 {
873   BufferParams params;
874   bool use_border = false;
875
876   params.full_width = width;
877   params.full_height = height;
878
879   if (b_v3d && b_rv3d && b_rv3d.view_perspective() != BL::RegionView3D::view_perspective_CAMERA)
880     use_border = b_v3d.use_render_border();
881   else
882     use_border = b_render.use_border();
883
884   if (use_border) {
885     /* border render */
886     /* the viewport may offset the border outside the view */
887     BoundBox2D border = cam->border.clamp();
888     params.full_x = (int)(border.left * (float)width);
889     params.full_y = (int)(border.bottom * (float)height);
890     params.width = (int)(border.right * (float)width) - params.full_x;
891     params.height = (int)(border.top * (float)height) - params.full_y;
892
893     /* survive in case border goes out of view or becomes too small */
894     params.width = max(params.width, 1);
895     params.height = max(params.height, 1);
896   }
897   else {
898     params.width = width;
899     params.height = height;
900   }
901
902   update_viewport_display_passes(b_v3d, params.passes);
903
904   return params;
905 }
906
907 CCL_NAMESPACE_END