2 * ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
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.
18 * ***** END GPL LICENSE BLOCK *****
21 /** \file blender/editors/transform/transform_snap_object.c
22 * \ingroup edtransform
30 #include "MEM_guardedalloc.h"
33 #include "BLI_kdopbvh.h"
34 #include "BLI_memarena.h"
35 #include "BLI_ghash.h"
36 #include "BLI_linklist.h"
37 #include "BLI_listbase.h"
38 #include "BLI_utildefines.h"
40 #include "DNA_armature_types.h"
41 #include "DNA_curve_types.h"
42 #include "DNA_scene_types.h"
43 #include "DNA_object_types.h"
44 #include "DNA_meshdata_types.h"
45 #include "DNA_screen_types.h"
46 #include "DNA_view3d_types.h"
48 #include "BKE_DerivedMesh.h"
49 #include "BKE_object.h"
50 #include "BKE_anim.h" /* for duplis */
51 #include "BKE_editmesh.h"
53 #include "BKE_tracking.h"
55 #include "ED_transform.h"
56 #include "ED_transform_snap_object_context.h"
57 #include "ED_view3d.h"
58 #include "ED_armature.h"
60 #include "transform.h"
62 typedef struct SnapObjectData {
69 typedef struct SnapObjectData_Mesh {
71 BVHTreeFromMesh *bvh_trees[2];
73 } SnapObjectData_Mesh;
75 typedef struct SnapObjectData_EditMesh {
77 BVHTreeFromEditMesh *bvh_trees[2];
79 } SnapObjectData_EditMesh;
81 struct SnapObjectContext {
86 /* Optional: when performing screen-space projection.
87 * otherwise this doesn't take viewport into account. */
95 /* Object -> SnapObjectData map */
101 /* Filter data, returns true to check this value */
104 bool (*test_vert_fn)(BMVert *, void *user_data);
105 bool (*test_edge_fn)(BMEdge *, void *user_data);
106 bool (*test_face_fn)(BMFace *, void *user_data);
113 static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt);
116 /* -------------------------------------------------------------------- */
118 /** \name Support for storing all depths, not just the first (raycast 'all')
120 * This uses a list of #SnapObjectHitDepth structs.
124 /* Store all ray-hits */
125 struct RayCastAll_Data {
128 /* internal vars for adding depths */
129 BVHTree_RayCastCallback raycast_callback;
131 const float(*obmat)[4];
132 const float(*timat)[3];
138 unsigned int ob_uuid;
140 /* DerivedMesh only */
142 const struct MLoopTri *dm_looptri;
149 static struct SnapObjectHitDepth *hit_depth_create(
150 const float depth, const float co[3], const float no[3], int index,
151 Object *ob, const float obmat[4][4], unsigned int ob_uuid)
153 struct SnapObjectHitDepth *hit = MEM_mallocN(sizeof(*hit), __func__);
156 copy_v3_v3(hit->co, co);
157 copy_v3_v3(hit->no, no);
161 copy_m4_m4(hit->obmat, (float(*)[4])obmat);
162 hit->ob_uuid = ob_uuid;
167 static int hit_depth_cmp(const void *arg1, const void *arg2)
169 const struct SnapObjectHitDepth *h1 = arg1;
170 const struct SnapObjectHitDepth *h2 = arg2;
173 if (h1->depth < h2->depth) {
176 else if (h1->depth > h2->depth) {
183 static void raycast_all_cb(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
185 struct RayCastAll_Data *data = userdata;
186 data->raycast_callback(data->bvhdata, index, ray, hit);
187 if (hit->index != -1) {
188 /* get all values in worldspace */
189 float location[3], normal[3];
192 /* worldspace location */
193 mul_v3_m4v3(location, (float(*)[4])data->obmat, hit->co);
194 depth = (hit->dist + data->len_diff) / data->local_scale;
196 /* worldspace normal */
197 copy_v3_v3(normal, hit->no);
198 mul_m3_v3((float(*)[3])data->timat, normal);
199 normalize_v3(normal);
201 /* currently unused, and causes issues when looptri's havn't been calculated.
202 * since theres some overhead in ensuring this data is valid, it may need to be optional. */
205 hit->index = dm_looptri_to_poly_index(data->dm, &data->dm_looptri[hit->index]);
209 struct SnapObjectHitDepth *hit_item = hit_depth_create(
210 depth, location, normal, hit->index,
211 data->ob, data->obmat, data->ob_uuid);
212 BLI_addtail(data->hit_list, hit_item);
219 /* -------------------------------------------------------------------- */
221 /** \name Internal Object Snapping API
224 static bool snapEdge(
225 ARegion *ar, const float v1co[3], const short v1no[3], const float v2co[3], const short v2no[3],
226 float obmat[4][4], float timat[3][3], const float mval_fl[2], float *dist_px,
227 const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], float *ray_depth,
228 float r_loc[3], float r_no[3])
230 float intersect[3] = {0, 0, 0}, ray_end[3], dvec[3];
234 copy_v3_v3(ray_end, ray_normal_local);
235 mul_v3_fl(ray_end, 2000);
236 add_v3_v3v3(ray_end, ray_start_local, ray_end);
238 /* dvec used but we don't care about result */
239 result = isect_line_line_v3(v1co, v2co, ray_start_local, ray_end, intersect, dvec);
242 float edge_loc[3], vec[3];
245 /* check for behind ray_start */
246 sub_v3_v3v3(dvec, intersect, ray_start_local);
248 sub_v3_v3v3(edge_loc, v1co, v2co);
249 sub_v3_v3v3(vec, intersect, v2co);
251 mul = dot_v3v3(vec, edge_loc) / dot_v3v3(edge_loc, edge_loc);
255 copy_v3_v3(intersect, v1co);
259 copy_v3_v3(intersect, v2co);
262 if (dot_v3v3(ray_normal_local, dvec) > 0) {
268 copy_v3_v3(location, intersect);
270 mul_m4_v3(obmat, location);
272 new_depth = len_v3v3(location, ray_start);
274 if (ED_view3d_project_float_global(ar, location, screen_loc, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
275 new_dist = len_manhattan_v2v2(mval_fl, screen_loc);
278 new_dist = TRANSFORM_DIST_MAX_PX;
281 /* 10% threshold if edge is closer but a bit further
282 * this takes care of series of connected edges a bit slanted w.r.t the viewport
283 * otherwise, it would stick to the verts of the closest edge and not slide along merrily
285 if (new_dist <= *dist_px && new_depth < *ray_depth * 1.001f) {
288 *ray_depth = new_depth;
291 sub_v3_v3v3(edge_loc, v1co, v2co);
292 sub_v3_v3v3(vec, intersect, v2co);
294 mul = dot_v3v3(vec, edge_loc) / dot_v3v3(edge_loc, edge_loc);
297 normal_short_to_float_v3(n1, v1no);
298 normal_short_to_float_v3(n2, v2no);
299 interp_v3_v3v3(r_no, n2, n1, mul);
300 mul_m3_v3(timat, r_no);
304 copy_v3_v3(r_loc, location);
314 static bool snapVertex(
315 ARegion *ar, const float vco[3], const float vno[3],
316 float obmat[4][4], float timat[3][3], const float mval_fl[2], float *dist_px,
317 const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], float *ray_depth,
318 float r_loc[3], float r_no[3])
323 sub_v3_v3v3(dvec, vco, ray_start_local);
325 if (dot_v3v3(ray_normal_local, dvec) > 0) {
331 copy_v3_v3(location, vco);
333 mul_m4_v3(obmat, location);
335 new_depth = len_v3v3(location, ray_start);
337 if (ED_view3d_project_float_global(ar, location, screen_loc, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
338 new_dist = len_manhattan_v2v2(mval_fl, screen_loc);
341 new_dist = TRANSFORM_DIST_MAX_PX;
345 if (new_dist <= *dist_px && new_depth < *ray_depth) {
346 *ray_depth = new_depth;
349 copy_v3_v3(r_loc, location);
352 copy_v3_v3(r_no, vno);
353 mul_m3_v3(timat, r_no);
364 static bool snapArmature(
365 ARegion *ar, Object *ob, bArmature *arm, float obmat[4][4],
366 const float mval[2], float *dist_px, const short snap_to,
367 const float ray_start[3], const float ray_normal[3], float *ray_depth,
368 float r_loc[3], float *UNUSED(r_no))
371 float ray_start_local[3], ray_normal_local[3];
374 invert_m4_m4(imat, obmat);
376 mul_v3_m4v3(ray_start_local, imat, ray_start);
377 mul_v3_mat3_m4v3(ray_normal_local, imat, ray_normal);
382 for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
383 if (eBone->layer & arm->layer) {
384 /* skip hidden or moving (selected) bones */
385 if ((eBone->flag & (BONE_HIDDEN_A | BONE_ROOTSEL | BONE_TIPSEL)) == 0) {
387 case SCE_SNAP_MODE_VERTEX:
388 retval |= snapVertex(
389 ar, eBone->head, NULL, obmat, NULL, mval, dist_px,
390 ray_start, ray_start_local, ray_normal_local, ray_depth,
392 retval |= snapVertex(
393 ar, eBone->tail, NULL, obmat, NULL, mval, dist_px,
394 ray_start, ray_start_local, ray_normal_local, ray_depth,
397 case SCE_SNAP_MODE_EDGE:
399 ar, eBone->head, NULL, eBone->tail, NULL,
400 obmat, NULL, mval, dist_px,
401 ray_start, ray_start_local, ray_normal_local,
402 ray_depth, r_loc, NULL);
409 else if (ob->pose && ob->pose->chanbase.first) {
413 for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
415 /* skip hidden bones */
416 if (bone && !(bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG))) {
417 const float *head_vec = pchan->pose_head;
418 const float *tail_vec = pchan->pose_tail;
421 case SCE_SNAP_MODE_VERTEX:
422 retval |= snapVertex(
423 ar, head_vec, NULL, obmat, NULL, mval, dist_px,
424 ray_start, ray_start_local, ray_normal_local,
425 ray_depth, r_loc, NULL);
426 retval |= snapVertex(
427 ar, tail_vec, NULL, obmat, NULL, mval, dist_px,
428 ray_start, ray_start_local, ray_normal_local, ray_depth,
431 case SCE_SNAP_MODE_EDGE:
433 ar, head_vec, NULL, tail_vec, NULL,
434 obmat, NULL, mval, dist_px,
435 ray_start, ray_start_local, ray_normal_local,
436 ray_depth, r_loc, NULL);
446 static bool snapCurve(
447 ARegion *ar, Object *ob, Curve *cu, float obmat[4][4],
448 const float mval[2], float *dist_px, const short snap_to,
449 const float ray_start[3], const float ray_normal[3], float *ray_depth,
450 float r_loc[3], float *UNUSED(r_no))
453 float ray_start_local[3], ray_normal_local[3];
459 /* only vertex snapping mode (eg control points and handles) supported for now) */
460 if (snap_to != SCE_SNAP_MODE_VERTEX) {
464 invert_m4_m4(imat, obmat);
466 copy_v3_v3(ray_start_local, ray_start);
467 copy_v3_v3(ray_normal_local, ray_normal);
469 mul_m4_v3(imat, ray_start_local);
470 mul_mat3_m4_v3(imat, ray_normal_local);
472 for (nu = (ob->mode == OB_MODE_EDIT ? cu->editnurb->nurbs.first : cu->nurb.first); nu; nu = nu->next) {
473 for (u = 0; u < nu->pntsu; u++) {
475 case SCE_SNAP_MODE_VERTEX:
477 if (ob->mode == OB_MODE_EDIT) {
479 /* don't snap to selected (moving) or hidden */
480 if (nu->bezt[u].f2 & SELECT || nu->bezt[u].hide != 0) {
483 retval |= snapVertex(
484 ar, nu->bezt[u].vec[1], NULL, obmat, NULL, mval, dist_px,
485 ray_start, ray_start_local, ray_normal_local, ray_depth,
487 /* don't snap if handle is selected (moving), or if it is aligning to a moving handle */
488 if (!(nu->bezt[u].f1 & SELECT) &&
489 !(nu->bezt[u].h1 & HD_ALIGN && nu->bezt[u].f3 & SELECT))
491 retval |= snapVertex(
492 ar, nu->bezt[u].vec[0], NULL, obmat, NULL, mval, dist_px,
493 ray_start, ray_start_local, ray_normal_local, ray_depth,
496 if (!(nu->bezt[u].f3 & SELECT) &&
497 !(nu->bezt[u].h2 & HD_ALIGN && nu->bezt[u].f1 & SELECT))
499 retval |= snapVertex(
500 ar, nu->bezt[u].vec[2], NULL, obmat, NULL, mval, dist_px,
501 ray_start, ray_start_local, ray_normal_local, ray_depth,
506 /* don't snap to selected (moving) or hidden */
507 if (nu->bp[u].f1 & SELECT || nu->bp[u].hide != 0) {
510 retval |= snapVertex(
511 ar, nu->bp[u].vec, NULL, obmat, NULL, mval, dist_px,
512 ray_start, ray_start_local, ray_normal_local, ray_depth,
517 /* curve is not visible outside editmode if nurb length less than two */
520 retval |= snapVertex(
521 ar, nu->bezt[u].vec[1], NULL, obmat, NULL, mval, dist_px,
522 ray_start, ray_start_local, ray_normal_local, ray_depth,
526 retval |= snapVertex(
527 ar, nu->bp[u].vec, NULL, obmat, NULL, mval, dist_px,
528 ray_start, ray_start_local, ray_normal_local, ray_depth,
543 /* may extend later (for now just snaps to empty center) */
544 static bool snapEmpty(
545 ARegion *ar, Object *ob, float obmat[4][4],
546 const float mval[2], float *dist_px, const short snap_to,
547 const float ray_start[3], const float ray_normal[3], float *ray_depth,
548 float r_loc[3], float *UNUSED(r_no))
551 float ray_start_local[3], ray_normal_local[3];
554 if (ob->transflag & OB_DUPLI) {
557 /* for now only vertex supported */
558 if (snap_to != SCE_SNAP_MODE_VERTEX) {
562 invert_m4_m4(imat, obmat);
564 mul_v3_m4v3(ray_start_local, imat, ray_start);
565 mul_v3_mat3_m4v3(ray_normal_local, imat, ray_normal);
568 case SCE_SNAP_MODE_VERTEX:
570 const float zero_co[3] = {0.0f};
571 retval |= snapVertex(
572 ar, zero_co, NULL, obmat, NULL, mval, dist_px,
573 ray_start, ray_start_local, ray_normal_local, ray_depth,
584 static bool snapCamera(
585 ARegion *ar, Scene *scene, Object *object, float obmat[4][4],
586 const float mval[2], float *dist_px, const short snap_to,
587 const float ray_start[3], const float ray_normal[3], float *ray_depth,
588 float r_loc[3], float *UNUSED(r_no))
590 float orig_camera_mat[4][4], orig_camera_imat[4][4], imat[4][4];
592 MovieClip *clip = BKE_object_movieclip_get(scene, object, false);
593 MovieTracking *tracking;
594 float ray_start_local[3], ray_normal_local[3];
599 if (object->transflag & OB_DUPLI) {
603 tracking = &clip->tracking;
605 BKE_tracking_get_camera_object_matrix(scene, object, orig_camera_mat);
607 invert_m4_m4(orig_camera_imat, orig_camera_mat);
608 invert_m4_m4(imat, obmat);
611 case SCE_SNAP_MODE_VERTEX:
613 MovieTrackingObject *tracking_object;
615 for (tracking_object = tracking->objects.first;
617 tracking_object = tracking_object->next)
619 ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object);
620 MovieTrackingTrack *track;
621 float reconstructed_camera_mat[4][4],
622 reconstructed_camera_imat[4][4];
623 float (*vertex_obmat)[4];
625 copy_v3_v3(ray_start_local, ray_start);
626 copy_v3_v3(ray_normal_local, ray_normal);
628 if ((tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0) {
629 BKE_tracking_camera_get_reconstructed_interpolate(tracking, tracking_object,
630 CFRA, reconstructed_camera_mat);
632 invert_m4_m4(reconstructed_camera_imat, reconstructed_camera_mat);
635 for (track = tracksbase->first; track; track = track->next) {
638 if ((track->flag & TRACK_HAS_BUNDLE) == 0) {
642 copy_v3_v3(bundle_pos, track->bundle_pos);
643 if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
644 mul_m4_v3(orig_camera_imat, ray_start_local);
645 mul_mat3_m4_v3(orig_camera_imat, ray_normal_local);
646 vertex_obmat = orig_camera_mat;
649 mul_m4_v3(reconstructed_camera_imat, bundle_pos);
650 mul_m4_v3(imat, ray_start_local);
651 mul_mat3_m4_v3(imat, ray_normal_local);
652 vertex_obmat = obmat;
655 retval |= snapVertex(
656 ar, bundle_pos, NULL, vertex_obmat, NULL, mval, dist_px,
657 ray_start, ray_start_local, ray_normal_local, ray_depth,
671 static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt)
673 const int *index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX);
674 return index_mp_to_orig ? index_mp_to_orig[lt->poly] : lt->poly;
677 static bool snapDerivedMesh(
678 SnapObjectContext *sctx,
679 Object *ob, DerivedMesh *dm, float obmat[4][4],
680 const float mval[2], float *dist_px, const short snap_to, bool do_bb,
681 const float ray_start[3], const float ray_normal[3], const float ray_origin[3],
682 float *ray_depth, unsigned int ob_index,
683 float r_loc[3], float r_no[3], int *r_index,
684 ListBase *r_hit_list)
686 ARegion *ar = sctx->v3d_data.ar;
689 if (snap_to == SCE_SNAP_MODE_FACE) {
690 if (dm->getNumPolys(dm) == 0) {
694 if (snap_to == SCE_SNAP_MODE_EDGE) {
695 if (dm->getNumEdges(dm) == 0) {
700 if (dm->getNumVerts(dm) == 0) {
706 const bool do_ray_start_correction = (
707 ELEM(snap_to, SCE_SNAP_MODE_FACE, SCE_SNAP_MODE_VERTEX) &&
708 (sctx->use_v3d && !((RegionView3D *)sctx->v3d_data.ar->regiondata)->is_persp));
709 bool need_ray_start_correction_init = do_ray_start_correction;
712 float timat[3][3]; /* transpose inverse matrix for normals */
713 float ray_start_local[3], ray_normal_local[3];
714 float local_scale, local_depth, len_diff;
716 invert_m4_m4(imat, obmat);
717 transpose_m3_m4(timat, imat);
719 copy_v3_v3(ray_start_local, ray_start);
720 copy_v3_v3(ray_normal_local, ray_normal);
722 mul_m4_v3(imat, ray_start_local);
723 mul_mat3_m4_v3(imat, ray_normal_local);
725 /* local scale in normal direction */
726 local_scale = normalize_v3(ray_normal_local);
727 local_depth = *ray_depth;
728 if (local_depth != BVH_RAYCAST_DIST_MAX) {
729 local_depth *= local_scale;
733 BoundBox *bb = BKE_object_boundbox_get(ob);
738 /* We cannot aford a bbox with some null dimension, which may happen in some cases...
739 * Threshold is rather high, but seems to be needed to get good behavior, see T46099. */
740 bb = BKE_boundbox_ensure_minimum_dimensions(bb, &bb_temp, 1e-1f);
742 /* Exact value here is arbitrary (ideally we would scale in pixel-space based on 'dist_px'),
743 * scale up so we can snap against verts & edges on the boundbox, see T46816. */
744 if (ELEM(snap_to, SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE)) {
745 BKE_boundbox_scale(&bb_temp, bb, 1.0f + 1e-1f);
749 /* was local_depth, see: T47838 */
750 len_diff = BVH_RAYCAST_DIST_MAX;
752 if (!BKE_boundbox_ray_hit_check(bb, ray_start_local, ray_normal_local, &len_diff)) {
755 need_ray_start_correction_init = false;
759 SnapObjectData_Mesh *sod = NULL;
760 BVHTreeFromMesh *treedata = NULL, treedata_stack;
762 if (sctx->flag & SNAP_OBJECT_USE_CACHE) {
764 if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) {
768 sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod));
769 sod->sd.type = SNAP_MESH;
774 case SCE_SNAP_MODE_FACE:
777 case SCE_SNAP_MODE_VERTEX:
781 if (tree_index != -1) {
782 if (sod->bvh_trees[tree_index] == NULL) {
783 sod->bvh_trees[tree_index] = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*treedata));
785 treedata = sod->bvh_trees[tree_index];
787 /* the tree is owned by the DM and may have been freed since we last used! */
788 if (treedata && treedata->tree) {
789 if (treedata->cached && !bvhcache_has_tree(dm->bvhCache, treedata->tree)) {
790 free_bvhtree_from_mesh(treedata);
796 if (ELEM(snap_to, SCE_SNAP_MODE_FACE, SCE_SNAP_MODE_VERTEX)) {
797 treedata = &treedata_stack;
798 memset(treedata, 0, sizeof(*treedata));
802 if (treedata && treedata->tree == NULL) {
804 case SCE_SNAP_MODE_FACE:
805 bvhtree_from_mesh_looptri(treedata, dm, 0.0f, 4, 6);
807 case SCE_SNAP_MODE_VERTEX:
808 bvhtree_from_mesh_verts(treedata, dm, 0.0f, 2, 6);
813 if (need_ray_start_correction_init) {
814 /* We *need* a reasonably valid len_diff in this case.
815 * Use BHVTree to find the closest face from ray_start_local.
817 if (treedata && treedata->tree != NULL) {
818 BVHTreeNearest nearest;
820 nearest.dist_sq = FLT_MAX;
821 /* Compute and store result. */
822 BLI_bvhtree_find_nearest(
823 treedata->tree, ray_start_local, &nearest, treedata->nearest_callback, treedata);
824 if (nearest.index != -1) {
825 len_diff = sqrtf(nearest.dist_sq);
829 /* Only use closer ray_start in case of ortho view! In perspective one, ray_start may already
830 * been *inside* boundbox, leading to snap failures (see T38409).
831 * Note also ar might be null (see T38435), in this case we assume ray_start is ok!
833 if (do_ray_start_correction) {
834 float ray_org_local[3];
836 copy_v3_v3(ray_org_local, ray_origin);
837 mul_m4_v3(imat, ray_org_local);
839 /* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with very far
840 * away ray_start values (as returned in case of ortho view3d), see T38358.
842 len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */
843 madd_v3_v3v3fl(ray_start_local, ray_org_local, ray_normal_local,
844 len_diff - len_v3v3(ray_start_local, ray_org_local));
845 local_depth -= len_diff;
852 case SCE_SNAP_MODE_FACE:
855 struct RayCastAll_Data data;
857 data.bvhdata = treedata;
858 data.raycast_callback = treedata->raycast_callback;
861 data.len_diff = len_diff;
862 data.local_scale = local_scale;
864 data.ob_uuid = ob_index,
866 data.hit_list = r_hit_list;
867 data.retval = retval;
869 BLI_bvhtree_ray_cast_all(
870 treedata->tree, ray_start_local, ray_normal_local, 0.0f,
871 *ray_depth, raycast_all_cb, &data);
873 retval = data.retval;
879 hit.dist = local_depth;
881 if (treedata->tree &&
882 BLI_bvhtree_ray_cast(
883 treedata->tree, ray_start_local, ray_normal_local, 0.0f,
884 &hit, treedata->raycast_callback, treedata) != -1)
886 hit.dist += len_diff;
887 hit.dist /= local_scale;
888 if (hit.dist <= *ray_depth) {
889 *ray_depth = hit.dist;
890 copy_v3_v3(r_loc, hit.co);
891 copy_v3_v3(r_no, hit.no);
893 /* back to worldspace */
894 mul_m4_v3(obmat, r_loc);
895 mul_m3_v3(timat, r_no);
901 *r_index = dm_looptri_to_poly_index(dm, &treedata->looptri[hit.index]);
908 case SCE_SNAP_MODE_VERTEX:
910 BVHTreeNearest nearest;
913 nearest.dist_sq = local_depth * local_depth;
914 if (treedata->tree &&
915 BLI_bvhtree_find_nearest_to_ray(
916 treedata->tree, ray_start_local, ray_normal_local,
917 &nearest, NULL, NULL) != -1)
919 const MVert *v = &treedata->vert[nearest.index];
921 normal_short_to_float_v3(vno, v->no);
923 ar, v->co, vno, obmat, timat, mval, dist_px,
924 ray_start, ray_start_local, ray_normal_local, ray_depth,
929 case SCE_SNAP_MODE_EDGE:
931 MVert *verts = dm->getVertArray(dm);
932 MEdge *edges = dm->getEdgeArray(dm);
933 int totedge = dm->getNumEdges(dm);
935 for (int i = 0; i < totedge; i++) {
936 MEdge *e = edges + i;
938 ar, verts[e->v1].co, verts[e->v1].no, verts[e->v2].co, verts[e->v2].no,
939 obmat, timat, mval, dist_px,
940 ray_start, ray_start_local, ray_normal_local, ray_depth,
948 if ((sctx->flag & SNAP_OBJECT_USE_CACHE) == 0) {
950 free_bvhtree_from_mesh(treedata);
959 static bool snapEditMesh(
960 SnapObjectContext *sctx,
961 Object *ob, BMEditMesh *em, float obmat[4][4],
962 const float mval[2], float *dist_px, const short snap_to,
963 const float ray_start[3], const float ray_normal[3], const float ray_origin[3],
964 float *ray_depth, const unsigned int ob_index,
965 float r_loc[3], float r_no[3], int *r_index,
966 ListBase *r_hit_list)
968 ARegion *ar = sctx->v3d_data.ar;
971 if (snap_to == SCE_SNAP_MODE_FACE) {
972 if (em->bm->totface == 0) {
976 if (snap_to == SCE_SNAP_MODE_EDGE) {
977 if (em->bm->totedge == 0) {
982 if (em->bm->totvert == 0) {
988 const bool do_ray_start_correction = (
989 ELEM(snap_to, SCE_SNAP_MODE_FACE, SCE_SNAP_MODE_VERTEX) &&
990 (sctx->use_v3d && !((RegionView3D *)sctx->v3d_data.ar->regiondata)->is_persp));
993 float timat[3][3]; /* transpose inverse matrix for normals */
994 float ray_start_local[3], ray_normal_local[3];
995 float local_scale, local_depth;
997 invert_m4_m4(imat, obmat);
998 transpose_m3_m4(timat, imat);
1000 copy_v3_v3(ray_start_local, ray_start);
1001 copy_v3_v3(ray_normal_local, ray_normal);
1003 mul_m4_v3(imat, ray_start_local);
1004 mul_mat3_m4_v3(imat, ray_normal_local);
1006 /* local scale in normal direction */
1007 local_scale = normalize_v3(ray_normal_local);
1008 local_depth = *ray_depth;
1009 if (local_depth != BVH_RAYCAST_DIST_MAX) {
1010 local_depth *= local_scale;
1013 SnapObjectData_EditMesh *sod = NULL;
1015 BVHTreeFromEditMesh *treedata = NULL, treedata_stack;
1017 if (sctx->flag & SNAP_OBJECT_USE_CACHE) {
1019 if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) {
1023 sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod));
1024 sod->sd.type = SNAP_EDIT_MESH;
1027 int tree_index = -1;
1029 case SCE_SNAP_MODE_FACE:
1032 case SCE_SNAP_MODE_VERTEX:
1036 if (tree_index != -1) {
1037 if (sod->bvh_trees[tree_index] == NULL) {
1038 sod->bvh_trees[tree_index] = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*treedata));
1040 treedata = sod->bvh_trees[tree_index];
1044 if (ELEM(snap_to, SCE_SNAP_MODE_FACE, SCE_SNAP_MODE_VERTEX)) {
1045 treedata = &treedata_stack;
1046 memset(treedata, 0, sizeof(*treedata));
1050 if (treedata && treedata->tree == NULL) {
1052 case SCE_SNAP_MODE_FACE:
1054 BLI_bitmap *looptri_mask = NULL;
1055 int looptri_num_active = -1;
1056 if (sctx->callbacks.edit_mesh.test_face_fn) {
1057 looptri_mask = BLI_BITMAP_NEW(em->tottri, __func__);
1058 looptri_num_active = BM_iter_mesh_bitmap_from_filter_tessface(
1059 em->bm, looptri_mask,
1060 sctx->callbacks.edit_mesh.test_face_fn, sctx->callbacks.edit_mesh.user_data);
1062 bvhtree_from_editmesh_looptri_ex(treedata, em, looptri_mask, looptri_num_active, 0.0f, 4, 6);
1064 MEM_freeN(looptri_mask);
1068 case SCE_SNAP_MODE_VERTEX:
1070 BLI_bitmap *verts_mask = NULL;
1071 int verts_num_active = -1;
1072 if (sctx->callbacks.edit_mesh.test_vert_fn) {
1073 verts_mask = BLI_BITMAP_NEW(em->bm->totvert, __func__);
1074 verts_num_active = BM_iter_mesh_bitmap_from_filter(
1075 BM_VERTS_OF_MESH, em->bm, verts_mask,
1076 (bool (*)(BMElem *, void *))sctx->callbacks.edit_mesh.test_vert_fn,
1077 sctx->callbacks.edit_mesh.user_data);
1079 bvhtree_from_editmesh_verts_ex(treedata, em, verts_mask, verts_num_active, 0.0f, 2, 6);
1081 MEM_freeN(verts_mask);
1088 /* Only use closer ray_start in case of ortho view! In perspective one, ray_start may already
1089 * been *inside* boundbox, leading to snap failures (see T38409).
1090 * Note also ar might be null (see T38435), in this case we assume ray_start is ok!
1092 float len_diff = 0.0f;
1093 if (do_ray_start_correction) {
1094 /* We *need* a reasonably valid len_diff in this case.
1095 * Use BHVTree to find the closest face from ray_start_local.
1097 if (treedata && treedata->tree != NULL) {
1098 BVHTreeNearest nearest;
1100 nearest.dist_sq = FLT_MAX;
1101 /* Compute and store result. */
1102 if (BLI_bvhtree_find_nearest(
1103 treedata->tree, ray_start_local, &nearest, treedata->nearest_callback, treedata) != -1)
1105 len_diff = sqrtf(nearest.dist_sq);
1106 float ray_org_local[3];
1108 copy_v3_v3(ray_org_local, ray_origin);
1109 mul_m4_v3(imat, ray_org_local);
1111 /* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with very far
1112 * away ray_start values (as returned in case of ortho view3d), see T38358.
1114 len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */
1115 madd_v3_v3v3fl(ray_start_local, ray_org_local, ray_normal_local,
1116 len_diff - len_v3v3(ray_start_local, ray_org_local));
1117 local_depth -= len_diff;
1123 case SCE_SNAP_MODE_FACE:
1126 struct RayCastAll_Data data;
1128 data.bvhdata = treedata;
1129 data.raycast_callback = treedata->raycast_callback;
1132 data.len_diff = len_diff;
1133 data.local_scale = local_scale;
1135 data.ob_uuid = ob_index;
1137 data.hit_list = r_hit_list;
1138 data.retval = retval;
1140 BLI_bvhtree_ray_cast_all(
1141 treedata->tree, ray_start_local, ray_normal_local, 0.0f,
1142 *ray_depth, raycast_all_cb, &data);
1144 retval = data.retval;
1150 hit.dist = local_depth;
1152 if (treedata->tree &&
1153 BLI_bvhtree_ray_cast(
1154 treedata->tree, ray_start_local, ray_normal_local, 0.0f,
1155 &hit, treedata->raycast_callback, treedata) != -1)
1157 hit.dist += len_diff;
1158 hit.dist /= local_scale;
1159 if (hit.dist <= *ray_depth) {
1160 *ray_depth = hit.dist;
1161 copy_v3_v3(r_loc, hit.co);
1162 copy_v3_v3(r_no, hit.no);
1164 /* back to worldspace */
1165 mul_m4_v3(obmat, r_loc);
1166 mul_m3_v3(timat, r_no);
1172 *r_index = hit.index;
1179 case SCE_SNAP_MODE_VERTEX:
1181 BVHTreeNearest nearest;
1184 nearest.dist_sq = local_depth * local_depth;
1185 if (treedata->tree &&
1186 BLI_bvhtree_find_nearest_to_ray(
1187 treedata->tree, ray_start_local, ray_normal_local,
1188 &nearest, NULL, NULL) != -1)
1190 const BMVert *v = BM_vert_at_index(em->bm, nearest.index);
1191 retval = snapVertex(
1192 ar, v->co, v->no, obmat, timat, mval, dist_px,
1193 ray_start, ray_start_local, ray_normal_local, ray_depth,
1198 case SCE_SNAP_MODE_EDGE:
1200 BM_mesh_elem_table_ensure(em->bm, BM_EDGE);
1201 int totedge = em->bm->totedge;
1202 for (int i = 0; i < totedge; i++) {
1203 BMEdge *eed = BM_edge_at_index(em->bm, i);
1205 if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) &&
1206 !BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) &&
1207 !BM_elem_flag_test(eed->v2, BM_ELEM_SELECT))
1209 short v1no[3], v2no[3];
1210 normal_float_to_short_v3(v1no, eed->v1->no);
1211 normal_float_to_short_v3(v2no, eed->v2->no);
1213 ar, eed->v1->co, v1no, eed->v2->co, v2no,
1214 obmat, timat, mval, dist_px,
1215 ray_start, ray_start_local, ray_normal_local, ray_depth,
1224 if ((sctx->flag & SNAP_OBJECT_USE_CACHE) == 0) {
1226 free_bvhtree_from_editmesh(treedata);
1234 static bool snapObject(
1235 SnapObjectContext *sctx,
1236 Object *ob, float obmat[4][4], bool use_obedit, const short snap_to,
1237 const float mval[2], float *dist_px, const unsigned int ob_index,
1238 const float ray_start[3], const float ray_normal[3], const float ray_origin[3],
1241 float r_loc[3], float r_no[3], int *r_index,
1242 Object **r_ob, float r_obmat[4][4],
1243 ListBase *r_hit_list)
1245 ARegion *ar = sctx->v3d_data.ar;
1246 bool retval = false;
1248 if (ob->type == OB_MESH) {
1252 em = BKE_editmesh_from_object(ob);
1253 retval = snapEditMesh(
1254 sctx, ob, em, obmat, mval, dist_px, snap_to,
1255 ray_start, ray_normal, ray_origin,
1256 ray_depth, ob_index,
1257 r_loc, r_no, r_index,
1261 /* in this case we want the mesh from the editmesh, avoids stale data. see: T45978.
1262 * still set the 'em' to NULL, since we only want the 'dm'. */
1264 em = BKE_editmesh_from_object(ob);
1266 editbmesh_get_derived_cage_and_final(sctx->scene, ob, em, CD_MASK_BAREMESH, &dm);
1269 dm = mesh_get_derived_final(sctx->scene, ob, CD_MASK_BAREMESH);
1271 retval = snapDerivedMesh(
1272 sctx, ob, dm, obmat, mval, dist_px, snap_to, true,
1273 ray_start, ray_normal, ray_origin,
1274 ray_depth, ob_index,
1275 r_loc, r_no, r_index, r_hit_list);
1280 else if (ob->type == OB_ARMATURE) {
1281 retval = snapArmature(
1282 ar, ob, ob->data, obmat, mval, dist_px, snap_to,
1283 ray_start, ray_normal, ray_depth,
1286 else if (ob->type == OB_CURVE) {
1288 ar, ob, ob->data, obmat, mval, dist_px, snap_to,
1289 ray_start, ray_normal, ray_depth,
1292 else if (ob->type == OB_EMPTY) {
1294 ar, ob, obmat, mval, dist_px, snap_to,
1295 ray_start, ray_normal, ray_depth,
1298 else if (ob->type == OB_CAMERA) {
1299 retval = snapCamera(
1300 ar, sctx->scene, ob, obmat, mval, dist_px, snap_to,
1301 ray_start, ray_normal, ray_depth,
1308 copy_m4_m4(r_obmat, obmat);
1315 static bool snapObjectsRay(
1316 SnapObjectContext *sctx,
1317 const unsigned short snap_to, const SnapSelect snap_select,
1318 const bool use_object_edit_cage,
1319 const float mval[2], float *dist_px,
1320 const float ray_start[3], const float ray_normal[3], const float ray_origin[3], float *ray_depth,
1322 float r_loc[3], float r_no[3], int *r_index,
1323 Object **r_ob, float r_obmat[4][4],
1324 ListBase *r_hit_list)
1326 bool retval = false;
1327 unsigned int ob_index = 0;
1328 Object *obedit = use_object_edit_cage ? sctx->scene->obedit : NULL;
1329 Base *base_act = sctx->scene->basact;
1331 bool ignore_object_selected = false, ignore_object_active = false;
1332 switch (snap_select) {
1335 case SNAP_NOT_SELECTED:
1336 ignore_object_selected = true;
1338 case SNAP_NOT_ACTIVE:
1339 ignore_object_active = true;
1342 for (Base *base = sctx->scene->base.first; base != NULL; base = base->next) {
1343 if ((BASE_VISIBLE_BGMODE(sctx->v3d_data.v3d, sctx->scene, base)) &&
1344 (base->flag & (BA_HAS_RECALC_OB | BA_HAS_RECALC_DATA)) == 0 &&
1346 !((ignore_object_selected && (base->flag & (SELECT | BA_WAS_SEL))) ||
1347 (ignore_object_active && base == base_act)))
1349 Object *ob = base->object;
1351 if (ob->transflag & OB_DUPLI) {
1352 DupliObject *dupli_ob;
1353 ListBase *lb = object_duplilist(sctx->bmain->eval_ctx, sctx->scene, ob);
1355 for (dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) {
1356 bool use_obedit_dupli = (obedit && dupli_ob->ob->data == obedit->data);
1357 Object *dupli_snap = (use_obedit_dupli) ? obedit : dupli_ob->ob;
1359 retval |= snapObject(
1360 sctx, dupli_snap, dupli_ob->mat, use_obedit_dupli, snap_to,
1361 mval, dist_px, ob_index++,
1362 ray_start, ray_normal, ray_origin, ray_depth,
1363 r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list);
1366 free_object_duplilist(lb);
1369 bool use_obedit = (obedit != NULL) && (ob->data == obedit->data);
1370 Object *ob_snap = use_obedit ? obedit : ob;
1372 retval |= snapObject(
1373 sctx, ob_snap, ob->obmat, use_obedit, snap_to,
1374 mval, dist_px, ob_index++,
1375 ray_start, ray_normal, ray_origin, ray_depth,
1376 r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list);
1386 /* -------------------------------------------------------------------- */
1388 /** \name Public Object Snapping API
1391 SnapObjectContext *ED_transform_snap_object_context_create(
1392 Main *bmain, Scene *scene, int flag)
1394 SnapObjectContext *sctx = MEM_callocN(sizeof(*sctx), __func__);
1398 sctx->bmain = bmain;
1399 sctx->scene = scene;
1404 SnapObjectContext *ED_transform_snap_object_context_create_view3d(
1405 Main *bmain, Scene *scene, int flag,
1406 /* extra args for view3d */
1407 ARegion *ar, View3D *v3d)
1409 SnapObjectContext *sctx = ED_transform_snap_object_context_create(bmain, scene, flag);
1411 sctx->use_v3d = true;
1412 sctx->v3d_data.ar = ar;
1413 sctx->v3d_data.v3d = v3d;
1415 if (sctx->flag & SNAP_OBJECT_USE_CACHE) {
1416 sctx->cache.object_map = BLI_ghash_ptr_new(__func__);
1417 sctx->cache.mem_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
1423 static void snap_object_data_free(void *sod_v)
1425 switch (((SnapObjectData *)sod_v)->type) {
1428 SnapObjectData_Mesh *sod = sod_v;
1429 for (int i = 0; i < ARRAY_SIZE(sod->bvh_trees); i++) {
1430 if (sod->bvh_trees[i]) {
1431 free_bvhtree_from_mesh(sod->bvh_trees[i]);
1436 case SNAP_EDIT_MESH:
1438 SnapObjectData_EditMesh *sod = sod_v;
1439 for (int i = 0; i < ARRAY_SIZE(sod->bvh_trees); i++) {
1440 if (sod->bvh_trees[i]) {
1441 free_bvhtree_from_editmesh(sod->bvh_trees[i]);
1449 void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx)
1451 if (sctx->flag & SNAP_OBJECT_USE_CACHE) {
1452 BLI_ghash_free(sctx->cache.object_map, NULL, snap_object_data_free);
1453 BLI_memarena_free(sctx->cache.mem_arena);
1459 void ED_transform_snap_object_context_set_editmesh_callbacks(
1460 SnapObjectContext *sctx,
1461 bool (*test_vert_fn)(BMVert *, void *user_data),
1462 bool (*test_edge_fn)(BMEdge *, void *user_data),
1463 bool (*test_face_fn)(BMFace *, void *user_data),
1466 sctx->callbacks.edit_mesh.test_vert_fn = test_vert_fn;
1467 sctx->callbacks.edit_mesh.test_edge_fn = test_edge_fn;
1468 sctx->callbacks.edit_mesh.test_face_fn = test_face_fn;
1470 sctx->callbacks.edit_mesh.user_data = user_data;
1473 bool ED_transform_snap_object_project_ray_ex(
1474 SnapObjectContext *sctx,
1475 const unsigned short snap_to,
1476 const struct SnapObjectParams *params,
1477 const float ray_start[3], const float ray_normal[3], float *ray_depth,
1478 float r_loc[3], float r_no[3], int *r_index,
1479 Object **r_ob, float r_obmat[4][4])
1481 return snapObjectsRay(
1483 snap_to, params->snap_select, params->use_object_edit_cage,
1485 ray_start, ray_normal, ray_start, ray_depth,
1486 r_loc, r_no, r_index, r_ob, r_obmat, NULL);
1490 * Fill in a list of all hits.
1492 * \param ray_depth: Only depths in this range are considered, -1.0 for maximum.
1493 * \param sort: Optionally sort the hits by depth.
1494 * \param r_hit_list: List of #SnapObjectHitDepth (caller must free).
1496 bool ED_transform_snap_object_project_ray_all(
1497 SnapObjectContext *sctx,
1498 const unsigned short snap_to,
1499 const struct SnapObjectParams *params,
1500 const float ray_start[3], const float ray_normal[3],
1501 float ray_depth, bool sort,
1502 ListBase *r_hit_list)
1504 if (ray_depth == -1.0f) {
1505 ray_depth = BVH_RAYCAST_DIST_MAX;
1509 float ray_depth_prev = ray_depth;
1512 bool retval = snapObjectsRay(
1514 snap_to, params->snap_select, params->use_object_edit_cage,
1516 ray_start, ray_normal, ray_start, &ray_depth,
1517 NULL, NULL, NULL, NULL, NULL,
1520 /* meant to be readonly for 'all' hits, ensure it is */
1522 BLI_assert(ray_depth_prev == ray_depth);
1526 BLI_listbase_sort(r_hit_list, hit_depth_cmp);
1533 * Convenience function for snap ray-casting.
1535 * Given a ray, cast it into the scene (snapping to faces).
1537 * \return Snap success
1539 static bool transform_snap_context_project_ray_impl(
1540 SnapObjectContext *sctx,
1541 const struct SnapObjectParams *params,
1542 const float ray_start[3], const float ray_normal[3], float *ray_depth,
1543 float r_co[3], float r_no[3])
1547 /* try snap edge, then face if it fails */
1548 ret = ED_transform_snap_object_project_ray_ex(
1552 ray_start, ray_normal, ray_depth,
1559 bool ED_transform_snap_object_project_ray(
1560 SnapObjectContext *sctx,
1561 const struct SnapObjectParams *params,
1562 const float ray_origin[3], const float ray_direction[3], float *ray_depth,
1563 float r_co[3], float r_no[3])
1565 float ray_depth_fallback;
1566 if (ray_depth == NULL) {
1567 ray_depth_fallback = BVH_RAYCAST_DIST_MAX;
1568 ray_depth = &ray_depth_fallback;
1571 float no_fallback[3];
1576 return transform_snap_context_project_ray_impl(
1579 ray_origin, ray_direction, ray_depth,
1583 static bool transform_snap_context_project_view3d_mixed_impl(
1584 SnapObjectContext *sctx,
1585 const unsigned short snap_to_flag,
1586 const struct SnapObjectParams *params,
1587 const float mval[2], float *dist_px,
1589 float r_co[3], float r_no[3])
1591 float ray_depth = BVH_RAYCAST_DIST_MAX;
1592 bool is_hit = false;
1594 float r_no_dummy[3];
1599 const int elem_type[3] = {SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE, SCE_SNAP_MODE_FACE};
1601 BLI_assert(snap_to_flag != 0);
1602 BLI_assert((snap_to_flag & ~(1 | 2 | 4)) == 0);
1604 for (int i = 0; i < 3; i++) {
1605 if ((snap_to_flag & (1 << i)) && (is_hit == false || use_depth)) {
1606 if (use_depth == false) {
1607 ray_depth = BVH_RAYCAST_DIST_MAX;
1610 if (ED_transform_snap_object_project_view3d(
1612 elem_type[i], params,
1613 mval, dist_px, &ray_depth,
1625 * Convenience function for performing snapping.
1627 * Given a 2D region value, snap to vert/edge/face.
1629 * \param sctx: Snap context.
1630 * \param mval: Screenspace coordinate.
1631 * \param dist_px: Maximum distance to snap (in pixels).
1632 * \param use_depth: Snap to the closest element, use when using more than one snap type.
1633 * \param r_co: hit location.
1634 * \param r_no: hit normal (optional).
1635 * \return Snap success
1637 bool ED_transform_snap_object_project_view3d_mixed(
1638 SnapObjectContext *sctx,
1639 const unsigned short snap_to_flag,
1640 const struct SnapObjectParams *params,
1641 const float mval_fl[2], float *dist_px,
1643 float r_co[3], float r_no[3])
1645 return transform_snap_context_project_view3d_mixed_impl(
1647 snap_to_flag, params,
1648 mval_fl, dist_px, use_depth,
1652 bool ED_transform_snap_object_project_view3d_ex(
1653 SnapObjectContext *sctx,
1654 const unsigned short snap_to,
1655 const struct SnapObjectParams *params,
1656 const float mval[2], float *dist_px,
1658 float r_loc[3], float r_no[3], int *r_index)
1660 float ray_start[3], ray_normal[3], ray_orgigin[3];
1662 float ray_depth_fallback;
1663 if (ray_depth == NULL) {
1664 ray_depth_fallback = BVH_RAYCAST_DIST_MAX;
1665 ray_depth = &ray_depth_fallback;
1668 if (!ED_view3d_win_to_ray_ex(
1669 sctx->v3d_data.ar, sctx->v3d_data.v3d,
1670 mval, ray_orgigin, ray_normal, ray_start, true))
1675 return snapObjectsRay(
1677 snap_to, params->snap_select, params->use_object_edit_cage,
1679 ray_start, ray_normal, ray_orgigin, ray_depth,
1680 r_loc, r_no, r_index, NULL, NULL, NULL);
1683 bool ED_transform_snap_object_project_view3d(
1684 SnapObjectContext *sctx,
1685 const unsigned short snap_to,
1686 const struct SnapObjectParams *params,
1687 const float mval[2], float *dist_px,
1689 float r_loc[3], float r_no[3])
1691 return ED_transform_snap_object_project_view3d_ex(
1701 * see: #ED_transform_snap_object_project_ray_all
1703 bool ED_transform_snap_object_project_all_view3d_ex(
1704 SnapObjectContext *sctx,
1705 const struct SnapObjectParams *params,
1706 const float mval[2],
1707 float ray_depth, bool sort,
1708 ListBase *r_hit_list)
1710 float ray_start[3], ray_normal[3];
1712 if (!ED_view3d_win_to_ray_ex(
1713 sctx->v3d_data.ar, sctx->v3d_data.v3d,
1714 mval, NULL, ray_normal, ray_start, true))
1719 return ED_transform_snap_object_project_ray_all(
1723 ray_start, ray_normal, ray_depth, sort,