diff options
author | Campbell Barton <ideasman42@gmail.com> | 2011-11-14 07:54:23 +0400 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2011-11-14 07:54:23 +0400 |
commit | a34fed3f2c1924c1487c4e159d3825697b08841c (patch) | |
tree | 497462f25d5ae94edce0515b6de2f01f8517f416 | |
parent | fea58943ecf32daa5bd828656d5e1157e6de984a (diff) |
VIEW3D_OT_camera_to_view_selected operator to move the camera to frame
all selected, renderable objects.
-rw-r--r-- | release/scripts/startup/bl_ui/space_view3d.py | 1 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_camera.h | 5 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_object.h | 11 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/camera.c | 107 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/object.c | 63 | ||||
-rw-r--r-- | source/blender/editors/space_view3d/view3d_intern.h | 3 | ||||
-rw-r--r-- | source/blender/editors/space_view3d/view3d_ops.c | 3 | ||||
-rw-r--r-- | source/blender/editors/space_view3d/view3d_view.c | 55 |
8 files changed, 243 insertions, 5 deletions
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 9ca542103ad..32ac4284267 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -366,6 +366,7 @@ class VIEW3D_MT_view_align(Menu): layout.operator("view3d.view_all", text="Center Cursor and View All").center = True layout.operator("view3d.camera_to_view", text="Align Active Camera to View") + layout.operator("view3d.camera_to_view_selected", text="Align Active Camera to Selected") layout.operator("view3d.view_selected") layout.operator("view3d.view_center_cursor") diff --git a/source/blender/blenkernel/BKE_camera.h b/source/blender/blenkernel/BKE_camera.h index d21c1092922..fc0ef0248f3 100644 --- a/source/blender/blenkernel/BKE_camera.h +++ b/source/blender/blenkernel/BKE_camera.h @@ -41,6 +41,7 @@ struct Object; struct RenderData; struct Scene; struct rctf; +struct View3D; void *add_camera(const char *name); struct Camera *copy_camera(struct Camera *cam); @@ -63,6 +64,10 @@ void camera_view_frame_ex(struct Scene *scene, struct Camera *camera, float draw void camera_view_frame(struct Scene *scene, struct Camera *camera, float r_vec[4][3]); +int camera_view_frame_fit_to_scene( + struct Scene *scene, struct View3D *v3d, struct Object *camera_ob, + float r_co[3]); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index ecc00901dd5..cb79c7a7290 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -110,6 +110,17 @@ void object_set_dimensions(struct Object *ob, const float *value); void object_boundbox_flag(struct Object *ob, int flag, int set); void minmax_object(struct Object *ob, float min[3], float max[3]); int minmax_object_duplis(struct Scene *scene, struct Object *ob, float *min, float *max); + +/* sometimes min-max isnt enough, we need to loop over each point */ +void BKE_object_foreach_display_point( + struct Object *ob, float obmat[4][4], + void (*func_cb)(const float[3], void *), void *user_data); +void BKE_scene_foreach_display_point( + struct Scene *scene, + struct View3D *v3d, + const short flag, + void (*func_cb)(const float[3], void *), void *user_data); + void solve_tracking (struct Object *ob, float targetmat[][4]); int ray_hit_boundbox(struct BoundBox *bb, float ray_start[3], float ray_normal[3]); diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c index 145eb9363e9..0f973273b32 100644 --- a/source/blender/blenkernel/intern/camera.c +++ b/source/blender/blenkernel/intern/camera.c @@ -41,6 +41,7 @@ #include "BKE_animsys.h" #include "BKE_camera.h" +#include "BKE_object.h" #include "BKE_global.h" #include "BKE_library.h" #include "BKE_main.h" @@ -394,3 +395,109 @@ void camera_view_frame(Scene *scene, Camera *camera, float r_vec[4][3]) dummy_asp, dummy_shift, &dummy_drawsize, r_vec); } + +typedef struct CameraViewFrameData { + float frame_tx[4][3]; + float normal_tx[4][3]; + float dist_vals[4]; + unsigned int tot; +} CameraViewFrameData; + +static void camera_to_frame_view_cb(const float co[3], void *user_data) +{ + CameraViewFrameData *data= (CameraViewFrameData *)user_data; + unsigned int i; + + for (i= 0; i < 4; i++) { + float nd= -dist_to_plane_v3(co, data->frame_tx[i], data->normal_tx[i]); + if (nd < data->dist_vals[i]) { + data->dist_vals[i]= nd; + } + } + + data->tot++; +} + +/* dont move the camera, just yield the fit location */ +int camera_view_frame_fit_to_scene(Scene *scene, struct View3D *v3d, Object *camera_ob, float r_co[3]) +{ + float plane_tx[4][3]; + float rot_obmat[3][3]; + const float zero[3]= {0,0,0}; + CameraViewFrameData data_cb; + + unsigned int i; + + camera_view_frame(scene, camera_ob->data, data_cb.frame_tx); + + copy_m3_m4(rot_obmat, camera_ob->obmat); + normalize_m3(rot_obmat); + + for (i= 0; i < 4; i++) { + mul_m3_v3(rot_obmat, data_cb.frame_tx[i]); + } + + for (i= 0; i < 4; i++) { + normal_tri_v3(data_cb.normal_tx[i], + zero, data_cb.frame_tx[i], data_cb.frame_tx[(i + 1) % 4]); + } + + /* initialize callback data */ + data_cb.dist_vals[0]= + data_cb.dist_vals[1]= + data_cb.dist_vals[2]= + data_cb.dist_vals[3]= FLT_MAX; + data_cb.tot= 0; + /* run callback on all visible points */ + BKE_scene_foreach_display_point(scene, v3d, BA_SELECT, + camera_to_frame_view_cb, &data_cb); + + if (data_cb.tot <= 1) { + return FALSE; + } + else { + float plane_isect_1[3], plane_isect_1_other[3]; + float plane_isect_2[3], plane_isect_2_other[3]; + + float plane_isect_pt_1[3], plane_isect_pt_2[3]; + + /* apply the dist-from-plane's to the transformed plane points */ + for (i= 0; i < 4; i++) { + mul_v3_v3fl(plane_tx[i], data_cb.normal_tx[i], data_cb.dist_vals[i]); + } + + if ( (isect_plane_plane_v3(plane_isect_1, plane_isect_1_other, + plane_tx[0], data_cb.normal_tx[0], + plane_tx[2], data_cb.normal_tx[2]) == 0) || + (isect_plane_plane_v3(plane_isect_2, plane_isect_2_other, + plane_tx[1], data_cb.normal_tx[1], + plane_tx[3], data_cb.normal_tx[3]) == 0)) + { + /* this is very unlikely */ + return FALSE; + } + else { + + add_v3_v3(plane_isect_1_other, plane_isect_1); + add_v3_v3(plane_isect_2_other, plane_isect_2); + + if (isect_line_line_v3(plane_isect_1, plane_isect_1_other, + plane_isect_2, plane_isect_2_other, + plane_isect_pt_1, plane_isect_pt_2) == 0) + { + return FALSE; + } + else { + float cam_plane_no[3]= {0.0f, 0.0f, -1.0f}; + float tvec[3]; + mul_m3_v3(rot_obmat, cam_plane_no); + + sub_v3_v3v3(tvec, plane_isect_pt_2, plane_isect_pt_1); + copy_v3_v3(r_co, dot_v3v3(tvec, cam_plane_no) > 0.0f ? + plane_isect_pt_1 : plane_isect_pt_2); + + return TRUE; + } + } + } +} diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 4e6bc4eee89..ffd49ecc57d 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -2333,6 +2333,69 @@ int minmax_object_duplis(Scene *scene, Object *ob, float *min, float *max) return ok; } +void BKE_object_foreach_display_point( + Object *ob, float obmat[4][4], + void (*func_cb)(const float[3], void *), void *user_data) +{ + float co[3]; + + if (ob->derivedFinal) { + DerivedMesh *dm= ob->derivedFinal; + MVert *mv= dm->getVertArray(dm); + int totvert= dm->getNumVerts(dm); + int i; + + for (i= 0; i < totvert; i++, mv++) { + mul_v3_m4v3(co, obmat, mv->co); + func_cb(co, user_data); + } + } + else if (ob->disp.first) { + DispList *dl; + + for (dl=ob->disp.first; dl; dl=dl->next) { + float *v3= dl->verts; + int totvert= dl->nr; + int i; + + for (i= 0; i < totvert; i++, v3+=3) { + mul_v3_m4v3(co, obmat, v3); + func_cb(co, user_data); + } + } + } +} + +void BKE_scene_foreach_display_point( + Scene *scene, View3D *v3d, const short flag, + void (*func_cb)(const float[3], void *), void *user_data) +{ + Base *base; + Object *ob; + + for(base= FIRSTBASE; base; base = base->next) { + if(BASE_VISIBLE(v3d, base) && (base->flag & flag) == flag) { + ob= base->object; + + if ((ob->transflag & OB_DUPLI)==0) { + BKE_object_foreach_display_point(ob, ob->obmat, func_cb, user_data); + } + else { + ListBase *lb; + DupliObject *dob; + + lb= object_duplilist(scene, ob); + for(dob= lb->first; dob; dob= dob->next) { + if(dob->no_draw == 0) { + BKE_object_foreach_display_point(dob->ob, dob->mat, func_cb, user_data); + } + } + free_object_duplilist(lb); /* does restore */ + } + } + } +} + /* copied from DNA_object_types.h */ typedef struct ObTfmBack { float loc[3], dloc[3], orig[3]; diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index fa2d5db21df..775cb45066a 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -155,7 +155,8 @@ void VIEW3D_OT_select_border(struct wmOperatorType *ot); void VIEW3D_OT_select_lasso(struct wmOperatorType *ot); void VIEW3D_OT_smoothview(struct wmOperatorType *ot); -void VIEW3D_OT_setcameratoview(struct wmOperatorType *ot); +void VIEW3D_OT_camera_to_view(struct wmOperatorType *ot); +void VIEW3D_OT_camera_to_view_selected(struct wmOperatorType *ot); void VIEW3D_OT_object_as_camera(struct wmOperatorType *ot); void VIEW3D_OT_localview(struct wmOperatorType *ot); void VIEW3D_OT_game_start(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c index 6e26fb15873..aeb850243c5 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -85,7 +85,8 @@ void view3d_operatortypes(void) WM_operatortype_append(VIEW3D_OT_enable_manipulator); WM_operatortype_append(VIEW3D_OT_cursor3d); WM_operatortype_append(VIEW3D_OT_select_lasso); - WM_operatortype_append(VIEW3D_OT_setcameratoview); + WM_operatortype_append(VIEW3D_OT_camera_to_view); + WM_operatortype_append(VIEW3D_OT_camera_to_view_selected); WM_operatortype_append(VIEW3D_OT_object_as_camera); WM_operatortype_append(VIEW3D_OT_localview); WM_operatortype_append(VIEW3D_OT_game_start); diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index cc0e93740ea..d2d6d6b0959 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -43,6 +43,7 @@ #include "BKE_anim.h" #include "BKE_action.h" +#include "BKE_camera.h" #include "BKE_context.h" #include "BKE_depsgraph.h" #include "BKE_object.h" @@ -406,9 +407,8 @@ static int view3d_setcameratoview_poll(bContext *C) return 0; } -void VIEW3D_OT_setcameratoview(wmOperatorType *ot) +void VIEW3D_OT_camera_to_view(wmOperatorType *ot) { - /* identifiers */ ot->name= "Align Camera To View"; ot->description= "Set camera view to active view"; @@ -422,6 +422,55 @@ void VIEW3D_OT_setcameratoview(wmOperatorType *ot) ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; } +/* unlike VIEW3D_OT_view_selected this is for framing a render and not + * meant to take into account vertex/bone selection for eg. */ +static int view3d_camera_to_view_selected_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Scene *scene= CTX_data_scene(C); + View3D *v3d = CTX_wm_view3d(C); + Object *camera_ob= v3d->camera; + + float r_co[3]; /* the new location to apply */ + + /* this function does all the important stuff */ + if (camera_view_frame_fit_to_scene(scene, v3d, camera_ob, r_co)) { + + ObjectTfmProtectedChannels obtfm; + float obmat_new[4][4]; + + copy_m4_m4(obmat_new, camera_ob->obmat); + copy_v3_v3(obmat_new[3], r_co); + + /* only touch location */ + object_tfm_protected_backup(camera_ob, &obtfm); + object_apply_mat4(camera_ob, obmat_new, TRUE, TRUE); + object_tfm_protected_restore(camera_ob, &obtfm, OB_LOCK_SCALE | OB_LOCK_ROT4D); + + /* notifiers */ + DAG_id_tag_update(&camera_ob->id, OB_RECALC_OB); + WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, camera_ob); + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +void VIEW3D_OT_camera_to_view_selected(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Camera Fit Frame to Selected"; + ot->description= "Move the camera so selected objects are framed"; + ot->idname= "VIEW3D_OT_camera_to_view_selected"; + + /* api callbacks */ + ot->exec= view3d_camera_to_view_selected_exec; + // ot->poll= view3d_setcameratoview_poll; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + static int view3d_setobjectascamera_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -461,7 +510,7 @@ void VIEW3D_OT_object_as_camera(wmOperatorType *ot) ot->idname= "VIEW3D_OT_object_as_camera"; /* api callbacks */ - ot->exec= view3d_setobjectascamera_exec; + ot->exec= view3d_setobjectascamera_exec; ot->poll= ED_operator_rv3d_unlock_poll; /* flags */ |