diff options
Diffstat (limited to 'source/blender/editors/space_view3d/view3d_view.c')
-rw-r--r-- | source/blender/editors/space_view3d/view3d_view.c | 245 |
1 files changed, 195 insertions, 50 deletions
diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index 5a3893f733f..e9cb6dcdc44 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -44,6 +44,7 @@ #include "BKE_camera.h" #include "BKE_context.h" #include "BKE_depsgraph.h" +#include "BKE_DerivedMesh.h" #include "BKE_object.h" #include "BKE_global.h" #include "BKE_main.h" @@ -609,6 +610,20 @@ void VIEW3D_OT_object_as_camera(wmOperatorType *ot) /* ********************************** */ +void ED_view3d_clipping_calc_from_boundbox(float clip[4][4], const BoundBox *bb, const bool is_flip) +{ + int val; + + for (val = 0; val < 4; val++) { + normal_tri_v3(clip[val], bb->vec[val], bb->vec[val == 3 ? 0 : val + 1], bb->vec[val + 4]); + if (UNLIKELY(is_flip)) { + negate_v3(clip[val]); + } + + clip[val][3] = -dot_v3v3(clip[val], bb->vec[val]); + } +} + void ED_view3d_clipping_calc(BoundBox *bb, float planes[4][4], bglMats *mats, const rcti *rect) { float modelview[4][4]; @@ -644,16 +659,7 @@ void ED_view3d_clipping_calc(BoundBox *bb, float planes[4][4], bglMats *mats, co ((float *)modelview)[a] = mats->modelview[a]; flip_sign = is_negative_m4(modelview); - /* then plane equations */ - for (val = 0; val < 4; val++) { - - normal_tri_v3(planes[val], bb->vec[val], bb->vec[val == 3 ? 0 : val + 1], bb->vec[val + 4]); - - if (flip_sign) - negate_v3(planes[val]); - - planes[val][3] = -dot_v3v3(planes[val], bb->vec[val]); - } + ED_view3d_clipping_calc_from_boundbox(planes, bb, flip_sign); } static bool view3d_boundbox_clip_m4(const BoundBox *bb, float persmatob[4][4]) @@ -683,7 +689,7 @@ static bool view3d_boundbox_clip_m4(const BoundBox *bb, float persmatob[4][4]) return false; } -bool ED_view3d_boundbox_clip_ex(RegionView3D *rv3d, const BoundBox *bb, float obmat[4][4]) +bool ED_view3d_boundbox_clip_ex(const RegionView3D *rv3d, const BoundBox *bb, float obmat[4][4]) { /* return 1: draw */ @@ -692,7 +698,7 @@ bool ED_view3d_boundbox_clip_ex(RegionView3D *rv3d, const BoundBox *bb, float ob if (bb == NULL) return true; if (bb->flag & BOUNDBOX_DISABLED) return true; - mul_m4_m4m4(persmatob, rv3d->persmat, obmat); + mul_m4_m4m4(persmatob, (float(*)[4])rv3d->persmat, obmat); return view3d_boundbox_clip_m4(bb, persmatob); } @@ -705,7 +711,7 @@ bool ED_view3d_boundbox_clip(RegionView3D *rv3d, const BoundBox *bb) return view3d_boundbox_clip_m4(bb, rv3d->persmatob); } -float ED_view3d_depth_read_cached(ViewContext *vc, int x, int y) +float ED_view3d_depth_read_cached(const ViewContext *vc, int x, int y) { ViewDepths *vd = vc->rv3d->depths; @@ -724,16 +730,19 @@ void ED_view3d_depth_tag_update(RegionView3D *rv3d) rv3d->depths->damaged = true; } -void ED_view3d_dist_range_get(struct View3D *v3d, - float r_dist_range[2]) +void ED_view3d_dist_range_get( + const View3D *v3d, + float r_dist_range[2]) { r_dist_range[0] = v3d->grid * 0.001f; r_dist_range[1] = v3d->far * 10.0f; } /* copies logic of get_view3d_viewplane(), keep in sync */ -bool ED_view3d_clip_range_get(View3D *v3d, RegionView3D *rv3d, float *r_clipsta, float *r_clipend, - const bool use_ortho_factor) +bool ED_view3d_clip_range_get( + const View3D *v3d, const RegionView3D *rv3d, + float *r_clipsta, float *r_clipend, + const bool use_ortho_factor) { CameraParams params; @@ -753,8 +762,9 @@ bool ED_view3d_clip_range_get(View3D *v3d, RegionView3D *rv3d, float *r_clipsta, } /* also exposed in previewrender.c */ -bool ED_view3d_viewplane_get(View3D *v3d, RegionView3D *rv3d, int winx, int winy, - rctf *r_viewplane, float *r_clipsta, float *r_clipend, float *r_pixsize) +bool ED_view3d_viewplane_get( + const View3D *v3d, const RegionView3D *rv3d, int winx, int winy, + rctf *r_viewplane, float *r_clipsta, float *r_clipend, float *r_pixsize) { CameraParams params; @@ -792,7 +802,7 @@ void ED_view3d_polygon_offset(const RegionView3D *rv3d, const float dist) /** * \param rect optional for picking (can be NULL). */ -void view3d_winmatrix_set(ARegion *ar, View3D *v3d, const rctf *rect) +void view3d_winmatrix_set(ARegion *ar, const View3D *v3d, const rctf *rect) { RegionView3D *rv3d = ar->regiondata; rctf viewplane; @@ -891,13 +901,28 @@ char ED_view3d_lock_view_from_index(int index) } +char ED_view3d_axis_view_opposite(char view) +{ + switch (view) { + case RV3D_VIEW_FRONT: return RV3D_VIEW_BACK; + case RV3D_VIEW_BACK: return RV3D_VIEW_FRONT; + case RV3D_VIEW_LEFT: return RV3D_VIEW_RIGHT; + case RV3D_VIEW_RIGHT: return RV3D_VIEW_LEFT; + case RV3D_VIEW_TOP: return RV3D_VIEW_BOTTOM; + case RV3D_VIEW_BOTTOM: return RV3D_VIEW_TOP; + } + + return RV3D_VIEW_USER; +} + + bool ED_view3d_lock(RegionView3D *rv3d) { return ED_view3d_quat_from_axis_view(rv3d->view, rv3d->viewquat); } /* don't set windows active in here, is used by renderwin too */ -void view3d_viewmatrix_set(Scene *scene, View3D *v3d, RegionView3D *rv3d) +void view3d_viewmatrix_set(Scene *scene, const View3D *v3d, RegionView3D *rv3d) { if (rv3d->persp == RV3D_CAMOB) { /* obs/camera */ if (v3d->camera) { @@ -936,7 +961,7 @@ void view3d_viewmatrix_set(Scene *scene, View3D *v3d, RegionView3D *rv3d) } else if (v3d->ob_centre_cursor) { float vec[3]; - copy_v3_v3(vec, ED_view3d_cursor3d_get(scene, v3d)); + copy_v3_v3(vec, ED_view3d_cursor3d_get(scene, (View3D *)v3d)); translate_m4(rv3d->viewmat, -vec[0], -vec[1], -vec[2]); use_lock_ofs = true; } @@ -1006,23 +1031,55 @@ static void view3d_select_loop(ViewContext *vc, Scene *scene, View3D *v3d, ARegi lb = object_duplilist(G.main->eval_ctx, scene, base->object); for (dob = lb->first; dob; dob = dob->next) { - float omat[4][4]; + /* for restoring after override */ + DupliObjectData *dob_data = NULL; + DerivedMesh *store_final_dm; + float store_obmat[4][4]; tbase.object = dob->ob; - copy_m4_m4(omat, dob->ob->obmat); + copy_m4_m4(store_obmat, dob->ob->obmat); copy_m4_m4(dob->ob->obmat, dob->mat); + store_final_dm = dob->ob->derivedFinal; /* extra service: draw the duplicator in drawtype of parent */ /* MIN2 for the drawtype to allow bounding box objects in groups for lods */ dt = tbase.object->dt; tbase.object->dt = MIN2(tbase.object->dt, base->object->dt); dtx = tbase.object->dtx; tbase.object->dtx = base->object->dtx; + /* override final DM */ + tbase.object->transflag &= ~OB_IS_DUPLI_CACHE; + if (base->object->dup_cache) { + dob_data = BKE_dupli_cache_find_data(base->object->dup_cache, tbase.object); + if (dob_data && dob_data->dm) { + tbase.object->transflag |= OB_IS_DUPLI_CACHE; + + tbase.object->derivedFinal = dob_data->dm; + } + } + draw_object(scene, ar, v3d, &tbase, DRAW_PICKING | DRAW_CONSTCOLOR); + /* restore final DM */ + if (tbase.object->transflag & OB_IS_DUPLI_CACHE) { + DerivedMesh *cur = tbase.object->derivedFinal; + + /* in some cases drawing code can recreate the derivedFinal, + * make sure we free those first before restoring + */ + if (cur && cur != dob_data->dm) { + cur->needsFree = 1; + cur->release(cur); + } + + tbase.object->transflag &= ~OB_IS_DUPLI_CACHE; + tbase.object->derivedFinal = store_final_dm; + } + tbase.object->dt = dt; tbase.object->dtx = dtx; - copy_m4_m4(dob->ob->obmat, omat); + /* restore obmat and final DM */ + copy_m4_m4(dob->ob->obmat, store_obmat); } free_object_duplilist(lb); } @@ -1194,7 +1251,7 @@ static bool view3d_localview_init( View3D *v3d = sa->spacedata.first; Base *base; float min[3], max[3], box[3], mid[3]; - float size = 0.0f, size_persp = 0.0f, size_ortho = 0.0f; + float size = 0.0f; unsigned int locallay; bool ok = false; @@ -1232,13 +1289,6 @@ static bool view3d_localview_init( sub_v3_v3v3(box, max, min); size = max_fff(box[0], box[1], box[2]); - - /* do not zoom closer than the near clipping plane */ - size = max_ff(size, v3d->near * 1.5f); - - /* perspective size (we always switch out of camera view so no need to use its lens size) */ - size_persp = ED_view3d_radius_to_persp_dist(focallength_to_fov(v3d->lens, DEFAULT_SENSOR_WIDTH), size / 2.0f) * VIEW3D_MARGIN; - size_ortho = ED_view3d_radius_to_ortho_dist(v3d->lens, size / 2.0f) * VIEW3D_MARGIN; } if (ok == true) { @@ -1255,6 +1305,7 @@ static bool view3d_localview_init( for (ar = sa->regionbase.first; ar; ar = ar->next) { if (ar->regiontype == RGN_TYPE_WINDOW) { RegionView3D *rv3d = ar->regiondata; + bool ok_dist = true; /* new view values */ Object *camera_old = NULL; @@ -1270,25 +1321,24 @@ static bool view3d_localview_init( camera_old = v3d->camera; } - /* perspective should be a bit farther away to look nice */ - if (rv3d->persp != RV3D_ORTHO) { - dist_new = size_persp; - } - else { - dist_new = size_ortho; + if (rv3d->persp == RV3D_ORTHO) { + if (size < 0.0001f) { + ok_dist = false; + } } - /* correction for window aspect ratio */ - if (ar->winy > 2 && ar->winx > 2) { - float asp = (float)ar->winx / (float)ar->winy; - if (asp < 1.0f) asp = 1.0f / asp; - dist_new *= asp; + if (ok_dist) { + dist_new = ED_view3d_radius_to_dist(v3d, ar, rv3d->persp, true, (size / 2) * VIEW3D_MARGIN); + if (rv3d->persp == RV3D_PERSP) { + /* don't zoom closer than the near clipping plane */ + dist_new = max_ff(dist_new, v3d->near * 1.5f); + } } ED_view3d_smooth_view_ex( wm, win, sa, v3d, ar, camera_old, NULL, - ofs_new, NULL, &dist_new, NULL, + ofs_new, NULL, ok_dist ? &dist_new : NULL, NULL, smooth_viewtx); } } @@ -1695,21 +1745,116 @@ void VIEW3D_OT_game_start(wmOperatorType *ot) /* ************************************** */ -float ED_view3d_pixel_size(RegionView3D *rv3d, const float co[3]) +float ED_view3d_pixel_size(const RegionView3D *rv3d, const float co[3]) { - return mul_project_m4_v3_zfac(rv3d->persmat, co) * rv3d->pixsize * U.pixelsize; + return mul_project_m4_v3_zfac((float(*)[4])rv3d->persmat, co) * rv3d->pixsize * U.pixelsize; } -float ED_view3d_radius_to_persp_dist(const float angle, const float radius) +float ED_view3d_radius_to_dist_persp(const float angle, const float radius) { - return (radius / 2.0f) * fabsf(1.0f / cosf((((float)M_PI) - angle) / 2.0f)); + return radius * (1.0f / tanf(angle / 2.0f)); } -float ED_view3d_radius_to_ortho_dist(const float lens, const float radius) +float ED_view3d_radius_to_dist_ortho(const float lens, const float radius) { return radius / (DEFAULT_SENSOR_WIDTH / lens); } +/** + * Return a new RegionView3D.dist value to fit the \a radius. + * + * \note Depth isn't taken into account, this will fit a flat plane exactly, + * but points towards the view (with a perspective projection), + * may be within the radius but outside the view. eg: + * + * <pre> + * + + * pt --> + /^ radius + * / | + * / | + * view + + + * \ | + * \ | + * \| + * + + * </pre> + * + * \param ar Can be NULL if \a use_aspect is false. + * \param persp Allow the caller to tell what kind of perspective to use (ortho/view/camera) + * \param use_aspect Increase the distance to account for non 1:1 view aspect. + * \param radius The radius will be fitted exactly, typically pre-scaled by a margin (#VIEW3D_MARGIN). + */ +float ED_view3d_radius_to_dist( + const View3D *v3d, const ARegion *ar, + const char persp, const bool use_aspect, + const float radius) +{ + float dist; + + BLI_assert(ELEM(persp, RV3D_ORTHO, RV3D_PERSP, RV3D_CAMOB)); + BLI_assert((persp != RV3D_CAMOB) || v3d->camera); + + if (persp == RV3D_ORTHO) { + dist = ED_view3d_radius_to_dist_ortho(v3d->lens, radius); + } + else { + float lens, sensor_size, zoom; + float angle; + + if (persp == RV3D_CAMOB) { + CameraParams params; + BKE_camera_params_init(¶ms); + params.clipsta = v3d->near; + params.clipend = v3d->far; + BKE_camera_params_from_object(¶ms, v3d->camera); + + lens = params.lens; + sensor_size = BKE_camera_sensor_size(params.sensor_fit, params.sensor_x, params.sensor_y); + + /* ignore 'rv3d->camzoom' because we wan't to fit to the cameras frame */ + zoom = CAMERA_PARAM_ZOOM_INIT_CAMOB; + } + else { + lens = v3d->lens; + sensor_size = DEFAULT_SENSOR_WIDTH; + zoom = CAMERA_PARAM_ZOOM_INIT_PERSP; + } + + angle = focallength_to_fov(lens, sensor_size); + + /* zoom influences lens, correct this by scaling the angle as a distance (by the zoom-level) */ + angle = atanf(tanf(angle / 2.0f) * zoom) * 2.0f; + + dist = ED_view3d_radius_to_dist_persp(angle, radius); + } + + if (use_aspect) { + const RegionView3D *rv3d = ar->regiondata; + + float winx, winy; + + if (persp == RV3D_CAMOB) { + /* camera frame x/y in pixels */ + winx = ar->winx / rv3d->viewcamtexcofac[0]; + winy = ar->winy / rv3d->viewcamtexcofac[1]; + } + else { + winx = ar->winx; + winy = ar->winy; + } + + if (winx && winy) { + float aspect = winx / winy; + if (aspect < 1.0f) { + aspect = 1.0f / aspect; + } + dist *= aspect; + } + } + + return dist; +} + /* view matrix properties utilities */ /* unused */ |