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