diff options
-rw-r--r-- | source/blender/blenlib/BLI_kdopbvh.h | 1 | ||||
-rw-r--r-- | source/blender/blenlib/intern/BLI_kdopbvh.c | 10 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_snap.c | 1 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_snap_object.c | 614 |
4 files changed, 417 insertions, 209 deletions
diff --git a/source/blender/blenlib/BLI_kdopbvh.h b/source/blender/blenlib/BLI_kdopbvh.h index 76c3b6ef3fd..e7cbe05d713 100644 --- a/source/blender/blenlib/BLI_kdopbvh.h +++ b/source/blender/blenlib/BLI_kdopbvh.h @@ -107,6 +107,7 @@ typedef void (*BVHTree_RangeQuery)(void *userdata, int index, const float co[3], typedef void (*BVHTree_NearestProjectedCallback)( void *userdata, int index, const struct DistProjectedAABBPrecalc *precalc, + const float (*clip_plane)[4], const int clip_plane_len, BVHTreeNearest *nearest); diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c index 5571636be63..b3adf3106c1 100644 --- a/source/blender/blenlib/intern/BLI_kdopbvh.c +++ b/source/blender/blenlib/intern/BLI_kdopbvh.c @@ -2040,7 +2040,10 @@ static void bvhtree_nearest_projected_dfs_recursive( { if (node->totnode == 0) { if (data->callback) { - data->callback(data->userdata, node->index, &data->precalc, &data->nearest); + data->callback( + data->userdata, node->index, &data->precalc, + NULL, 0, + &data->nearest); } else { data->nearest.index = node->index; @@ -2089,7 +2092,10 @@ static void bvhtree_nearest_projected_with_clipplane_test_dfs_recursive( { if (node->totnode == 0) { if (data->callback) { - data->callback(data->userdata, node->index, &data->precalc, &data->nearest); + data->callback( + data->userdata, node->index, &data->precalc, + data->clip_plane, data->clip_plane_len, + &data->nearest); } else { data->nearest.index = node->index; diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 681f955087a..87e46f996b9 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -1201,6 +1201,7 @@ bool snapObjectsTransform( &(const struct SnapObjectParams){ .snap_select = t->tsnap.modeSelect, .use_object_edit_cage = (t->flag & T_EDIT) != 0, + .use_occlusion_test = t->scene->toolsettings->snap_mode != SCE_SNAP_MODE_FACE, }, mval, dist_px, NULL, r_loc, r_no, NULL, diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index eb8fa0480ce..253cd53fb3e 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -71,6 +71,8 @@ /** Internal Data Types * \{ */ +#define MAX_CLIPPLANE_LEN 3 + enum eViewProj { VIEW_PROJ_NONE = -1, VIEW_PROJ_ORTHO = 0, @@ -80,12 +82,11 @@ enum eViewProj { typedef struct SnapData { short snap_to; float mval[2]; - float ray_start[3]; - float ray_dir[3]; float pmat[4][4]; /* perspective matrix */ float win_size[2];/* win x and y */ enum eViewProj view_proj; - float depth_range[2]; + float clip_plane[MAX_CLIPPLANE_LEN][4]; + short clip_plane_len; } SnapData; typedef struct SnapObjectData { @@ -196,38 +197,6 @@ static void iter_snap_objects( } -/** - * Generates a struct with the immutable parameters that will be used on all objects. - * - * \param snap_to: Element to snap, Vertice, Edge or Face. - * \param view_proj: ORTHO or PERSP. - * Currently only works one at a time, but can eventually operate as flag. - * - * \param mval: Mouse coords. - * (When NULL, ray-casting is handled without any projection matrix correction.) - * \param ray_origin: ray_start before being moved toward the ray_normal at the distance from vew3d clip_min. - * \param ray_start: ray_origin moved for the start clipping plane (clip_min). - * \param ray_direction: Unit length direction of the ray. - * \param depth_range: distances of clipe plane min and clip plane max; - */ -static void snap_data_set( - SnapData *snapdata, - const ARegion *ar, const unsigned short snap_to, const enum eViewProj view_proj, - const float mval[2], const float ray_start[3], const float ray_direction[3], - const float depth_range[2]) -{ - copy_m4_m4(snapdata->pmat, ((RegionView3D *)ar->regiondata)->persmat); - snapdata->win_size[0] = ar->winx; - snapdata->win_size[1] = ar->winy; - copy_v2_v2(snapdata->mval, mval); - snapdata->snap_to = snap_to; - copy_v3_v3(snapdata->ray_start, ray_start); - copy_v3_v3(snapdata->ray_dir, ray_direction); - snapdata->view_proj = view_proj; - copy_v2_v2(snapdata->depth_range, depth_range); -} - - MINLINE float depth_get(const float co[3], const float ray_start[3], const float ray_dir[3]) { float dvec[3]; @@ -682,7 +651,7 @@ static bool raycastObj( SnapObjectContext *sctx, const float ray_start[3], const float ray_dir[3], Object *ob, float obmat[4][4], const unsigned int ob_index, - bool use_obedit, + bool use_obedit, bool use_occlusion_test, /* read/write args */ float *ray_depth, /* return args */ @@ -692,6 +661,15 @@ static bool raycastObj( { bool retval = false; + if (use_occlusion_test) { + if (use_obedit && sctx->use_v3d && + !(sctx->v3d_data.v3d->flag & V3D_ZBUF_SELECT)) + { + /* Use of occlude geometry in editing mode disabled. */ + return; + } + } + switch (ob->type) { case OB_MESH: if (use_obedit) { @@ -739,16 +717,19 @@ struct RaycastObjUserData { Object **r_ob; float (*r_obmat)[4]; ListBase *r_hit_list; + bool use_occlusion_test; bool ret; }; static void raycast_obj_cb(SnapObjectContext *sctx, bool is_obedit, Object *ob, float obmat[4][4], void *data) { struct RaycastObjUserData *dt = data; + dt->ret |= raycastObj( sctx, dt->ray_start, dt->ray_dir, - ob, obmat, dt->ob_index++, is_obedit, + ob, obmat, dt->ob_index++, + is_obedit, dt->use_occlusion_test, dt->ray_depth, dt->r_loc, dt->r_no, dt->r_index, dt->r_ob, dt->r_obmat, @@ -805,6 +786,7 @@ static bool raycastObjects( .r_ob = r_ob, .r_obmat = r_obmat, .r_hit_list = r_hit_list, + .use_occlusion_test = params->use_occlusion_test, .ret = false, }; @@ -900,29 +882,26 @@ static void cb_mlooptri_verts_get( } static bool test_projected_vert_dist( - const struct DistProjectedAABBPrecalc *neasrest_precalc, - const float depth_range[2], + const struct DistProjectedAABBPrecalc *precalc, + const float (*clip_plane)[4], const int clip_plane_len, const bool is_persp, const float co[3], float *dist_px_sq, float r_co[3]) { - float w; - if (is_persp) { - w = mul_project_m4_v3_zfac(neasrest_precalc->pmat, co); - if (w < depth_range[0] || w > depth_range[1]) { - return false; - } + if (!isect_point_planes_v3_negated(clip_plane, clip_plane_len, co)) { + return false; } float co2d[2] = { - (dot_m4_v3_row_x(neasrest_precalc->pmat, co) + neasrest_precalc->pmat[3][0]), - (dot_m4_v3_row_y(neasrest_precalc->pmat, co) + neasrest_precalc->pmat[3][1]), + (dot_m4_v3_row_x(precalc->pmat, co) + precalc->pmat[3][0]), + (dot_m4_v3_row_y(precalc->pmat, co) + precalc->pmat[3][1]), }; if (is_persp) { + float w = mul_project_m4_v3_zfac(precalc->pmat, co); mul_v2_fl(co2d, 1.0f / w); } - const float dist_sq = len_squared_v2v2(neasrest_precalc->mval, co2d); + const float dist_sq = len_squared_v2v2(precalc->mval, co2d); if (dist_sq < *dist_px_sq) { copy_v3_v3(r_co, co); *dist_px_sq = dist_sq; @@ -932,23 +911,144 @@ static bool test_projected_vert_dist( } static bool test_projected_edge_dist( - const struct DistProjectedAABBPrecalc *neasrest_precalc, - const float depth_range[2], const bool is_persp, - const float va[3], const float vb[3], + const struct DistProjectedAABBPrecalc *precalc, + const float (*clip_plane)[4], const int clip_plane_len, + const bool is_persp, const float va[3], const float vb[3], float *dist_px_sq, float r_co[3]) { - float near_co[3], dummy_depth; dist_squared_ray_to_seg_v3( - neasrest_precalc->ray_origin, - neasrest_precalc->ray_direction, + precalc->ray_origin, + precalc->ray_direction, va, vb, near_co, &dummy_depth); return test_projected_vert_dist( - neasrest_precalc, depth_range, + precalc, clip_plane, clip_plane_len, is_persp, near_co, dist_px_sq, r_co); } +static bool snapMeshPolygon( + SnapObjectContext *sctx, SnapData *snapdata, + Object *ob, float obmat[4][4], + /* read/write args */ + float *dist_px, + /* return args */ + float r_loc[3], float r_no[3], int *r_index) +{ + bool retval = false; + + float lpmat[4][4], dist_px_sq = SQUARE(*dist_px); + mul_m4_m4m4(lpmat, snapdata->pmat, obmat); + + struct DistProjectedAABBPrecalc neasrest_precalc; + dist_squared_to_projected_aabb_precalc( + &neasrest_precalc, lpmat, snapdata->win_size, snapdata->mval); + + float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4]; + transpose_m4_m4(tobmat, obmat); + for (int i = snapdata->clip_plane_len; i--;) { + mul_v4_m4v4(clip_planes_local[i], tobmat, snapdata->clip_plane[i]); + } + + bool is_persp = snapdata->view_proj == VIEW_PROJ_PERSP; + + SnapObjectData *sod = BLI_ghash_lookup(sctx->cache.object_map, ob); + BLI_assert(sod != NULL); + + if (sod->type == SNAP_MESH) { + Mesh *me = ob->data; + MPoly *mp = &me->mpoly[*r_index]; + + const MLoop *ml = &me->mloop[mp->loopstart]; + for (int i = mp->totloop; i--; ml++) { + if (snapdata->snap_to == SCE_SNAP_MODE_VERTEX) { + const MVert *vert = &me->mvert[ml->v]; + if (test_projected_vert_dist( + &neasrest_precalc, + clip_planes_local, snapdata->clip_plane_len, + is_persp, vert->co, + &dist_px_sq, r_loc)) + { + normal_short_to_float_v3(r_no, vert->no); + *r_index = ml->v; + retval = true; + } + } + else { + float co_pair[2][3]; + const MEdge *edge = &me->medge[ml->e]; + copy_v3_v3(co_pair[0], me->mvert[edge->v1].co); + copy_v3_v3(co_pair[1], me->mvert[edge->v2].co); + if (test_projected_edge_dist( + &neasrest_precalc, + clip_planes_local, snapdata->clip_plane_len, + is_persp, co_pair[0], co_pair[1], + &dist_px_sq, r_loc)) + { + sub_v3_v3v3(r_no, co_pair[0], co_pair[1]); + *r_index = ml->e; + retval = true; + } + } + } + } + else { + BLI_assert(sod->type == SNAP_EDIT_MESH); + + BMEditMesh *em = BKE_editmesh_from_object(ob); + BM_mesh_elem_table_ensure(em->bm, BM_FACE); + BMFace *f = BM_face_at_index(em->bm, *r_index); + + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + + do { + if (snapdata->snap_to == SCE_SNAP_MODE_VERTEX) { + const float *co = l_iter->v->co; + if (test_projected_vert_dist( + &neasrest_precalc, + clip_planes_local, snapdata->clip_plane_len, + is_persp, co, + &dist_px_sq, r_loc)) + { + copy_v3_v3(r_no, l_iter->v->no); + *r_index = BM_elem_index_get(l_iter->v); + retval = true; + } + } + else { + float co_pair[2][3]; + copy_v3_v3(co_pair[0], l_iter->e->v1->co); + copy_v3_v3(co_pair[1], l_iter->e->v2->co); + if (test_projected_edge_dist( + &neasrest_precalc, + clip_planes_local, snapdata->clip_plane_len, + is_persp, co_pair[0], co_pair[1], + &dist_px_sq, r_loc)) + { + sub_v3_v3v3(r_no, co_pair[0], co_pair[1]); + *r_index = BM_elem_index_get(l_iter->e); + retval = true; + } + } + } while ((l_iter = l_iter->next) != l_first); + } + + if (retval) { + float imat[4][4]; + invert_m4_m4(imat, obmat); + + mul_m4_v3(obmat, r_loc); + mul_transposed_mat3_m4_v3(obmat, r_no); + normalize_v3(r_no); + + *dist_px = sqrtf(dist_px_sq); + + return true; + } + return false; +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -963,7 +1063,6 @@ typedef void (*Nearest2DCopyVertNoCallback)(const int index, float r_no[3], void typedef struct Nearest2dUserData { bool is_persp; - float depth_range[2]; short snap_to; void *userdata; @@ -979,6 +1078,7 @@ typedef struct Nearest2dUserData { static void cb_walk_leaf_snap_vert( void *userdata, int index, const struct DistProjectedAABBPrecalc *precalc, + const float (*clip_plane)[4], const int clip_plane_len, BVHTreeNearest *nearest) { struct Nearest2dUserData *data = userdata; @@ -988,9 +1088,9 @@ static void cb_walk_leaf_snap_vert( if (test_projected_vert_dist( precalc, - data->depth_range, - data->is_persp, - co, + clip_plane, + clip_plane_len, + data->is_persp, co, &nearest->dist_sq, nearest->co)) { @@ -1002,6 +1102,7 @@ static void cb_walk_leaf_snap_vert( static void cb_walk_leaf_snap_edge( void *userdata, int index, const struct DistProjectedAABBPrecalc *precalc, + const float (*clip_plane)[4], const int clip_plane_len, BVHTreeNearest *nearest) { struct Nearest2dUserData *data = userdata; @@ -1016,7 +1117,8 @@ static void cb_walk_leaf_snap_edge( if (test_projected_edge_dist( precalc, - data->depth_range, + clip_plane, + clip_plane_len, data->is_persp, v_pair[0], v_pair[1], &nearest->dist_sq, @@ -1031,7 +1133,9 @@ static void cb_walk_leaf_snap_edge( if (vindex[i] == nearest->index) { continue; } - cb_walk_leaf_snap_vert(userdata, vindex[i], precalc, nearest); + cb_walk_leaf_snap_vert( + userdata, vindex[i], precalc, + clip_plane, clip_plane_len, nearest); } } } @@ -1039,6 +1143,7 @@ static void cb_walk_leaf_snap_edge( static void cb_walk_leaf_snap_tri( void *userdata, int index, const struct DistProjectedAABBPrecalc *precalc, + const float (*clip_plane)[4], const int clip_plane_len, BVHTreeNearest *nearest) { struct Nearest2dUserData *data = userdata; @@ -1051,7 +1156,9 @@ static void cb_walk_leaf_snap_tri( if (eindex[i] == nearest->index) { continue; } - cb_walk_leaf_snap_edge(userdata, eindex[i], precalc, nearest); + cb_walk_leaf_snap_edge( + userdata, eindex[i], precalc, + clip_plane, clip_plane_len, nearest); } } } @@ -1062,7 +1169,9 @@ static void cb_walk_leaf_snap_tri( if (vindex[i] == nearest->index) { continue; } - cb_walk_leaf_snap_vert(userdata, vindex[i], precalc, nearest); + cb_walk_leaf_snap_vert( + userdata, vindex[i], precalc, + clip_plane, clip_plane_len, nearest); } } } @@ -1077,9 +1186,9 @@ static bool snapArmature( SnapData *snapdata, Object *ob, bArmature *arm, float obmat[4][4], /* read/write args */ - float *ray_depth, float *dist_px, + float *dist_px, /* return args */ - float r_loc[3], float *UNUSED(r_no)) + float r_loc[3], float *UNUSED(r_no), int *r_index) { bool retval = false; @@ -1107,6 +1216,12 @@ static bool snapArmature( } } + float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4]; + transpose_m4_m4(tobmat, obmat); + for (int i = snapdata->clip_plane_len; i--;) { + mul_v4_m4v4(clip_planes_local[i], tobmat, snapdata->clip_plane[i]); + } + bool is_persp = snapdata->view_proj == VIEW_PROJ_PERSP; if (arm->edbo) { @@ -1117,15 +1232,18 @@ static bool snapArmature( switch (snapdata->snap_to) { case SCE_SNAP_MODE_VERTEX: retval |= test_projected_vert_dist( - &neasrest_precalc, snapdata->depth_range, + &neasrest_precalc, + clip_planes_local, snapdata->clip_plane_len, is_persp, eBone->head, &dist_px_sq, r_loc); retval |= test_projected_vert_dist( - &neasrest_precalc, snapdata->depth_range, + &neasrest_precalc, + clip_planes_local, snapdata->clip_plane_len, is_persp, eBone->tail, &dist_px_sq, r_loc); break; case SCE_SNAP_MODE_EDGE: retval |= test_projected_edge_dist( - &neasrest_precalc, snapdata->depth_range, + &neasrest_precalc, + clip_planes_local, snapdata->clip_plane_len, is_persp, eBone->head, eBone->tail, &dist_px_sq, r_loc); break; @@ -1145,15 +1263,18 @@ static bool snapArmature( switch (snapdata->snap_to) { case SCE_SNAP_MODE_VERTEX: retval |= test_projected_vert_dist( - &neasrest_precalc, snapdata->depth_range, + &neasrest_precalc, + clip_planes_local, snapdata->clip_plane_len, is_persp, head_vec, &dist_px_sq, r_loc); retval |= test_projected_vert_dist( - &neasrest_precalc, snapdata->depth_range, + &neasrest_precalc, + clip_planes_local, snapdata->clip_plane_len, is_persp, tail_vec, &dist_px_sq, r_loc); break; case SCE_SNAP_MODE_EDGE: retval |= test_projected_edge_dist( - &neasrest_precalc, snapdata->depth_range, + &neasrest_precalc, + clip_planes_local, snapdata->clip_plane_len, is_persp, head_vec, tail_vec, &dist_px_sq, r_loc); break; @@ -1164,7 +1285,10 @@ static bool snapArmature( if (retval) { *dist_px = sqrtf(dist_px_sq); mul_m4_v3(obmat, r_loc); - *ray_depth = depth_get(r_loc, snapdata->ray_start, snapdata->ray_dir); + if (r_index) { + /* Does not support index. */ + *r_index = -1; + } return true; } return false; @@ -1174,9 +1298,9 @@ static bool snapCurve( SnapData *snapdata, Object *ob, float obmat[4][4], bool use_obedit, /* read/write args */ - float *ray_depth, float *dist_px, + float *dist_px, /* return args */ - float r_loc[3], float *UNUSED(r_no)) + float r_loc[3], float *UNUSED(r_no), int *r_index) { bool retval = false; @@ -1208,6 +1332,13 @@ static bool snapCurve( } } + + float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4]; + transpose_m4_m4(tobmat, obmat); + for (int i = snapdata->clip_plane_len; i--;) { + mul_v4_m4v4(clip_planes_local[i], tobmat, snapdata->clip_plane[i]); + } + bool is_persp = snapdata->view_proj == VIEW_PROJ_PERSP; for (Nurb *nu = (use_obedit ? cu->editnurb->nurbs.first : cu->nurb.first); nu; nu = nu->next) { @@ -1222,7 +1353,8 @@ static bool snapCurve( break; } retval |= test_projected_vert_dist( - &neasrest_precalc, snapdata->depth_range, + &neasrest_precalc, + clip_planes_local, snapdata->clip_plane_len, is_persp, nu->bezt[u].vec[1], &dist_px_sq, r_loc); /* don't snap if handle is selected (moving), or if it is aligning to a moving handle */ @@ -1230,7 +1362,8 @@ static bool snapCurve( !(nu->bezt[u].h1 & HD_ALIGN && nu->bezt[u].f3 & SELECT)) { retval |= test_projected_vert_dist( - &neasrest_precalc, snapdata->depth_range, + &neasrest_precalc, + clip_planes_local, snapdata->clip_plane_len, is_persp, nu->bezt[u].vec[0], &dist_px_sq, r_loc); } @@ -1238,7 +1371,8 @@ static bool snapCurve( !(nu->bezt[u].h2 & HD_ALIGN && nu->bezt[u].f1 & SELECT)) { retval |= test_projected_vert_dist( - &neasrest_precalc, snapdata->depth_range, + &neasrest_precalc, + clip_planes_local, snapdata->clip_plane_len, is_persp, nu->bezt[u].vec[2], &dist_px_sq, r_loc); } @@ -1249,7 +1383,8 @@ static bool snapCurve( break; } retval |= test_projected_vert_dist( - &neasrest_precalc, snapdata->depth_range, + &neasrest_precalc, + clip_planes_local, snapdata->clip_plane_len, is_persp, nu->bp[u].vec, &dist_px_sq, r_loc); } @@ -1259,13 +1394,15 @@ static bool snapCurve( if (nu->pntsu > 1) { if (nu->bezt) { retval |= test_projected_vert_dist( - &neasrest_precalc, snapdata->depth_range, + &neasrest_precalc, + clip_planes_local, snapdata->clip_plane_len, is_persp, nu->bezt[u].vec[1], &dist_px_sq, r_loc); } else { retval |= test_projected_vert_dist( - &neasrest_precalc, snapdata->depth_range, + &neasrest_precalc, + clip_planes_local, snapdata->clip_plane_len, is_persp, nu->bp[u].vec, &dist_px_sq, r_loc); } @@ -1279,7 +1416,10 @@ static bool snapCurve( if (retval) { *dist_px = sqrtf(dist_px_sq); mul_m4_v3(obmat, r_loc); - *ray_depth = depth_get(r_loc, snapdata->ray_start, snapdata->ray_dir); + if (r_index) { + /* Does not support index yet. */ + *r_index = -1; + } return true; } return false; @@ -1290,9 +1430,9 @@ static bool snapEmpty( SnapData *snapdata, Object *ob, float obmat[4][4], /* read/write args */ - float *ray_depth, float *dist_px, + float *dist_px, /* return args */ - float r_loc[3], float *UNUSED(r_no)) + float r_loc[3], float *UNUSED(r_no), int *r_index) { bool retval = false; @@ -1308,32 +1448,44 @@ static bool snapEmpty( dist_squared_to_projected_aabb_precalc( &neasrest_precalc, snapdata->pmat, snapdata->win_size, snapdata->mval); + float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4]; + transpose_m4_m4(tobmat, obmat); + for (int i = snapdata->clip_plane_len; i--;) { + mul_v4_m4v4(clip_planes_local[i], tobmat, snapdata->clip_plane[i]); + } + bool is_persp = snapdata->view_proj == VIEW_PROJ_PERSP; float dist_px_sq = SQUARE(*dist_px); float co[3]; copy_v3_v3(co, obmat[3]); if (test_projected_vert_dist( - &neasrest_precalc, snapdata->depth_range, + &neasrest_precalc, + clip_planes_local, snapdata->clip_plane_len, is_persp, co, &dist_px_sq, r_loc)) { *dist_px = sqrtf(dist_px_sq); - *ray_depth = depth_get(r_loc, snapdata->ray_start, snapdata->ray_dir); retval = true; } break; } } - return retval; + if (retval && r_index) { + /* Does not support index. */ + *r_index = -1; + return true; + } + + return false; } static bool snapCamera( const SnapObjectContext *sctx, SnapData *snapdata, Object *object, float obmat[4][4], /* read/write args */ - float *ray_depth, float *dist_px, + float *dist_px, /* return args */ - float r_loc[3], float *UNUSED(r_no)) + float r_loc[3], float *UNUSED(r_no), int *r_index) { Scene *scene = sctx->scene; @@ -1352,6 +1504,12 @@ static bool snapCamera( return retval; } + float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4]; + transpose_m4_m4(tobmat, obmat); + for (int i = snapdata->clip_plane_len; i--;) { + mul_v4_m4v4(clip_planes_local[i], tobmat, snapdata->clip_plane[i]); + } + tracking = &clip->tracking; BKE_tracking_get_camera_object_matrix(scene, object, orig_camera_mat); @@ -1402,7 +1560,8 @@ static bool snapCamera( mul_m4_v3(vertex_obmat, bundle_pos); retval |= test_projected_vert_dist( - &neasrest_precalc, snapdata->depth_range, + &neasrest_precalc, + clip_planes_local, snapdata->clip_plane_len, is_persp, bundle_pos, &dist_px_sq, r_loc); } } @@ -1413,7 +1572,10 @@ static bool snapCamera( if (retval) { *dist_px = sqrtf(dist_px_sq); - *ray_depth = depth_get(r_loc, snapdata->ray_start, snapdata->ray_dir); + if (r_index) { + /* Does not support index. */ + *r_index = -1; + } return true; } return false; @@ -1423,9 +1585,9 @@ static bool snapMesh( SnapObjectContext *sctx, SnapData *snapdata, Object *ob, Mesh *me, float obmat[4][4], /* read/write args */ - float *ray_depth, float *dist_px, + float *dist_px, /* return args */ - float r_loc[3], float r_no[3]) + float r_loc[3], float r_no[3], int *r_index) { bool retval = false; @@ -1553,15 +1715,8 @@ static bool snapMesh( } } - /* Warning: the depth_max is currently being used only in perspective view. - * It is not correct to limit the maximum depth for elements obtained with nearest - * since this limitation depends on the normal and the size of the occlusion face. - * And more... ray_depth is being confused with Z-depth here... (varies only the precision) */ - const float ray_depth_max_global = *ray_depth + snapdata->depth_range[0]; - Nearest2dUserData neasrest2d = { .is_persp = snapdata->view_proj == VIEW_PROJ_PERSP, - .depth_range = {snapdata->depth_range[0], ray_depth_max_global}, .snap_to = snapdata->snap_to, .userdata = treedata, .get_vert_co = (Nearest2DGetVertCoCallback)cb_mvert_co_get, @@ -1576,42 +1731,53 @@ static bool snapMesh( .dist_sq = dist_px_sq, }; + float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4]; + transpose_m4_m4(tobmat, obmat); + for (int i = snapdata->clip_plane_len; i--;) { + mul_v4_m4v4(clip_planes_local[i], tobmat, snapdata->clip_plane[i]); + } + if (bvhtree[1]) { /* snap to loose verts */ BLI_bvhtree_find_nearest_projected( bvhtree[1], lpmat, snapdata->win_size, snapdata->mval, - NULL, 0, &nearest, cb_walk_leaf_snap_vert, &neasrest2d); + clip_planes_local, snapdata->clip_plane_len, + &nearest, cb_walk_leaf_snap_vert, &neasrest2d); } if (bvhtree[0]) { /* snap to loose edges */ BLI_bvhtree_find_nearest_projected( bvhtree[0], lpmat, snapdata->win_size, snapdata->mval, - NULL, 0, &nearest, cb_walk_leaf_snap_edge, &neasrest2d); + clip_planes_local, snapdata->clip_plane_len, + &nearest, cb_walk_leaf_snap_edge, &neasrest2d); } if (treedata->tree) { /* snap to looptris */ BLI_bvhtree_find_nearest_projected( treedata->tree, lpmat, snapdata->win_size, snapdata->mval, - NULL, 0, &nearest, cb_walk_leaf_snap_tri, &neasrest2d); + clip_planes_local, snapdata->clip_plane_len, + &nearest, cb_walk_leaf_snap_tri, &neasrest2d); } if (nearest.index != -1) { - float imat[4][4]; - float timat[3][3]; /* transpose inverse matrix for normals */ - invert_m4_m4(imat, obmat); - transpose_m3_m4(timat, imat); + *dist_px = sqrtf(nearest.dist_sq); copy_v3_v3(r_loc, nearest.co); mul_m4_v3(obmat, r_loc); + if (r_no) { + float imat[4][4]; + invert_m4_m4(imat, obmat); + copy_v3_v3(r_no, nearest.no); - mul_m3_v3(timat, r_no); + mul_transposed_mat3_m4_v3(obmat, r_no); normalize_v3(r_no); } - *dist_px = sqrtf(nearest.dist_sq); - *ray_depth = depth_get(r_loc, snapdata->ray_start, snapdata->ray_dir); + if (r_index) { + *r_index = nearest.index; + } retval = true; } @@ -1623,9 +1789,9 @@ static bool snapEditMesh( SnapObjectContext *sctx, SnapData *snapdata, Object *ob, BMEditMesh *em, float obmat[4][4], /* read/write args */ - float *ray_depth, float *dist_px, + float *dist_px, /* return args */ - float r_loc[3], float r_no[3]) + float r_loc[3], float r_no[3], int *r_index) { bool retval = false; @@ -1713,7 +1879,6 @@ static bool snapEditMesh( Nearest2dUserData neasrest2d = { .is_persp = snapdata->view_proj == VIEW_PROJ_PERSP, - .depth_range = {snapdata->depth_range[0], *ray_depth + snapdata->depth_range[0]}, .snap_to = snapdata->snap_to, .userdata = treedata->em, .get_vert_co = (Nearest2DGetVertCoCallback)cb_bvert_co_get, @@ -1736,27 +1901,35 @@ static bool snapEditMesh( BM_mesh_elem_table_ensure(em->bm, BM_EDGE | BM_VERT); } - float lpmat[4][4]; + float lpmat[4][4], tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4]; mul_m4_m4m4(lpmat, snapdata->pmat, obmat); + transpose_m4_m4(tobmat, obmat); + + for (int i = snapdata->clip_plane_len; i--;) { + mul_v4_m4v4(clip_planes_local[i], tobmat, snapdata->clip_plane[i]); + } + BLI_bvhtree_find_nearest_projected( treedata->tree, lpmat, snapdata->win_size, snapdata->mval, - NULL, 0, &nearest, cb_walk_leaf, &neasrest2d); + clip_planes_local, snapdata->clip_plane_len, + &nearest, cb_walk_leaf, &neasrest2d); if (nearest.index != -1) { - float imat[4][4]; - float timat[3][3]; /* transpose inverse matrix for normals */ - invert_m4_m4(imat, obmat); - transpose_m3_m4(timat, imat); + *dist_px = sqrtf(nearest.dist_sq); copy_v3_v3(r_loc, nearest.co); mul_m4_v3(obmat, r_loc); if (r_no) { + float imat[4][4]; + invert_m4_m4(imat, obmat); + copy_v3_v3(r_no, nearest.no); - mul_m3_v3(timat, r_no); + mul_transposed_mat3_m4_v3(obmat, r_no); normalize_v3(r_no); } - *dist_px = sqrtf(nearest.dist_sq); - *ray_depth = depth_get(r_loc, snapdata->ray_start, snapdata->ray_dir); + if (r_index) { + *r_index = nearest.index; + } retval = true; } @@ -1773,9 +1946,9 @@ static bool snapObject( SnapObjectContext *sctx, SnapData *snapdata, Object *ob, float obmat[4][4], bool use_obedit, /* read/write args */ - float *ray_depth, float *dist_px, + float *dist_px, /* return args */ - float r_loc[3], float r_no[3], + float r_loc[3], float r_no[3], int *r_index, Object **r_ob, float r_obmat[4][4]) { bool retval = false; @@ -1786,14 +1959,14 @@ static bool snapObject( BMEditMesh *em = BKE_editmesh_from_object(ob); retval = snapEditMesh( sctx, snapdata, ob, em, obmat, - ray_depth, dist_px, - r_loc, r_no); + dist_px, + r_loc, r_no, r_index); } else { retval = snapMesh( sctx, snapdata, ob, ob->data, obmat, - ray_depth, dist_px, - r_loc, r_no); + dist_px, + r_loc, r_no, r_index); } break; @@ -1801,30 +1974,30 @@ static bool snapObject( retval = snapArmature( snapdata, ob, ob->data, obmat, - ray_depth, dist_px, - r_loc, r_no); + dist_px, + r_loc, r_no, r_index); break; case OB_CURVE: retval = snapCurve( snapdata, ob, obmat, use_obedit, - ray_depth, dist_px, - r_loc, r_no); + dist_px, + r_loc, r_no, r_index); break; case OB_EMPTY: retval = snapEmpty( snapdata, ob, obmat, - ray_depth, dist_px, - r_loc, r_no); + dist_px, + r_loc, r_no, r_index); break; case OB_CAMERA: retval = snapCamera( sctx, snapdata, ob, obmat, - ray_depth, dist_px, - r_loc, r_no); + dist_px, + r_loc, r_no, r_index); break; } @@ -1845,11 +2018,11 @@ static bool snapObject( struct SnapObjUserData { SnapData *snapdata; /* read/write args */ - float *ray_depth; float *dist_px; /* return args */ float *r_loc; float *r_no; + int *r_index; Object **r_ob; float (*r_obmat)[4]; bool ret; @@ -1862,9 +2035,9 @@ static void sanp_obj_cb(SnapObjectContext *sctx, bool is_obedit, Object *ob, flo sctx, dt->snapdata, ob, obmat, is_obedit, /* read/write args */ - dt->ray_depth, dt->dist_px, + dt->dist_px, /* return args */ - dt->r_loc, dt->r_no, + dt->r_loc, dt->r_no, dt->r_index, dt->r_ob, dt->r_obmat); } @@ -1901,18 +2074,18 @@ static bool snapObjectsRay( SnapObjectContext *sctx, SnapData *snapdata, const struct SnapObjectParams *params, /* read/write args */ - float *ray_depth, float *dist_px, + float *dist_px, /* return args */ - float r_loc[3], float r_no[3], + float r_loc[3], float r_no[3], int *r_index, Object **r_ob, float r_obmat[4][4]) { struct SnapObjUserData data = { .snapdata = snapdata, - .ray_depth = ray_depth, .dist_px = dist_px, .r_loc = r_loc, .r_no = r_no, .r_ob = r_ob, + .r_index = r_index, .r_obmat = r_obmat, .ret = false, }; @@ -2111,53 +2284,25 @@ static bool transform_snap_context_project_view3d_mixed_impl( const float mval[2], float *dist_px, float r_co[3], float r_no[3]) { - float ray_depth = BVH_RAYCAST_DIST_MAX; - bool is_hit = false; - const int elem_type[3] = {SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE, SCE_SNAP_MODE_FACE}; BLI_assert(snap_to_flag != 0); BLI_assert((snap_to_flag & ~(1 | 2 | 4)) == 0); - if (params->use_occlusion_test) { - const float dist_px_orig = dist_px ? *dist_px : 0; - for (int i = 2; i >= 0; i--) { - if (snap_to_flag & (1 << i)) { - if (i == 0) { - BLI_assert(dist_px != NULL); - *dist_px = dist_px_orig; - } - if (ED_transform_snap_object_project_view3d( - sctx, - elem_type[i], params, - mval, dist_px, &ray_depth, - r_co, r_no)) - { - /* 0.01 is a random but small value to prioritizing - * the first elements of the loop */ - ray_depth += 0.01f; - is_hit = true; - } - } - } - } - else { - for (int i = 0; i < 3; i++) { - if (snap_to_flag & (1 << i)) { - if (ED_transform_snap_object_project_view3d( - sctx, - elem_type[i], params, - mval, dist_px, &ray_depth, - r_co, r_no)) - { - is_hit = true; - break; - } + for (int i = 0; i < 3; i++) { + if (snap_to_flag & (1 << i)) { + if (ED_transform_snap_object_project_view3d( + sctx, + elem_type[i], params, + mval, dist_px, NULL, + r_co, r_no)) + { + return true; } } } - return is_hit; + return false; } /** @@ -2195,51 +2340,106 @@ bool ED_transform_snap_object_project_view3d_ex( float r_loc[3], float r_no[3], int *r_index, Object **r_ob, float r_obmat[4][4]) { + float loc[3], no[3], obmat[4][4]; + Object *ob = NULL; + + int index_fallback; + if (r_index == NULL) { + r_index = &index_fallback; + } + + bool has_hit = false, retval = false; const ARegion *ar = sctx->v3d_data.ar; const RegionView3D *rv3d = ar->regiondata; - float ray_origin[3], ray_end[3], ray_start[3], ray_normal[3], depth_range[2]; + if (snap_to == SCE_SNAP_MODE_FACE || params->use_occlusion_test) { + float ray_origin[3], ray_end[3], ray_start[3], ray_normal[3], depth_range[2]; - ED_view3d_win_to_origin(ar, mval, ray_origin); - ED_view3d_win_to_vector(ar, mval, ray_normal); + ED_view3d_win_to_origin(ar, mval, ray_origin); + ED_view3d_win_to_vector(ar, mval, ray_normal); - ED_view3d_clip_range_get( - sctx->depsgraph, - sctx->v3d_data.v3d, sctx->v3d_data.ar->regiondata, - &depth_range[0], &depth_range[1], false); + ED_view3d_clip_range_get( + sctx->depsgraph, + sctx->v3d_data.v3d, sctx->v3d_data.ar->regiondata, + &depth_range[0], &depth_range[1], false); - madd_v3_v3v3fl(ray_start, ray_origin, ray_normal, depth_range[0]); - madd_v3_v3v3fl(ray_end, ray_origin, ray_normal, depth_range[1]); + madd_v3_v3v3fl(ray_start, ray_origin, ray_normal, depth_range[0]); + madd_v3_v3v3fl(ray_end, ray_origin, ray_normal, depth_range[1]); - if (!ED_view3d_clip_segment(rv3d, ray_start, ray_end)) { - return false; - } + if (!ED_view3d_clip_segment(rv3d, ray_start, ray_end)) { + return false; + } - float ray_depth_fallback; - if (ray_depth == NULL) { - ray_depth_fallback = BVH_RAYCAST_DIST_MAX; - ray_depth = &ray_depth_fallback; - } + float ray_depth_fallback; + if (ray_depth == NULL) { + ray_depth_fallback = BVH_RAYCAST_DIST_MAX; + ray_depth = &ray_depth_fallback; + } - if (snap_to == SCE_SNAP_MODE_FACE) { - return raycastObjects( + has_hit = raycastObjects( sctx, params, ray_start, ray_normal, - ray_depth, r_loc, r_no, r_index, r_ob, r_obmat, NULL); + &ray_depth_fallback, loc, no, + r_index, &ob, obmat, NULL); + + retval = has_hit && (snap_to == SCE_SNAP_MODE_FACE); } - else { + + if (ELEM(snap_to, SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE)) { SnapData snapdata; - const enum eViewProj view_proj = rv3d->is_persp ? - VIEW_PROJ_PERSP : VIEW_PROJ_ORTHO; - snap_data_set( - &snapdata, ar, snap_to, view_proj, mval, - ray_start, ray_normal, depth_range); + copy_m4_m4(snapdata.pmat, rv3d->persmat); + snapdata.win_size[0] = ar->winx; + snapdata.win_size[1] = ar->winy; + copy_v2_v2(snapdata.mval, mval); + snapdata.snap_to = snap_to; + snapdata.view_proj = rv3d->is_persp ? VIEW_PROJ_PERSP : VIEW_PROJ_ORTHO; + + planes_from_projmat( + snapdata.pmat, + NULL, NULL, NULL, NULL, + snapdata.clip_plane[0], snapdata.clip_plane[1]); + + snapdata.clip_plane_len = 2; + + if (has_hit) { + /* Compute the new clip_pane but do not add it yet. */ + float new_clipplane[4]; + plane_from_point_normal_v3(new_clipplane, loc, no); + + /* Try to snap only to the polygon. */ + retval |= snapMeshPolygon( + sctx, &snapdata, ob, obmat, + dist_px, loc, no, r_index); + + /* Add the new clip plane to the beginning of the list. */ + for (int i = snapdata.clip_plane_len; i != 0; i--) { + copy_v4_v4(snapdata.clip_plane[i], snapdata.clip_plane[i - 1]); + } + copy_v4_v4(snapdata.clip_plane[0], new_clipplane); + snapdata.clip_plane_len++; + } - return snapObjectsRay( + retval |= snapObjectsRay( sctx, &snapdata, params, - ray_depth, dist_px, r_loc, r_no, r_ob, r_obmat); + dist_px, loc, no, r_index, &ob, obmat); + } + + if (retval) { + copy_v3_v3(r_loc, loc); + if (r_no) { + copy_v3_v3(r_no, no); + } + if (r_ob) { + *r_ob = ob; + } + if (r_obmat) { + copy_m4_m4(r_obmat, obmat); + } + return true; } + + return false; } bool ED_transform_snap_object_project_view3d( |