Cycles: svn merge -r40266:40358 https://svn.blender.org/svnroot/bf-blender/trunk...
[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         bool ortho;
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         Transform matrix;
51 };
52
53 static void blender_camera_init(BlenderCamera *bcam)
54 {
55         memset(bcam, 0, sizeof(BlenderCamera));
56
57         bcam->zoom = 1.0f;
58         bcam->pixelaspect = make_float2(1.0f, 1.0f);
59 }
60
61 static float blender_camera_focal_distance(BL::Object b_ob, BL::Camera b_camera)
62 {
63         BL::Object b_dof_object = b_camera.dof_object();
64
65         if(!b_dof_object)
66                 return b_camera.dof_distance();
67         
68         /* for dof object, return distance along camera direction. this is
69          * compatible with blender, but does it fit our dof model? */
70         Transform obmat = get_transform(b_ob.matrix_world());
71         Transform dofmat = get_transform(b_dof_object.matrix_world());
72
73         float3 cam_p = transform_get_column(&obmat, 3);
74         float3 cam_dir = normalize(transform_get_column(&obmat, 2));
75         float3 dof_p = transform_get_column(&dofmat, 3);
76         float3 proj_p = dot(dof_p, cam_dir) * cam_dir;
77
78         return len(proj_p - cam_p);
79 }
80
81 static void blender_camera_from_object(BlenderCamera *bcam, BL::Object b_ob)
82 {
83         BL::ID b_ob_data = b_ob.data();
84
85         if(b_ob_data.is_a(&RNA_Camera)) {
86                 BL::Camera b_camera(b_ob_data);
87                 PointerRNA ccamera = RNA_pointer_get(&b_camera.ptr, "cycles");
88
89                 bcam->nearclip = b_camera.clip_start();
90                 bcam->farclip = b_camera.clip_end();
91
92                 bcam->ortho = (b_camera.type() == BL::Camera::type_ORTHO);
93                 bcam->ortho_scale = b_camera.ortho_scale();
94
95                 bcam->lens = b_camera.lens();
96                 bcam->aperturesize = RNA_float_get(&ccamera, "aperture_size");
97                 bcam->apertureblades = RNA_int_get(&ccamera, "aperture_blades");
98                 bcam->aperturerotation = RNA_float_get(&ccamera, "aperture_rotation");
99                 bcam->focaldistance = blender_camera_focal_distance(b_ob, b_camera);
100
101                 bcam->shift.x = b_camera.shift_x();
102                 bcam->shift.y = b_camera.shift_y();
103         }
104         else {
105                 /* from lamp not implemented yet */
106         }
107 }
108
109 static void blender_camera_sync(Camera *cam, BlenderCamera *bcam, int width, int height)
110 {
111         /* copy camera to compare later */
112         Camera prevcam = *cam;
113
114         /* dimensions */
115         float xratio = width*bcam->pixelaspect.x;
116         float yratio = height*bcam->pixelaspect.y;
117
118         /* compute x/y aspect and ratio */
119         float aspectratio, xaspect, yaspect;
120
121         if(xratio > yratio) {
122                 aspectratio= xratio/yratio;
123                 xaspect= aspectratio;
124                 yaspect= 1.0f;
125         }
126         else {
127                 aspectratio= yratio/xratio;
128                 xaspect= 1.0f;
129                 yaspect= aspectratio;
130         }
131
132         /* modify aspect for orthographic scale */
133         if(bcam->ortho) {
134                 xaspect = xaspect*bcam->ortho_scale/(aspectratio*2.0f);
135                 yaspect = yaspect*bcam->ortho_scale/(aspectratio*2.0f);
136                 aspectratio = bcam->ortho_scale/2.0f;
137         }
138
139         /* set viewplane */
140         cam->left = -xaspect;
141         cam->right = xaspect;
142         cam->bottom = -yaspect;
143         cam->top = yaspect;
144
145         /* zoom for 3d camera view */
146         cam->left *= bcam->zoom;
147         cam->right *= bcam->zoom;
148         cam->bottom *= bcam->zoom;
149         cam->top *= bcam->zoom;
150
151         /* modify viewplane with camera shift and 3d camera view offset */
152         float dx = 2.0f*(aspectratio*bcam->shift.x + bcam->offset.x*xaspect*2.0f);
153         float dy = 2.0f*(aspectratio*bcam->shift.y + bcam->offset.y*yaspect*2.0f);
154
155         cam->left += dx;
156         cam->right += dx;
157         cam->bottom += dy;
158         cam->top += dy;
159
160         /* clipping distances */
161         cam->nearclip = bcam->nearclip;
162         cam->farclip = bcam->farclip;
163
164         /* orthographic */
165         cam->ortho = bcam->ortho;
166
167         /* perspective */
168         cam->fov = 2.0f*atan(16.0f/bcam->lens/aspectratio);
169         cam->focaldistance = bcam->focaldistance;
170         cam->aperturesize = bcam->aperturesize;
171         cam->blades = bcam->apertureblades;
172         cam->bladesrotation = bcam->aperturerotation;
173
174         /* transform, note the blender camera points along the negative z-axis */
175         cam->matrix = bcam->matrix * transform_scale(1.0f, 1.0f, -1.0f);
176
177         /* set update flag */
178         if(cam->modified(prevcam))
179                 cam->tag_update();
180 }
181
182 /* Sync Render Camera */
183
184 void BlenderSync::sync_camera(int width, int height)
185 {
186         BlenderCamera bcam;
187         blender_camera_init(&bcam);
188
189         /* pixel aspect */
190         BL::RenderSettings r = b_scene.render();
191
192         bcam.pixelaspect.x = r.pixel_aspect_x();
193         bcam.pixelaspect.y = r.pixel_aspect_y();
194
195         /* camera object */
196         BL::Object b_ob = b_scene.camera();
197
198         if(b_ob) {
199                 blender_camera_from_object(&bcam, b_ob);
200                 bcam.matrix = get_transform(b_ob.matrix_world());
201         }
202
203         /* sync */
204         Camera *cam = scene->camera;
205         blender_camera_sync(cam, &bcam, width, height);
206 }
207
208 /* Sync 3D View Camera */
209
210 void BlenderSync::sync_view(BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, int width, int height)
211 {
212         BlenderCamera bcam;
213         blender_camera_init(&bcam);
214
215         /* 3d view parameters */
216         bcam.nearclip = b_v3d.clip_start();
217         bcam.farclip = b_v3d.clip_end();
218         bcam.lens = b_v3d.lens();
219
220         if(b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_CAMERA) {
221                 /* camera view */
222                 BL::Object b_ob = b_scene.camera();
223
224                 if(b_ob) {
225                         blender_camera_from_object(&bcam, b_ob);
226
227                         /* magic zoom formula */
228                         bcam.zoom = (float)b_rv3d.view_camera_zoom();
229                         bcam.zoom = (1.41421f + bcam.zoom/50.0f);
230                         bcam.zoom *= bcam.zoom;
231                         bcam.zoom = 2.0f/bcam.zoom;
232
233                         /* offset */
234                         bcam.offset = get_float2(b_rv3d.view_camera_offset());
235                 }
236         }
237         else if(b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_ORTHO) {
238                 /* orthographic view */
239                 bcam.farclip *= 0.5;
240                 bcam.nearclip = -bcam.farclip;
241
242                 bcam.ortho = true;
243                 bcam.ortho_scale = b_rv3d.view_distance();
244         }
245
246         bcam.zoom *= 2.0f;
247
248         /* 3d view transform */
249         bcam.matrix = transform_inverse(get_transform(b_rv3d.view_matrix()));
250
251         /* sync */
252         blender_camera_sync(scene->camera, &bcam, width, height);
253 }
254
255 CCL_NAMESPACE_END
256