bdd02bb508601e882546c9706296be44ee83dbed
[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         Transform matrix;
60 };
61
62 static void blender_camera_init(BlenderCamera *bcam)
63 {
64         memset(bcam, 0, sizeof(BlenderCamera));
65
66         bcam->type = CAMERA_PERSPECTIVE;
67         bcam->zoom = 1.0f;
68         bcam->pixelaspect = make_float2(1.0f, 1.0f);
69         bcam->sensor_width = 32.0f;
70         bcam->sensor_height = 18.0f;
71         bcam->sensor_fit = BlenderCamera::AUTO;
72         bcam->shuttertime = 1.0f;
73 }
74
75 static float blender_camera_focal_distance(BL::Object b_ob, BL::Camera b_camera)
76 {
77         BL::Object b_dof_object = b_camera.dof_object();
78
79         if(!b_dof_object)
80                 return b_camera.dof_distance();
81         
82         /* for dof object, return distance along camera Z direction */
83         Transform obmat = transform_clear_scale(get_transform(b_ob.matrix_world()));
84         Transform dofmat = get_transform(b_dof_object.matrix_world());
85         Transform mat = transform_inverse(obmat) * dofmat;
86
87         return fabsf(transform_get_column(&mat, 3).z);
88 }
89
90 static void blender_camera_from_object(BlenderCamera *bcam, BL::Object b_ob)
91 {
92         BL::ID b_ob_data = b_ob.data();
93
94         if(b_ob_data.is_a(&RNA_Camera)) {
95                 BL::Camera b_camera(b_ob_data);
96                 PointerRNA ccamera = RNA_pointer_get(&b_camera.ptr, "cycles");
97
98                 bcam->nearclip = b_camera.clip_start();
99                 bcam->farclip = b_camera.clip_end();
100
101                 switch(b_camera.type())
102                 {
103                         case BL::Camera::type_ORTHO:
104                                 bcam->type = CAMERA_ORTHOGRAPHIC;
105                                 break;
106                         case BL::Camera::type_PANO:
107                                 bcam->type = CAMERA_PANORAMA;
108                                 break;
109                         case BL::Camera::type_PERSP:
110                         default:
111                                 bcam->type = CAMERA_PERSPECTIVE;
112                                 break;
113                 }       
114
115                 switch(RNA_enum_get(&ccamera, "panorama_type"))
116                 {
117                         case 1:
118                                 bcam->panorama_type = PANORAMA_FISHEYE_EQUIDISTANT;
119                                 break;
120                         case 2:
121                                 bcam->panorama_type = PANORAMA_FISHEYE_EQUISOLID;
122                                 break;
123                         case 0:
124                         default:
125                                 bcam->panorama_type = PANORAMA_EQUIRECTANGULAR;
126                                 break;
127                 }       
128
129                 bcam->fisheye_fov = RNA_float_get(&ccamera, "fisheye_fov");
130                 bcam->fisheye_lens = RNA_float_get(&ccamera, "fisheye_lens");
131
132                 bcam->ortho_scale = b_camera.ortho_scale();
133
134                 bcam->lens = b_camera.lens();
135
136                 /* allow f/stop number to change aperture_size but still
137                    give manual control over aperture radius */
138                 int aperture_type = RNA_enum_get(&ccamera, "aperture_type");
139
140                 if(aperture_type == 1) {
141                         float fstop = RNA_float_get(&ccamera, "aperture_fstop");
142                         bcam->aperturesize = (bcam->lens*1e-3f)/(2.0f*max(fstop, 1e-5f));
143                 }
144                 else
145                         bcam->aperturesize = RNA_float_get(&ccamera, "aperture_size");
146
147                 bcam->apertureblades = RNA_int_get(&ccamera, "aperture_blades");
148                 bcam->aperturerotation = RNA_float_get(&ccamera, "aperture_rotation");
149                 bcam->focaldistance = blender_camera_focal_distance(b_ob, b_camera);
150
151                 bcam->shift.x = b_camera.shift_x();
152                 bcam->shift.y = b_camera.shift_y();
153
154                 bcam->sensor_width = b_camera.sensor_width();
155                 bcam->sensor_height = b_camera.sensor_height();
156
157                 if(b_camera.sensor_fit() == BL::Camera::sensor_fit_AUTO)
158                         bcam->sensor_fit = BlenderCamera::AUTO;
159                 else if(b_camera.sensor_fit() == BL::Camera::sensor_fit_HORIZONTAL)
160                         bcam->sensor_fit = BlenderCamera::HORIZONTAL;
161                 else
162                         bcam->sensor_fit = BlenderCamera::VERTICAL;
163         }
164         else {
165                 /* from lamp not implemented yet */
166         }
167 }
168
169 static Transform blender_camera_matrix(const Transform& tfm, CameraType type)
170 {
171         Transform result;
172
173         if(type == CAMERA_PANORAMA) {
174                 /* make it so environment camera needs to be pointed in the direction
175                    of the positive x-axis to match an environment texture, this way
176                    it is looking at the center of the texture */
177                 result = tfm *
178                         make_transform( 0.0f, -1.0f, 0.0f, 0.0f,
179                                         0.0f,  0.0f, 1.0f, 0.0f,
180                                        -1.0f,  0.0f, 0.0f, 0.0f,
181                                         0.0f,  0.0f, 0.0f, 1.0f);
182         }
183         else {
184                 /* note the blender camera points along the negative z-axis */
185                 result = tfm * transform_scale(1.0f, 1.0f, -1.0f);
186         }
187
188         return transform_clear_scale(result);
189 }
190
191 static void blender_camera_sync(Camera *cam, BlenderCamera *bcam, int width, int height)
192 {
193         /* copy camera to compare later */
194         Camera prevcam = *cam;
195
196         /* dimensions */
197         float xratio = width*bcam->pixelaspect.x;
198         float yratio = height*bcam->pixelaspect.y;
199
200         /* compute x/y aspect and ratio */
201         float aspectratio, xaspect, yaspect;
202
203         /* sensor fitting */
204         bool horizontal_fit;
205         float sensor_size;
206
207         cam->sensorwidth = bcam->sensor_width;
208         cam->sensorheight = bcam->sensor_height;
209
210         if(bcam->sensor_fit == BlenderCamera::AUTO) {
211                 horizontal_fit = (xratio > yratio);
212                 sensor_size = bcam->sensor_width;
213         }
214         else if(bcam->sensor_fit == BlenderCamera::HORIZONTAL) {
215                 horizontal_fit = true;
216                 sensor_size = bcam->sensor_width;
217         }
218         else {
219                 horizontal_fit = false;
220                 sensor_size = bcam->sensor_height;
221         }
222
223         if(horizontal_fit) {
224                 aspectratio= xratio/yratio;
225                 xaspect= aspectratio;
226                 yaspect= 1.0f;
227         }
228         else {
229                 aspectratio= yratio/xratio;
230                 xaspect= 1.0f;
231                 yaspect= aspectratio;
232         }
233
234         /* modify aspect for orthographic scale */
235         if(bcam->type == CAMERA_ORTHOGRAPHIC) {
236                 xaspect = xaspect*bcam->ortho_scale/(aspectratio*2.0f);
237                 yaspect = yaspect*bcam->ortho_scale/(aspectratio*2.0f);
238                 aspectratio = bcam->ortho_scale/2.0f;
239         }
240
241         if(bcam->type == CAMERA_PANORAMA) {
242                 /* set viewplane */
243                 cam->left = 0.0f;
244                 cam->right = 1.0f;
245                 cam->bottom = 0.0f;
246                 cam->top = 1.0f;
247         }
248         else {
249                 /* set viewplane */
250                 cam->left = -xaspect;
251                 cam->right = xaspect;
252                 cam->bottom = -yaspect;
253                 cam->top = yaspect;
254
255                 /* zoom for 3d camera view */
256                 cam->left *= bcam->zoom;
257                 cam->right *= bcam->zoom;
258                 cam->bottom *= bcam->zoom;
259                 cam->top *= bcam->zoom;
260
261                 /* modify viewplane with camera shift and 3d camera view offset */
262                 float dx = 2.0f*(aspectratio*bcam->shift.x + bcam->offset.x*xaspect*2.0f);
263                 float dy = 2.0f*(aspectratio*bcam->shift.y + bcam->offset.y*yaspect*2.0f);
264
265                 cam->left += dx;
266                 cam->right += dx;
267                 cam->bottom += dy;
268                 cam->top += dy;
269         }
270
271         /* clipping distances */
272         cam->nearclip = bcam->nearclip;
273         cam->farclip = bcam->farclip;
274
275         /* type */
276         cam->type = bcam->type;
277
278         /* panorama */
279         cam->panorama_type = bcam->panorama_type;
280         cam->fisheye_fov = bcam->fisheye_fov;
281         cam->fisheye_lens = bcam->fisheye_lens;
282
283         /* perspective */
284         cam->fov = 2.0f*atan((0.5f*sensor_size)/bcam->lens/aspectratio);
285         cam->focaldistance = bcam->focaldistance;
286         cam->aperturesize = bcam->aperturesize;
287         cam->blades = bcam->apertureblades;
288         cam->bladesrotation = bcam->aperturerotation;
289
290         /* transform */
291         cam->matrix = blender_camera_matrix(bcam->matrix, bcam->type);
292         cam->motion.pre = cam->matrix;
293         cam->motion.post = cam->matrix;
294         cam->use_motion = false;
295         cam->shuttertime = bcam->shuttertime;
296
297         /* set update flag */
298         if(cam->modified(prevcam))
299                 cam->tag_update();
300 }
301
302 /* Sync Render Camera */
303
304 void BlenderSync::sync_camera(BL::Object b_override, int width, int height)
305 {
306         BlenderCamera bcam;
307         blender_camera_init(&bcam);
308
309         /* pixel aspect */
310         BL::RenderSettings r = b_scene.render();
311
312         bcam.pixelaspect.x = r.pixel_aspect_x();
313         bcam.pixelaspect.y = r.pixel_aspect_y();
314         bcam.shuttertime = r.motion_blur_shutter();
315
316         /* camera object */
317         BL::Object b_ob = b_scene.camera();
318
319         if(b_override)
320                 b_ob = b_override;
321
322         if(b_ob) {
323                 blender_camera_from_object(&bcam, b_ob);
324                 bcam.matrix = get_transform(b_ob.matrix_world());
325         }
326
327         /* sync */
328         Camera *cam = scene->camera;
329         blender_camera_sync(cam, &bcam, width, height);
330 }
331
332 void BlenderSync::sync_camera_motion(BL::Object b_ob, int motion)
333 {
334         Camera *cam = scene->camera;
335
336         Transform tfm = get_transform(b_ob.matrix_world());
337         tfm = blender_camera_matrix(tfm, cam->type);
338
339         if(tfm != cam->matrix) {
340                 if(motion == -1)
341                         cam->motion.pre = tfm;
342                 else
343                         cam->motion.post = tfm;
344
345                 cam->use_motion = true;
346         }
347 }
348
349 /* Sync 3D View Camera */
350
351 void BlenderSync::sync_view(BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, int width, int height)
352 {
353         BlenderCamera bcam;
354         blender_camera_init(&bcam);
355
356         /* 3d view parameters */
357         bcam.nearclip = b_v3d.clip_start();
358         bcam.farclip = b_v3d.clip_end();
359         bcam.lens = b_v3d.lens();
360         bcam.shuttertime = b_scene.render().motion_blur_shutter();
361
362         if(b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_CAMERA) {
363                 /* camera view */
364                 BL::Object b_ob = (b_v3d.lock_camera_and_layers())? b_scene.camera(): b_v3d.camera();
365
366                 if(b_ob) {
367                         blender_camera_from_object(&bcam, b_ob);
368
369                         /* magic zoom formula */
370                         bcam.zoom = (float)b_rv3d.view_camera_zoom();
371                         bcam.zoom = (1.41421f + bcam.zoom/50.0f);
372                         bcam.zoom *= bcam.zoom;
373                         bcam.zoom = 2.0f/bcam.zoom;
374
375                         /* offset */
376                         bcam.offset = get_float2(b_rv3d.view_camera_offset());
377                 }
378         }
379         else if(b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_ORTHO) {
380                 /* orthographic view */
381                 bcam.farclip *= 0.5;
382                 bcam.nearclip = -bcam.farclip;
383
384                 bcam.type = CAMERA_ORTHOGRAPHIC;
385                 bcam.ortho_scale = b_rv3d.view_distance();
386         }
387
388         bcam.zoom *= 2.0f;
389
390         /* 3d view transform */
391         bcam.matrix = transform_inverse(get_transform(b_rv3d.view_matrix()));
392
393         /* sync */
394         blender_camera_sync(scene->camera, &bcam, width, height);
395 }
396
397 BufferParams BlenderSync::get_buffer_params(BL::Scene b_scene, BL::RegionView3D b_rv3d, int width, int height)
398 {
399         BufferParams params;
400
401         params.full_width = width;
402         params.full_height = height;
403
404         /* border render */
405         BL::RenderSettings r = b_scene.render();
406
407         if(!b_rv3d && r.use_border()) {
408                 params.full_x = r.border_min_x()*width;
409                 params.full_y = r.border_min_y()*height;
410                 params.width = (int)(r.border_max_x()*width) - params.full_x;
411                 params.height = (int)(r.border_max_y()*height) - params.full_y;
412         }
413         else {
414                 params.width = width;
415                 params.height = height;
416         }
417
418         return params;
419 }
420
421 CCL_NAMESPACE_END
422