Blender V2.61 - r43446

camera.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00019  * All rights reserved.
00020  *
00021  * The Original Code is: all of this file.
00022  *
00023  * Contributor(s): none yet.
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  */
00027 
00032 #include <stdlib.h>
00033 
00034 #include "DNA_camera_types.h"
00035 #include "DNA_lamp_types.h"
00036 #include "DNA_object_types.h"
00037 #include "DNA_scene_types.h"
00038 #include "DNA_view3d_types.h"
00039 
00040 #include "BLI_math.h"
00041 #include "BLI_utildefines.h"
00042 
00043 #include "BKE_animsys.h"
00044 #include "BKE_camera.h"
00045 #include "BKE_object.h"
00046 #include "BKE_global.h"
00047 #include "BKE_library.h"
00048 #include "BKE_main.h"
00049 #include "BKE_screen.h"
00050 
00051 /****************************** Camera Datablock *****************************/
00052 
00053 void *add_camera(const char *name)
00054 {
00055     Camera *cam;
00056     
00057     cam=  alloc_libblock(&G.main->camera, ID_CA, name);
00058 
00059     cam->lens= 35.0f;
00060     cam->sensor_x= 32.0f;
00061     cam->sensor_y= 18.0f;
00062     cam->clipsta= 0.1f;
00063     cam->clipend= 100.0f;
00064     cam->drawsize= 0.5f;
00065     cam->ortho_scale= 6.0;
00066     cam->flag |= CAM_SHOWPASSEPARTOUT;
00067     cam->passepartalpha = 0.5f;
00068     
00069     return cam;
00070 }
00071 
00072 Camera *copy_camera(Camera *cam)
00073 {
00074     Camera *camn;
00075     
00076     camn= copy_libblock(&cam->id);
00077 
00078     id_lib_extern((ID *)camn->dof_ob);
00079 
00080     return camn;
00081 }
00082 
00083 void make_local_camera(Camera *cam)
00084 {
00085     Main *bmain= G.main;
00086     Object *ob;
00087     int is_local= FALSE, is_lib= FALSE;
00088 
00089     /* - only lib users: do nothing
00090      * - only local users: set flag
00091      * - mixed: make copy
00092      */
00093     
00094     if(cam->id.lib==NULL) return;
00095     if(cam->id.us==1) {
00096         id_clear_lib_data(bmain, &cam->id);
00097         return;
00098     }
00099     
00100     for(ob= bmain->object.first; ob && ELEM(0, is_lib, is_local); ob= ob->id.next) {
00101         if(ob->data==cam) {
00102             if(ob->id.lib) is_lib= TRUE;
00103             else is_local= TRUE;
00104         }
00105     }
00106     
00107     if(is_local && is_lib == FALSE) {
00108         id_clear_lib_data(bmain, &cam->id);
00109     }
00110     else if(is_local && is_lib) {
00111         Camera *cam_new= copy_camera(cam);
00112 
00113         cam_new->id.us= 0;
00114 
00115         /* Remap paths of new ID using old library as base. */
00116         BKE_id_lib_local_paths(bmain, cam->id.lib, &cam_new->id);
00117 
00118         for(ob= bmain->object.first; ob; ob= ob->id.next) {
00119             if(ob->data == cam) {
00120                 if(ob->id.lib==NULL) {
00121                     ob->data= cam_new;
00122                     cam_new->id.us++;
00123                     cam->id.us--;
00124                 }
00125             }
00126         }
00127     }
00128 }
00129 
00130 void free_camera(Camera *ca)
00131 {
00132     BKE_free_animdata((ID *)ca);
00133 }
00134 
00135 /******************************** Camera Usage *******************************/
00136 
00137 void object_camera_mode(RenderData *rd, Object *cam_ob)
00138 {
00139     rd->mode &= ~(R_ORTHO|R_PANORAMA);
00140 
00141     if(cam_ob && cam_ob->type==OB_CAMERA) {
00142         Camera *cam= cam_ob->data;
00143         if(cam->type == CAM_ORTHO) rd->mode |= R_ORTHO;
00144         if(cam->flag & CAM_PANORAMA) rd->mode |= R_PANORAMA;
00145     }
00146 }
00147 
00148 /* get the camera's dof value, takes the dof object into account */
00149 float object_camera_dof_distance(Object *ob)
00150 {
00151     Camera *cam = (Camera *)ob->data; 
00152     if (ob->type != OB_CAMERA)
00153         return 0.0f;
00154     if (cam->dof_ob) {  
00155         /* too simple, better to return the distance on the view axis only
00156          * return len_v3v3(ob->obmat[3], cam->dof_ob->obmat[3]); */
00157         float mat[4][4], imat[4][4], obmat[4][4];
00158         
00159         copy_m4_m4(obmat, ob->obmat);
00160         normalize_m4(obmat);
00161         invert_m4_m4(imat, obmat);
00162         mult_m4_m4m4(mat, imat, cam->dof_ob->obmat);
00163         return fabsf(mat[3][2]);
00164     }
00165     return cam->YF_dofdist;
00166 }
00167 
00168 float camera_sensor_size(int sensor_fit, float sensor_x, float sensor_y)
00169 {
00170     /* sensor size used to fit to. for auto, sensor_x is both x and y. */
00171     if(sensor_fit == CAMERA_SENSOR_FIT_VERT)
00172         return sensor_y;
00173 
00174     return sensor_x;
00175 }
00176 
00177 int camera_sensor_fit(int sensor_fit, float sizex, float sizey)
00178 {
00179     if(sensor_fit == CAMERA_SENSOR_FIT_AUTO) {
00180         if(sizex >= sizey)
00181             return CAMERA_SENSOR_FIT_HOR;
00182         else
00183             return CAMERA_SENSOR_FIT_VERT;
00184     }
00185 
00186     return sensor_fit;
00187 }
00188 
00189 /******************************** Camera Params *******************************/
00190 
00191 void camera_params_init(CameraParams *params)
00192 {
00193     memset(params, 0, sizeof(CameraParams));
00194 
00195     /* defaults */
00196     params->sensor_x= DEFAULT_SENSOR_WIDTH;
00197     params->sensor_y= DEFAULT_SENSOR_HEIGHT;
00198     params->sensor_fit= CAMERA_SENSOR_FIT_AUTO;
00199 
00200     params->zoom= 1.0f;
00201 }
00202 
00203 void camera_params_from_object(CameraParams *params, Object *ob)
00204 {
00205     if(!ob)
00206         return;
00207 
00208     if(ob->type==OB_CAMERA) {
00209         /* camera object */
00210         Camera *cam= ob->data;
00211 
00212         if(cam->type == CAM_ORTHO)
00213             params->is_ortho= TRUE;
00214         params->lens= cam->lens;
00215         params->ortho_scale= cam->ortho_scale;
00216 
00217         params->shiftx= cam->shiftx;
00218         params->shifty= cam->shifty;
00219 
00220         params->sensor_x= cam->sensor_x;
00221         params->sensor_y= cam->sensor_y;
00222         params->sensor_fit= cam->sensor_fit;
00223 
00224         params->clipsta= cam->clipsta;
00225         params->clipend= cam->clipend;
00226     }
00227     else if(ob->type==OB_LAMP) {
00228         /* lamp object */
00229         Lamp *la= ob->data;
00230         float fac= cosf((float)M_PI*la->spotsize/360.0f);
00231         float phi= acos(fac);
00232 
00233         params->lens= 16.0f*fac/sinf(phi);
00234         if(params->lens==0.0f)
00235             params->lens= 35.0f;
00236 
00237         params->clipsta= la->clipsta;
00238         params->clipend= la->clipend;
00239     }
00240 }
00241 
00242 void camera_params_from_view3d(CameraParams *params, View3D *v3d, RegionView3D *rv3d)
00243 {
00244     /* common */
00245     params->lens= v3d->lens;
00246     params->clipsta= v3d->near;
00247     params->clipend= v3d->far;
00248 
00249     if(rv3d->persp==RV3D_CAMOB) {
00250         /* camera view */
00251         camera_params_from_object(params, v3d->camera);
00252 
00253         params->zoom= BKE_screen_view3d_zoom_to_fac((float)rv3d->camzoom);
00254 
00255         params->offsetx= 2.0f*rv3d->camdx*params->zoom;
00256         params->offsety= 2.0f*rv3d->camdy*params->zoom;
00257 
00258         params->shiftx *= params->zoom;
00259         params->shifty *= params->zoom;
00260 
00261         params->zoom= 1.0f/params->zoom;
00262     }
00263     else if(rv3d->persp==RV3D_ORTHO) {
00264         /* orthographic view */
00265         params->clipend *= 0.5f;    // otherwise too extreme low zbuffer quality
00266         params->clipsta= - params->clipend;
00267 
00268         params->is_ortho= TRUE;
00269         params->ortho_scale = rv3d->dist;
00270         params->zoom= 2.0f;
00271     }
00272     else {
00273         /* perspective view */
00274         params->zoom= 2.0f;
00275     }
00276 }
00277 
00278 void camera_params_compute_viewplane(CameraParams *params, int winx, int winy, float xasp, float yasp)
00279 {
00280     rctf viewplane;
00281     float pixsize, viewfac, sensor_size, dx, dy;
00282     int sensor_fit;
00283 
00284     /* fields rendering */
00285     params->ycor= yasp/xasp;
00286     if(params->use_fields)
00287         params->ycor *= 2.0f;
00288 
00289     if(params->is_ortho) {
00290         /* orthographic camera */
00291         /* scale == 1.0 means exact 1 to 1 mapping */
00292         pixsize= params->ortho_scale;
00293     }
00294     else {
00295         /* perspective camera */
00296         sensor_size= camera_sensor_size(params->sensor_fit, params->sensor_x, params->sensor_y);
00297         pixsize= (sensor_size * params->clipsta)/params->lens;
00298     }
00299 
00300     /* determine sensor fit */
00301     sensor_fit = camera_sensor_fit(params->sensor_fit, xasp*winx, yasp*winy);
00302 
00303     if(sensor_fit==CAMERA_SENSOR_FIT_HOR)
00304         viewfac= winx;
00305     else
00306         viewfac= params->ycor * winy;
00307 
00308     pixsize /= viewfac;
00309 
00310     /* extra zoom factor */
00311     pixsize *= params->zoom;
00312 
00313     /* compute view plane:
00314      * fully centered, zbuffer fills in jittered between -.5 and +.5 */
00315     viewplane.xmin= -0.5f*(float)winx;
00316     viewplane.ymin= -0.5f*params->ycor*(float)winy;
00317     viewplane.xmax=  0.5f*(float)winx;
00318     viewplane.ymax=  0.5f*params->ycor*(float)winy;
00319 
00320     /* lens shift and offset */
00321     dx= params->shiftx*viewfac + winx*params->offsetx;
00322     dy= params->shifty*viewfac + winy*params->offsety;
00323 
00324     viewplane.xmin += dx;
00325     viewplane.ymin += dy;
00326     viewplane.xmax += dx;
00327     viewplane.ymax += dy;
00328 
00329     /* fields offset */
00330     if(params->field_second) {
00331         if(params->field_odd) {
00332             viewplane.ymin-= 0.5f * params->ycor;
00333             viewplane.ymax-= 0.5f * params->ycor;
00334         }
00335         else {
00336             viewplane.ymin+= 0.5f * params->ycor;
00337             viewplane.ymax+= 0.5f * params->ycor;
00338         }
00339     }
00340 
00341     /* the window matrix is used for clipping, and not changed during OSA steps */
00342     /* using an offset of +0.5 here would give clip errors on edges */
00343     viewplane.xmin *= pixsize;
00344     viewplane.xmax *= pixsize;
00345     viewplane.ymin *= pixsize;
00346     viewplane.ymax *= pixsize;
00347 
00348     params->viewdx= pixsize;
00349     params->viewdy= params->ycor * pixsize;
00350     params->viewplane= viewplane;
00351 }
00352 
00353 /* viewplane is assumed to be already computed */
00354 void camera_params_compute_matrix(CameraParams *params)
00355 {
00356     rctf viewplane= params->viewplane;
00357 
00358     /* compute projection matrix */
00359     if(params->is_ortho)
00360         orthographic_m4(params->winmat, viewplane.xmin, viewplane.xmax,
00361             viewplane.ymin, viewplane.ymax, params->clipsta, params->clipend);
00362     else
00363         perspective_m4(params->winmat, viewplane.xmin, viewplane.xmax,
00364             viewplane.ymin, viewplane.ymax, params->clipsta, params->clipend);
00365 }
00366 
00367 /***************************** Camera View Frame *****************************/
00368 
00369 void camera_view_frame_ex(Scene *scene, Camera *camera, float drawsize, const short do_clip, const float scale[3],
00370                           float r_asp[2], float r_shift[2], float *r_drawsize, float r_vec[4][3])
00371 {
00372     float facx, facy;
00373     float depth;
00374 
00375     /* aspect correcton */
00376     if (scene) {
00377         float aspx= (float) scene->r.xsch*scene->r.xasp;
00378         float aspy= (float) scene->r.ysch*scene->r.yasp;
00379         int sensor_fit= camera_sensor_fit(camera->sensor_fit, aspx, aspy);
00380 
00381         if(sensor_fit==CAMERA_SENSOR_FIT_HOR) {
00382             r_asp[0]= 1.0;
00383             r_asp[1]= aspy / aspx;
00384         }
00385         else {
00386             r_asp[0]= aspx / aspy;
00387             r_asp[1]= 1.0;
00388         }
00389     }
00390     else {
00391         r_asp[0]= 1.0f;
00392         r_asp[1]= 1.0f;
00393     }
00394 
00395     if(camera->type==CAM_ORTHO) {
00396         facx= 0.5f * camera->ortho_scale * r_asp[0] * scale[0];
00397         facy= 0.5f * camera->ortho_scale * r_asp[1] * scale[1];
00398         r_shift[0]= camera->shiftx * camera->ortho_scale * scale[0];
00399         r_shift[1]= camera->shifty * camera->ortho_scale * scale[1];
00400         depth= do_clip ? -((camera->clipsta * scale[2]) + 0.1f) : - drawsize * camera->ortho_scale * scale[2];
00401 
00402         *r_drawsize= 0.5f * camera->ortho_scale;
00403     }
00404     else {
00405         /* that way it's always visible - clipsta+0.1 */
00406         float fac;
00407         float half_sensor= 0.5f*((camera->sensor_fit==CAMERA_SENSOR_FIT_VERT) ? (camera->sensor_y) : (camera->sensor_x));
00408 
00409         *r_drawsize= drawsize / ((scale[0] + scale[1] + scale[2]) / 3.0f);
00410 
00411         if(do_clip) {
00412             /* fixed depth, variable size (avoids exceeding clipping range) */
00413             depth = -(camera->clipsta + 0.1f);
00414             fac = depth / (camera->lens/(-half_sensor) * scale[2]);
00415         }
00416         else {
00417             /* fixed size, variable depth (stays a reasonable size in the 3D view) */
00418             depth= *r_drawsize * camera->lens/(-half_sensor) * scale[2];
00419             fac= *r_drawsize;
00420         }
00421 
00422         facx= fac * r_asp[0] * scale[0];
00423         facy= fac * r_asp[1] * scale[1];
00424         r_shift[0]= camera->shiftx*fac*2 * scale[0];
00425         r_shift[1]= camera->shifty*fac*2 * scale[1];
00426     }
00427 
00428     r_vec[0][0]= r_shift[0] + facx; r_vec[0][1]= r_shift[1] + facy; r_vec[0][2]= depth;
00429     r_vec[1][0]= r_shift[0] + facx; r_vec[1][1]= r_shift[1] - facy; r_vec[1][2]= depth;
00430     r_vec[2][0]= r_shift[0] - facx; r_vec[2][1]= r_shift[1] - facy; r_vec[2][2]= depth;
00431     r_vec[3][0]= r_shift[0] - facx; r_vec[3][1]= r_shift[1] + facy; r_vec[3][2]= depth;
00432 }
00433 
00434 void camera_view_frame(Scene *scene, Camera *camera, float r_vec[4][3])
00435 {
00436     float dummy_asp[2];
00437     float dummy_shift[2];
00438     float dummy_drawsize;
00439     const float dummy_scale[3]= {1.0f, 1.0f, 1.0f};
00440 
00441     camera_view_frame_ex(scene, camera, FALSE, 1.0, dummy_scale,
00442                          dummy_asp, dummy_shift, &dummy_drawsize, r_vec);
00443 }
00444 
00445 
00446 typedef struct CameraViewFrameData {
00447     float frame_tx[4][3];
00448     float normal_tx[4][3];
00449     float dist_vals[4];
00450     unsigned int tot;
00451 } CameraViewFrameData;
00452 
00453 static void camera_to_frame_view_cb(const float co[3], void *user_data)
00454 {
00455     CameraViewFrameData *data= (CameraViewFrameData *)user_data;
00456     unsigned int i;
00457 
00458     for (i= 0; i < 4; i++) {
00459         float nd= dist_to_plane_v3(co, data->frame_tx[i], data->normal_tx[i]);
00460         if (nd < data->dist_vals[i]) {
00461             data->dist_vals[i]= nd;
00462         }
00463     }
00464 
00465     data->tot++;
00466 }
00467 
00468 /* dont move the camera, just yield the fit location */
00469 /* only valid for perspective cameras */
00470 int camera_view_frame_fit_to_scene(Scene *scene, struct View3D *v3d, Object *camera_ob, float r_co[3])
00471 {
00472     float shift[2];
00473     float plane_tx[4][3];
00474     float rot_obmat[3][3];
00475     const float zero[3]= {0,0,0};
00476     CameraViewFrameData data_cb;
00477 
00478     unsigned int i;
00479 
00480     camera_view_frame(scene, camera_ob->data, data_cb.frame_tx);
00481 
00482     copy_m3_m4(rot_obmat, camera_ob->obmat);
00483     normalize_m3(rot_obmat);
00484 
00485     for (i= 0; i < 4; i++) {
00486         /* normalize so Z is always 1.0f*/
00487         mul_v3_fl(data_cb.frame_tx[i], 1.0f/data_cb.frame_tx[i][2]);
00488     }
00489 
00490     /* get the shift back out of the frame */
00491     shift[0]= (data_cb.frame_tx[0][0] +
00492                data_cb.frame_tx[1][0] +
00493                data_cb.frame_tx[2][0] +
00494                data_cb.frame_tx[3][0]) / 4.0f;
00495     shift[1]= (data_cb.frame_tx[0][1] +
00496                data_cb.frame_tx[1][1] +
00497                data_cb.frame_tx[2][1] +
00498                data_cb.frame_tx[3][1]) / 4.0f;
00499 
00500     for (i= 0; i < 4; i++) {
00501         mul_m3_v3(rot_obmat, data_cb.frame_tx[i]);
00502     }
00503 
00504     for (i= 0; i < 4; i++) {
00505         normal_tri_v3(data_cb.normal_tx[i],
00506                       zero, data_cb.frame_tx[i], data_cb.frame_tx[(i + 1) % 4]);
00507     }
00508 
00509     /* initialize callback data */
00510     data_cb.dist_vals[0]=
00511     data_cb.dist_vals[1]=
00512     data_cb.dist_vals[2]=
00513     data_cb.dist_vals[3]= FLT_MAX;
00514     data_cb.tot= 0;
00515     /* run callback on all visible points */
00516     BKE_scene_foreach_display_point(scene, v3d, BA_SELECT,
00517                                     camera_to_frame_view_cb, &data_cb);
00518 
00519     if (data_cb.tot <= 1) {
00520         return FALSE;
00521     }
00522     else {
00523         float plane_isect_1[3], plane_isect_1_no[3], plane_isect_1_other[3];
00524         float plane_isect_2[3], plane_isect_2_no[3], plane_isect_2_other[3];
00525 
00526         float plane_isect_pt_1[3], plane_isect_pt_2[3];
00527 
00528         /* apply the dist-from-plane's to the transformed plane points */
00529         for (i= 0; i < 4; i++) {
00530             mul_v3_v3fl(plane_tx[i], data_cb.normal_tx[i], data_cb.dist_vals[i]);
00531         }
00532 
00533         isect_plane_plane_v3(plane_isect_1, plane_isect_1_no,
00534                              plane_tx[0], data_cb.normal_tx[0],
00535                              plane_tx[2], data_cb.normal_tx[2]);
00536         isect_plane_plane_v3(plane_isect_2, plane_isect_2_no,
00537                              plane_tx[1], data_cb.normal_tx[1],
00538                              plane_tx[3], data_cb.normal_tx[3]);
00539 
00540         add_v3_v3v3(plane_isect_1_other, plane_isect_1, plane_isect_1_no);
00541         add_v3_v3v3(plane_isect_2_other, plane_isect_2, plane_isect_2_no);
00542 
00543         if (isect_line_line_v3(plane_isect_1, plane_isect_1_other,
00544                                plane_isect_2, plane_isect_2_other,
00545                                plane_isect_pt_1, plane_isect_pt_2) == 0)
00546         {
00547             return FALSE;
00548         }
00549         else {
00550             float cam_plane_no[3]= {0.0f, 0.0f, -1.0f};
00551             float plane_isect_delta[3];
00552             float plane_isect_delta_len;
00553 
00554             mul_m3_v3(rot_obmat, cam_plane_no);
00555 
00556             sub_v3_v3v3(plane_isect_delta, plane_isect_pt_2, plane_isect_pt_1);
00557             plane_isect_delta_len= len_v3(plane_isect_delta);
00558 
00559             if (dot_v3v3(plane_isect_delta, cam_plane_no) > 0.0f) {
00560                 copy_v3_v3(r_co, plane_isect_pt_1);
00561 
00562                 /* offset shift */
00563                 normalize_v3(plane_isect_1_no);
00564                 madd_v3_v3fl(r_co, plane_isect_1_no, shift[1] * -plane_isect_delta_len);
00565             }
00566             else {
00567                 copy_v3_v3(r_co, plane_isect_pt_2);
00568 
00569                 /* offset shift */
00570                 normalize_v3(plane_isect_2_no);
00571                 madd_v3_v3fl(r_co, plane_isect_2_no, shift[0] * -plane_isect_delta_len);
00572             }
00573 
00574 
00575             return TRUE;
00576         }
00577     }
00578 }