style cleanup: block comments
[blender.git] / intern / cycles / blender / blender_camera.cpp
1 /*
2  * Copyright 2011, Blender Foundation.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18
19 #include "camera.h"
20 #include "scene.h"
21
22 #include "blender_sync.h"
23 #include "blender_util.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
40         float aperturesize;
41         uint apertureblades;
42         float aperturerotation;
43         float focaldistance;
44
45         float2 shift;
46         float2 offset;
47         float zoom;
48
49         float2 pixelaspect;
50
51         PanoramaType panorama_type;
52         float fisheye_fov;
53         float fisheye_lens;
54
55         enum { AUTO, HORIZONTAL, VERTICAL } sensor_fit;
56         float sensor_width;
57         float sensor_height;
58
59         float border_left;
60         float border_right;
61         float border_bottom;
62         float border_top;
63
64         Transform matrix;
65 };
66
67 static void blender_camera_init(BlenderCamera *bcam)
68 {
69         memset(bcam, 0, sizeof(BlenderCamera));
70
71         bcam->type = CAMERA_PERSPECTIVE;
72         bcam->zoom = 1.0f;
73         bcam->pixelaspect = make_float2(1.0f, 1.0f);
74         bcam->sensor_width = 32.0f;
75         bcam->sensor_height = 18.0f;
76         bcam->sensor_fit = BlenderCamera::AUTO;
77         bcam->shuttertime = 1.0f;
78         bcam->border_right = 1.0f;
79         bcam->border_top = 1.0f;
80 }
81
82 static float blender_camera_focal_distance(BL::Object b_ob, BL::Camera b_camera)
83 {
84         BL::Object b_dof_object = b_camera.dof_object();
85
86         if(!b_dof_object)
87                 return b_camera.dof_distance();
88         
89         /* for dof object, return distance along camera Z direction */
90         Transform obmat = transform_clear_scale(get_transform(b_ob.matrix_world()));
91         Transform dofmat = get_transform(b_dof_object.matrix_world());
92         Transform mat = transform_inverse(obmat) * dofmat;
93
94         return fabsf(transform_get_column(&mat, 3).z);
95 }
96
97 static void blender_camera_from_object(BlenderCamera *bcam, BL::Object b_ob)
98 {
99         BL::ID b_ob_data = b_ob.data();
100
101         if(b_ob_data.is_a(&RNA_Camera)) {
102                 BL::Camera b_camera(b_ob_data);
103                 PointerRNA ccamera = RNA_pointer_get(&b_camera.ptr, "cycles");
104
105                 bcam->nearclip = b_camera.clip_start();
106                 bcam->farclip = b_camera.clip_end();
107
108                 switch(b_camera.type())
109                 {
110                         case BL::Camera::type_ORTHO:
111                                 bcam->type = CAMERA_ORTHOGRAPHIC;
112                                 break;
113                         case BL::Camera::type_PANO:
114                                 bcam->type = CAMERA_PANORAMA;
115                                 break;
116                         case BL::Camera::type_PERSP:
117                         default:
118                                 bcam->type = CAMERA_PERSPECTIVE;
119                                 break;
120                 }       
121
122                 switch(RNA_enum_get(&ccamera, "panorama_type"))
123                 {
124                         case 1:
125                                 bcam->panorama_type = PANORAMA_FISHEYE_EQUIDISTANT;
126                                 break;
127                         case 2:
128                                 bcam->panorama_type = PANORAMA_FISHEYE_EQUISOLID;
129                                 break;
130                         case 0:
131                         default:
132                                 bcam->panorama_type = PANORAMA_EQUIRECTANGULAR;
133                                 break;
134                 }       
135
136                 bcam->fisheye_fov = RNA_float_get(&ccamera, "fisheye_fov");
137                 bcam->fisheye_lens = RNA_float_get(&ccamera, "fisheye_lens");
138
139                 bcam->ortho_scale = b_camera.ortho_scale();
140
141                 bcam->lens = b_camera.lens();
142
143                 /* allow f/stop number to change aperture_size but still
144                  * give manual control over aperture radius */
145                 int aperture_type = RNA_enum_get(&ccamera, "aperture_type");
146
147                 if(aperture_type == 1) {
148                         float fstop = RNA_float_get(&ccamera, "aperture_fstop");
149                         bcam->aperturesize = (bcam->lens*1e-3f)/(2.0f*max(fstop, 1e-5f));
150                 }
151                 else
152                         bcam->aperturesize = RNA_float_get(&ccamera, "aperture_size");
153
154                 bcam->apertureblades = RNA_int_get(&ccamera, "aperture_blades");
155                 bcam->aperturerotation = RNA_float_get(&ccamera, "aperture_rotation");
156                 bcam->focaldistance = blender_camera_focal_distance(b_ob, b_camera);
157
158                 bcam->shift.x = b_camera.shift_x();
159                 bcam->shift.y = b_camera.shift_y();
160
161                 bcam->sensor_width = b_camera.sensor_width();
162                 bcam->sensor_height = b_camera.sensor_height();
163
164                 if(b_camera.sensor_fit() == BL::Camera::sensor_fit_AUTO)
165                         bcam->sensor_fit = BlenderCamera::AUTO;
166                 else if(b_camera.sensor_fit() == BL::Camera::sensor_fit_HORIZONTAL)
167                         bcam->sensor_fit = BlenderCamera::HORIZONTAL;
168                 else
169                         bcam->sensor_fit = BlenderCamera::VERTICAL;
170         }
171         else {
172                 /* from lamp not implemented yet */
173         }
174 }
175
176 static Transform blender_camera_matrix(const Transform& tfm, CameraType type)
177 {
178         Transform result;
179
180         if(type == CAMERA_PANORAMA) {
181                 /* make it so environment camera needs to be pointed in the direction
182                  * of the positive x-axis to match an environment texture, this way
183                  * it is looking at the center of the texture */
184                 result = tfm *
185                         make_transform( 0.0f, -1.0f, 0.0f, 0.0f,
186                                         0.0f,  0.0f, 1.0f, 0.0f,
187                                        -1.0f,  0.0f, 0.0f, 0.0f,
188                                         0.0f,  0.0f, 0.0f, 1.0f);
189         }
190         else {
191                 /* note the blender camera points along the negative z-axis */
192                 result = tfm * transform_scale(1.0f, 1.0f, -1.0f);
193         }
194
195         return transform_clear_scale(result);
196 }
197
198 static void blender_camera_viewplane(BlenderCamera *bcam, int width, int height,
199         float *left, float *right, float *bottom, float *top, float *aspectratio, float *sensor_size)
200 {
201         /* dimensions */
202         float xratio = width*bcam->pixelaspect.x;
203         float yratio = height*bcam->pixelaspect.y;
204
205         /* compute x/y aspect and ratio */
206         float xaspect, yaspect;
207
208         /* sensor fitting */
209         bool horizontal_fit;
210
211         if(bcam->sensor_fit == BlenderCamera::AUTO) {
212                 horizontal_fit = (xratio > yratio);
213                 *sensor_size = bcam->sensor_width;
214         }
215         else if(bcam->sensor_fit == BlenderCamera::HORIZONTAL) {
216                 horizontal_fit = true;
217                 *sensor_size = bcam->sensor_width;
218         }
219         else {
220                 horizontal_fit = false;
221                 *sensor_size = bcam->sensor_height;
222         }
223
224         if(horizontal_fit) {
225                 *aspectratio= xratio/yratio;
226                 xaspect= *aspectratio;
227                 yaspect= 1.0f;
228         }
229         else {
230                 *aspectratio= yratio/xratio;
231                 xaspect= 1.0f;
232                 yaspect= *aspectratio;
233         }
234
235         /* modify aspect for orthographic scale */
236         if(bcam->type == CAMERA_ORTHOGRAPHIC) {
237                 xaspect = xaspect*bcam->ortho_scale/(*aspectratio*2.0f);
238                 yaspect = yaspect*bcam->ortho_scale/(*aspectratio*2.0f);
239                 *aspectratio = bcam->ortho_scale/2.0f;
240         }
241
242         if(bcam->type == CAMERA_PANORAMA) {
243                 /* set viewplane */
244                 *left = 0.0f;
245                 *right = 1.0f;
246                 *bottom = 0.0f;
247                 *top = 1.0f;
248         }
249         else {
250                 /* set viewplane */
251                 *left = -xaspect;
252                 *right = xaspect;
253                 *bottom = -yaspect;
254                 *top = yaspect;
255
256                 /* zoom for 3d camera view */
257                 *left *= bcam->zoom;
258                 *right *= bcam->zoom;
259                 *bottom *= bcam->zoom;
260                 *top *= bcam->zoom;
261
262                 /* modify viewplane with camera shift and 3d camera view offset */
263                 float dx = 2.0f*(*aspectratio*bcam->shift.x + bcam->offset.x*xaspect*2.0f);
264                 float dy = 2.0f*(*aspectratio*bcam->shift.y + bcam->offset.y*yaspect*2.0f);
265
266                 *left += dx;
267                 *right += dx;
268                 *bottom += dy;
269                 *top += dy;
270         }
271 }
272
273 static void blender_camera_sync(Camera *cam, BlenderCamera *bcam, int width, int height)
274 {
275         /* copy camera to compare later */
276         Camera prevcam = *cam;
277         float aspectratio, sensor_size;
278
279         /* viewplane */
280         blender_camera_viewplane(bcam, width, height,
281                 &cam->left, &cam->right, &cam->bottom, &cam->top, &aspectratio, &sensor_size);
282
283         /* sensor */
284         cam->sensorwidth = bcam->sensor_width;
285         cam->sensorheight = bcam->sensor_height;
286
287         /* clipping distances */
288         cam->nearclip = bcam->nearclip;
289         cam->farclip = bcam->farclip;
290
291         /* type */
292         cam->type = bcam->type;
293
294         /* panorama */
295         cam->panorama_type = bcam->panorama_type;
296         cam->fisheye_fov = bcam->fisheye_fov;
297         cam->fisheye_lens = bcam->fisheye_lens;
298
299         /* perspective */
300         cam->fov = 2.0f*atan((0.5f*sensor_size)/bcam->lens/aspectratio);
301         cam->focaldistance = bcam->focaldistance;
302         cam->aperturesize = bcam->aperturesize;
303         cam->blades = bcam->apertureblades;
304         cam->bladesrotation = bcam->aperturerotation;
305
306         /* transform */
307         cam->matrix = blender_camera_matrix(bcam->matrix, bcam->type);
308         cam->motion.pre = cam->matrix;
309         cam->motion.post = cam->matrix;
310         cam->use_motion = false;
311         cam->shuttertime = bcam->shuttertime;
312
313         /* border */
314         cam->border_left = bcam->border_left;
315         cam->border_right = bcam->border_right;
316         cam->border_bottom = bcam->border_bottom;
317         cam->border_top = bcam->border_top;
318
319         /* set update flag */
320         if(cam->modified(prevcam))
321                 cam->tag_update();
322 }
323
324 /* Sync Render Camera */
325
326 void BlenderSync::sync_camera(BL::Object b_override, int width, int height)
327 {
328         BlenderCamera bcam;
329         blender_camera_init(&bcam);
330
331         /* pixel aspect */
332         BL::RenderSettings r = b_scene.render();
333
334         bcam.pixelaspect.x = r.pixel_aspect_x();
335         bcam.pixelaspect.y = r.pixel_aspect_y();
336         bcam.shuttertime = r.motion_blur_shutter();
337
338         /* border */
339         if(r.use_border()) {
340                 bcam.border_left = r.border_min_x();
341                 bcam.border_right = r.border_max_x();
342                 bcam.border_bottom = r.border_min_y();
343                 bcam.border_top = r.border_max_y();
344         }
345
346         /* camera object */
347         BL::Object b_ob = b_scene.camera();
348
349         if(b_override)
350                 b_ob = b_override;
351
352         if(b_ob) {
353                 blender_camera_from_object(&bcam, b_ob);
354                 bcam.matrix = get_transform(b_ob.matrix_world());
355         }
356
357         /* sync */
358         Camera *cam = scene->camera;
359         blender_camera_sync(cam, &bcam, width, height);
360 }
361
362 void BlenderSync::sync_camera_motion(BL::Object b_ob, int motion)
363 {
364         Camera *cam = scene->camera;
365
366         Transform tfm = get_transform(b_ob.matrix_world());
367         tfm = blender_camera_matrix(tfm, cam->type);
368
369         if(tfm != cam->matrix) {
370                 if(motion == -1)
371                         cam->motion.pre = tfm;
372                 else
373                         cam->motion.post = tfm;
374
375                 cam->use_motion = true;
376         }
377 }
378
379 /* Sync 3D View Camera */
380
381 static void blender_camera_from_view(BlenderCamera *bcam, BL::Scene b_scene, BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, int width, int height)
382 {
383         /* 3d view parameters */
384         bcam->nearclip = b_v3d.clip_start();
385         bcam->farclip = b_v3d.clip_end();
386         bcam->lens = b_v3d.lens();
387         bcam->shuttertime = b_scene.render().motion_blur_shutter();
388
389         if(b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_CAMERA) {
390                 /* camera view */
391                 BL::Object b_ob = (b_v3d.lock_camera_and_layers())? b_scene.camera(): b_v3d.camera();
392
393                 if(b_ob) {
394                         blender_camera_from_object(bcam, b_ob);
395
396                         /* magic zoom formula */
397                         bcam->zoom = (float)b_rv3d.view_camera_zoom();
398                         bcam->zoom = (1.41421f + bcam->zoom/50.0f);
399                         bcam->zoom *= bcam->zoom;
400                         bcam->zoom = 2.0f/bcam->zoom;
401
402                         /* offset */
403                         bcam->offset = get_float2(b_rv3d.view_camera_offset());
404                 }
405         }
406         else if(b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_ORTHO) {
407                 /* orthographic view */
408                 bcam->farclip *= 0.5;
409                 bcam->nearclip = -bcam->farclip;
410
411                 bcam->type = CAMERA_ORTHOGRAPHIC;
412                 bcam->ortho_scale = b_rv3d.view_distance();
413         }
414
415         bcam->zoom *= 2.0f;
416
417         /* 3d view transform */
418         bcam->matrix = transform_inverse(get_transform(b_rv3d.view_matrix()));
419 }
420
421 static void blender_camera_border(BlenderCamera *bcam, BL::Scene b_scene, BL::SpaceView3D b_v3d,
422         BL::RegionView3D b_rv3d, int width, int height)
423 {
424         BL::RenderSettings r = b_scene.render();
425
426         if(!r.use_border())
427                 return;
428
429         /* camera view? */
430         if(!(b_rv3d && b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_CAMERA))
431                 return;
432
433         BL::Object b_ob = (b_v3d.lock_camera_and_layers())? b_scene.camera(): b_v3d.camera();
434
435         if(!b_ob)
436                 return;
437
438         bcam->border_left = r.border_min_x();
439         bcam->border_right = r.border_max_x();
440         bcam->border_bottom = r.border_min_y();
441         bcam->border_top = r.border_max_y();
442
443         float cam_left, cam_right, cam_bottom, cam_top;
444         float view_left, view_right, view_bottom, view_top;
445         float view_aspect, cam_aspect, sensor_size;
446
447         /* get viewport viewplane */
448         BlenderCamera view_bcam;
449         blender_camera_init(&view_bcam);
450         blender_camera_from_view(&view_bcam, b_scene, b_v3d, b_rv3d, width, height);
451
452         blender_camera_viewplane(&view_bcam, width, height,
453                 &view_left, &view_right, &view_bottom, &view_top, &view_aspect, &sensor_size);
454
455         view_left /= view_aspect;
456         view_right /= view_aspect;
457         view_bottom /= view_aspect;
458         view_top /= view_aspect;
459
460         /* get camera viewplane */
461         BlenderCamera cam_bcam;
462         blender_camera_init(&cam_bcam);
463         blender_camera_from_object(&cam_bcam, b_ob);
464
465         width = (int)(r.resolution_x()*r.resolution_percentage()/100);
466         height = (int)(r.resolution_y()*r.resolution_percentage()/100);
467
468         blender_camera_viewplane(&cam_bcam, width, height,
469                 &cam_left, &cam_right, &cam_bottom, &cam_top, &cam_aspect, &sensor_size);
470
471         cam_left /= cam_aspect;
472         cam_right /= cam_aspect;
473         cam_bottom /= cam_aspect;
474         cam_top /= cam_aspect;
475
476         /* determine viewport subset matching camera border */
477         float tmp_left = ((cam_left - view_left) / (view_right - view_left));
478         float tmp_right = ((cam_right - view_left) / (view_right - view_left));
479         float tmp_bottom = ((cam_bottom - view_bottom) / (view_top - view_bottom));
480         float tmp_top = ((cam_top - view_bottom) / (view_top - view_bottom));
481
482         bcam->border_left = tmp_left + bcam->border_left*(tmp_right - tmp_left);
483         bcam->border_right = tmp_left + bcam->border_right*(tmp_right - tmp_left);
484         bcam->border_bottom = tmp_bottom + bcam->border_bottom*(tmp_top - tmp_bottom);
485         bcam->border_top = tmp_bottom + bcam->border_top*(tmp_top - tmp_bottom);
486
487         /* clamp */
488         bcam->border_left = max(bcam->border_left, 0.0f);
489         bcam->border_right = min(bcam->border_right, 1.0f);
490         bcam->border_bottom = max(bcam->border_bottom, 0.0f);
491         bcam->border_top = min(bcam->border_top, 1.0f);
492 }
493
494 void BlenderSync::sync_view(BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, int width, int height)
495 {
496         BlenderCamera bcam;
497         blender_camera_init(&bcam);
498         blender_camera_from_view(&bcam, b_scene, b_v3d, b_rv3d, width, height);
499         blender_camera_border(&bcam, b_scene, b_v3d, b_rv3d, width, height);
500
501         blender_camera_sync(scene->camera, &bcam, width, height);
502 }
503
504 BufferParams BlenderSync::get_buffer_params(BL::Scene b_scene, Camera *cam, int width, int height)
505 {
506         BufferParams params;
507
508         params.full_width = width;
509         params.full_height = height;
510
511         if(b_scene.render().use_border()) {
512                 /* border render */
513                 params.full_x = cam->border_left*width;
514                 params.full_y = cam->border_bottom*height;
515                 params.width = (int)(cam->border_right*width) - params.full_x;
516                 params.height = (int)(cam->border_top*height) - params.full_y;
517         }
518         else {
519                 params.width = width;
520                 params.height = height;
521         }
522
523         return params;
524 }
525
526 CCL_NAMESPACE_END
527