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