Blender V5.0
transform_snap_object_mesh.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "BLI_math_matrix.hh"
10#include "BLI_math_vector.h"
11
12#include "BKE_bvhutils.hh"
13#include "BKE_mesh.hh"
14
16#include "ED_view3d.hh"
17
19
20#ifdef DEBUG_SNAP_TIME
21# if WIN32 and NDEBUG
22# pragma optimize("t", on)
23# endif
24#endif
25
26namespace blender::ed::transform {
27
28/* -------------------------------------------------------------------- */
31
32static void snap_object_data_mesh_get(const Mesh *mesh_eval,
33 bool skip_hidden,
34 bke::BVHTreeFromMesh *r_treedata)
35{
36 /* The BVHTree from corner_tris is always required. */
37 if (skip_hidden) {
38 *r_treedata = mesh_eval->bvh_corner_tris_no_hidden();
39 }
40 else {
41 *r_treedata = mesh_eval->bvh_corner_tris();
42 }
43}
44
46
47/* -------------------------------------------------------------------- */
50
51/* Store all ray-hits
52 * Support for storing all depths, not just the first (ray-cast 'all'). */
53
54/* Callback to ray-cast with back-face culling (#Mesh). */
56 int index,
57 const BVHTreeRay *ray,
58 BVHTreeRayHit *hit)
59{
61 const Span<float3> positions = data->vert_positions;
62 const int3 &tri = data->corner_tris[index];
63 const float *vtri_co[3] = {
64 positions[data->corner_verts[tri[0]]],
65 positions[data->corner_verts[tri[1]]],
66 positions[data->corner_verts[tri[2]]],
67 };
68 float dist = bke::bvhtree_ray_tri_intersection(ray, hit->dist, UNPACK3(vtri_co));
69
70 if (dist >= 0 && dist < hit->dist) {
71 float no[3];
72 if (raycast_tri_backface_culling_test(ray->direction, UNPACK3(vtri_co), no)) {
73 hit->index = index;
74 hit->dist = dist;
75 madd_v3_v3v3fl(hit->co, ray->origin, ray->direction, dist);
76 normalize_v3_v3(hit->no, no);
77 }
78 }
79}
80
82 const Object *ob_eval,
83 const Mesh *mesh_eval,
84 const float4x4 &obmat,
85 const uint ob_index,
86 bool use_hide)
87{
88 bool retval = false;
89
90 if (mesh_eval->faces_num == 0) {
91 return retval;
92 }
93
94 float4x4 imat = math::invert(obmat);
95 float3 ray_start_local = math::transform_point(imat, sctx->runtime.ray_start);
96 float3 ray_normal_local = math::transform_direction(imat, sctx->runtime.ray_dir);
97 float local_scale, local_depth, len_diff = 0.0f;
98
99 /* Local scale in normal direction. */
100 ray_normal_local = math::normalize_and_get_length(ray_normal_local, local_scale);
101
102 const bool is_in_front = (sctx->runtime.params.occlusion_test == SNAP_OCCLUSION_AS_SEEM) &&
103 (ob_eval->dtx & OB_DRAW_IN_FRONT);
104 const float depth_max = is_in_front ? sctx->ret.ray_depth_max_in_front : sctx->ret.ray_depth_max;
105 local_depth = depth_max;
106 if (local_depth != BVH_RAYCAST_DIST_MAX) {
107 local_depth *= local_scale;
108 }
109
110 /* Test bounding box. */
111 if (std::optional<Bounds<float3>> bounds = mesh_eval->bounds_min_max()) {
112 /* Was #BKE_boundbox_ray_hit_check, see: cf6ca226fa58 */
114 ray_start_local, ray_normal_local, bounds->min, bounds->max, &len_diff, nullptr))
115 {
116 return retval;
117 }
118 }
119
120 /* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with
121 * very far away ray_start values (as returned in case of ortho view3d), see #50486, #38358.
122 */
123 if (len_diff > 400.0f) {
124 /* Make temporary start point a bit away from bounding-box hit point. */
125 len_diff -= local_scale;
126 madd_v3_v3fl(ray_start_local, ray_normal_local, len_diff);
127 local_depth -= len_diff;
128 }
129 else {
130 len_diff = 0.0f;
131 }
132
133 bke::BVHTreeFromMesh treedata;
134 snap_object_data_mesh_get(mesh_eval, use_hide, &treedata);
135
136 const Span<int> tri_faces = mesh_eval->corner_tri_faces();
137
138 if (treedata.tree == nullptr) {
139 return retval;
140 }
141
142 BLI_assert(treedata.raycast_callback != nullptr);
143 if (sctx->runtime.hit_list) {
145
146 data.bvhdata = &treedata;
147 data.raycast_callback = treedata.raycast_callback;
148 data.obmat = &obmat;
149 data.len_diff = len_diff;
150 data.local_scale = local_scale;
151 data.ob_uuid = ob_index;
152 data.hit_list = sctx->runtime.hit_list;
153
154 void *hit_last_prev = data.hit_list->last;
156 treedata.tree, ray_start_local, ray_normal_local, 0.0f, depth_max, raycast_all_cb, &data);
157
158 retval = hit_last_prev != data.hit_list->last;
159 }
160 else {
161 BVHTreeRayHit hit{};
162 hit.index = -1;
163 hit.dist = local_depth;
164
165 if (BLI_bvhtree_ray_cast(treedata.tree,
166 ray_start_local,
167 ray_normal_local,
168 0.0f,
169 &hit,
172 treedata.raycast_callback,
173 &treedata) != -1)
174 {
175 hit.dist += len_diff;
176 hit.dist /= local_scale;
177 if (hit.dist <= depth_max) {
178 hit.index = tri_faces[hit.index];
179 retval = true;
180 }
181 SnapData::register_result_raycast(sctx, ob_eval, &mesh_eval->id, obmat, &hit, is_in_front);
182 }
183 }
184
185 return retval;
186}
187
189
190/* -------------------------------------------------------------------- */
193
195 const Object *ob_eval,
196 const Mesh *mesh_eval,
197 const float4x4 &obmat,
198 bool use_hide)
199{
200 bke::BVHTreeFromMesh treedata;
201 snap_object_data_mesh_get(mesh_eval, use_hide, &treedata);
202 if (treedata.tree == nullptr) {
203 return false;
204 }
205
206 BVHTreeNearest nearest{};
207 nearest.dist_sq = sctx->ret.dist_nearest_sq;
209 sctx, treedata.tree, treedata.nearest_callback, obmat, &treedata, &nearest))
210 {
211 SnapData::register_result(sctx, ob_eval, &mesh_eval->id, obmat, &nearest);
212 return true;
213 }
214 return false;
215}
216
218
219/* -------------------------------------------------------------------- */
222
223class SnapData_Mesh : public SnapData {
224 public:
227 const int2 *edges; /* Only used for #BVHTreeFromMeshEdges. */
228 const int *corner_verts;
229 const int *corner_edges;
231
232 SnapData_Mesh(SnapObjectContext *sctx, const Mesh *mesh_eval, const float4x4 &obmat)
233 : SnapData(sctx, obmat)
234 {
235 this->vert_positions = mesh_eval->vert_positions().data();
236 this->vert_normals = mesh_eval->vert_normals().data();
237 this->edges = mesh_eval->edges().data();
238 this->corner_verts = mesh_eval->corner_verts().data();
239 this->corner_edges = mesh_eval->corner_edges().data();
240 this->corner_tris = mesh_eval->corner_tris().data();
241 };
242
243 void get_vert_co(const int index, const float **r_co) override
244 {
245 *r_co = this->vert_positions[index];
246 }
247
248 void get_edge_verts_index(const int index, int r_v_index[2]) override
249 {
250 const int2 &edge = this->edges[index];
251 r_v_index[0] = edge[0];
252 r_v_index[1] = edge[1];
253 }
254
255 void copy_vert_no(const int index, float r_no[3]) override
256 {
257 copy_v3_v3(r_no, this->vert_normals[index]);
258 }
259};
260
261static void cb_snap_edge_verts(void *userdata,
262 int index,
263 const DistProjectedAABBPrecalc *precalc,
264 const float (*clip_plane)[4],
265 const int clip_plane_len,
266 BVHTreeNearest *nearest)
267{
268 SnapData_Mesh *data = static_cast<SnapData_Mesh *>(userdata);
269
270 int vindex[2];
271 data->get_edge_verts_index(index, vindex);
272
273 for (int i = 2; i--;) {
274 if (vindex[i] == nearest->index) {
275 continue;
276 }
277 cb_snap_vert(userdata, vindex[i], precalc, clip_plane, clip_plane_len, nearest);
278 }
279}
280
281static void cb_snap_tri_verts(void *userdata,
282 int index,
283 const DistProjectedAABBPrecalc *precalc,
284 const float (*clip_plane)[4],
285 const int clip_plane_len,
286 BVHTreeNearest *nearest)
287{
288 SnapData_Mesh *data = static_cast<SnapData_Mesh *>(userdata);
289
290 int vindex[3];
291 const int *corner_verts = data->corner_verts;
292 const int3 &tri = data->corner_tris[index];
293 vindex[0] = corner_verts[tri[0]];
294 vindex[1] = corner_verts[tri[1]];
295 vindex[2] = corner_verts[tri[2]];
296
297 if (data->use_backface_culling) {
298 const float3 *vert_positions = data->vert_positions;
299 const float3 &t0 = vert_positions[vindex[0]];
300 const float3 &t1 = vert_positions[vindex[1]];
301 const float3 &t2 = vert_positions[vindex[2]];
302 float dummy[3];
303 if (raycast_tri_backface_culling_test(precalc->ray_direction, t0, t1, t2, dummy)) {
304 return;
305 }
306 }
307
308 for (int i = 3; i--;) {
309 if (vindex[i] == nearest->index) {
310 continue;
311 }
312 cb_snap_vert(userdata, vindex[i], precalc, clip_plane, clip_plane_len, nearest);
313 }
314}
315
316static void cb_snap_tri_edges(void *userdata,
317 int index,
318 const DistProjectedAABBPrecalc *precalc,
319 const float (*clip_plane)[4],
320 const int clip_plane_len,
321 BVHTreeNearest *nearest)
322{
323 SnapData_Mesh *data = static_cast<SnapData_Mesh *>(userdata);
324 const int *corner_verts = data->corner_verts;
325 const int3 &tri = data->corner_tris[index];
326
327 if (data->use_backface_culling) {
328 const float3 *vert_positions = data->vert_positions;
329 const float3 &t0 = vert_positions[corner_verts[tri[0]]];
330 const float3 &t1 = vert_positions[corner_verts[tri[1]]];
331 const float3 &t2 = vert_positions[corner_verts[tri[2]]];
332 float dummy[3];
333 if (raycast_tri_backface_culling_test(precalc->ray_direction, t0, t1, t2, dummy)) {
334 return;
335 }
336 }
337
338 const int2 *edges = data->edges;
339 const int *corner_edges = data->corner_edges;
340 for (int j = 2, j_next = 0; j_next < 3; j = j_next++) {
341 int eindex = corner_edges[tri[j]];
342 const int2 &edge = edges[eindex];
343 const int2 tri_edge = {corner_verts[tri[j]], corner_verts[tri[j_next]]};
344 if (ELEM(edge[0], tri_edge[0], tri_edge[1]) && ELEM(edge[1], tri_edge[0], tri_edge[1])) {
345 if (eindex == nearest->index) {
346 continue;
347 }
348 cb_snap_edge(userdata, eindex, precalc, clip_plane, clip_plane_len, nearest);
349 }
350 }
351}
352
354
355/* -------------------------------------------------------------------- */
358
360 const Object *ob_eval,
361 const ID *id,
362 const float4x4 &obmat,
363 eSnapMode snap_to_flag,
364 int face_index)
365{
367
368 const Mesh *mesh_eval = reinterpret_cast<const Mesh *>(id);
369
370 SnapData_Mesh nearest2d(sctx, mesh_eval, obmat);
371 nearest2d.clip_planes_enable(sctx, ob_eval);
372
373 BVHTreeNearest nearest{};
374 nearest.index = -1;
375 nearest.dist_sq = sctx->ret.dist_px_sq;
376
377 const IndexRange face = mesh_eval->faces()[face_index];
378
379 if (snap_to_flag &
381 {
382 /* We return "Snap to Edge" even if the intent is "Snap to Edge Midpoint" or
383 * "Snap to Edge Perpendicular".
384 * This avoids complexity. These snap points will be tested in `snap_edge_points`. */
385 elem = SCE_SNAP_TO_EDGE;
386 BLI_assert(nearest2d.edges != nullptr);
387 const int *face_edges = &nearest2d.corner_edges[face.start()];
388 for (int i = face.size(); i--;) {
389 cb_snap_edge(&nearest2d,
390 face_edges[i],
391 &nearest2d.nearest_precalc,
392 reinterpret_cast<float (*)[4]>(nearest2d.clip_planes.data()),
393 nearest2d.clip_planes.size(),
394 &nearest);
395 }
396 }
397 else {
399 const int *face_verts = &nearest2d.corner_verts[face.start()];
400 for (int i = face.size(); i--;) {
401 cb_snap_vert(&nearest2d,
402 face_verts[i],
403 &nearest2d.nearest_precalc,
404 reinterpret_cast<float (*)[4]>(nearest2d.clip_planes.data()),
405 nearest2d.clip_planes.size(),
406 &nearest);
407 }
408 }
409
410 if (nearest.index != -1) {
411 nearest2d.nearest_point = nearest;
412 nearest2d.register_result(sctx, ob_eval, id);
413 return elem;
414 }
415
416 return SCE_SNAP_TO_NONE;
417}
418
420 const Object *ob_eval,
421 const ID *id,
422 const float4x4 &obmat,
423 float dist_px_sq_orig,
424 int edge_index)
425{
426 SnapData_Mesh nearest2d(sctx, reinterpret_cast<const Mesh *>(id), obmat);
427 eSnapMode elem = nearest2d.snap_edge_points_impl(sctx, edge_index, dist_px_sq_orig);
428 if (nearest2d.nearest_point.index != -2) {
429 nearest2d.register_result(sctx, ob_eval, id);
430 }
431 return elem;
432}
433
434static eSnapMode mesh_snap_mode_supported(const Mesh *mesh, bool skip_hidden)
435{
436 /* When skipping hidden geometry, we still cannot obtain the number of loose verts
437 * until computing #BVHTREE_FROM_LOOSEVERTS_NO_HIDDEN. Therefore, consider #SCE_SNAP_TO_POINT
438 * supported even if the mesh has no loose vertices in this case. */
439 eSnapMode snap_mode_supported = (skip_hidden || mesh->loose_verts().count) ? SCE_SNAP_TO_POINT :
441 if (mesh->faces_num) {
443 }
444 else if (mesh->edges_num) {
445 snap_mode_supported |= SNAP_TO_EDGE_ELEMENTS;
446 }
447
448 return snap_mode_supported;
449}
450
452 const Object *ob_eval,
453 const Mesh *mesh_eval,
454 const float4x4 &obmat,
455 bool skip_hidden,
456 bool is_editmesh,
457 eSnapMode snap_to)
458{
459 BLI_assert(snap_to != SCE_SNAP_TO_FACE);
460 SnapData_Mesh nearest2d(sctx, mesh_eval, obmat);
461 if (is_editmesh) {
462 nearest2d.use_backface_culling = false;
463 }
464
465 if (std::optional<Bounds<float3>> bounds = mesh_eval->bounds_min_max()) {
466 if (!nearest2d.snap_boundbox(bounds->min, bounds->max)) {
467 return SCE_SNAP_TO_NONE;
468 }
469 }
470
471 snap_to &= mesh_snap_mode_supported(mesh_eval, skip_hidden) &
473 if (snap_to == SCE_SNAP_TO_NONE) {
474 return SCE_SNAP_TO_NONE;
475 }
476
477 bke::BVHTreeFromMesh treedata;
478 snap_object_data_mesh_get(mesh_eval, skip_hidden, &treedata);
479
480 const BVHTree *bvhtree[2] = {nullptr};
481 bvhtree[0] = skip_hidden ? mesh_eval->bvh_loose_no_hidden_edges().tree :
482 mesh_eval->bvh_loose_edges().tree;
483 if (snap_to & SCE_SNAP_TO_POINT) {
484 bvhtree[1] = skip_hidden ? mesh_eval->bvh_loose_no_hidden_verts().tree :
485 mesh_eval->bvh_loose_verts().tree;
486 }
487
488 /* #XRAY_ENABLED can return false even with the XRAY flag enabled, this happens because the
489 * alpha is 1.0 in this case. But even with the alpha being 1.0, the edit mesh is still not
490 * occluded. */
491 const bool skip_occlusion_plane = is_editmesh && XRAY_FLAG_ENABLED(sctx->runtime.v3d);
492 nearest2d.clip_planes_enable(sctx, ob_eval, skip_occlusion_plane);
493
494 BVHTreeNearest nearest{};
495 nearest.index = -1;
496 nearest.dist_sq = sctx->ret.dist_px_sq;
497
498 int last_index = nearest.index;
500
501 if (bvhtree[1]) {
502 BLI_assert(snap_to & SCE_SNAP_TO_POINT);
503 /* Snap to loose verts. */
505 bvhtree[1],
506 nearest2d.pmat_local.ptr(),
507 sctx->runtime.win_size,
508 sctx->runtime.mval,
509 reinterpret_cast<float (*)[4]>(nearest2d.clip_planes.data()),
510 nearest2d.clip_planes.size(),
511 &nearest,
513 &nearest2d);
514
515 if (nearest.index != -1) {
516 last_index = nearest.index;
517 elem = SCE_SNAP_TO_POINT;
518 }
519 }
520
522 if (bvhtree[0]) {
523 /* Snap to loose edges. */
525 bvhtree[0],
526 nearest2d.pmat_local.ptr(),
527 sctx->runtime.win_size,
528 sctx->runtime.mval,
529 reinterpret_cast<float (*)[4]>(nearest2d.clip_planes.data()),
530 nearest2d.clip_planes.size(),
531 &nearest,
533 &nearest2d);
534 }
535
536 if (treedata.tree) {
537 /* Snap to corner_tris. */
539 treedata.tree,
540 nearest2d.pmat_local.ptr(),
541 sctx->runtime.win_size,
542 sctx->runtime.mval,
543 reinterpret_cast<float (*)[4]>(nearest2d.clip_planes.data()),
544 nearest2d.clip_planes.size(),
545 &nearest,
547 &nearest2d);
548 }
549
550 if (last_index != nearest.index) {
551 elem = SCE_SNAP_TO_EDGE;
552 }
553 }
554 else if (snap_to & SCE_SNAP_TO_EDGE_ENDPOINT) {
555 if (bvhtree[0]) {
556 /* Snap to loose edges verts. */
558 bvhtree[0],
559 nearest2d.pmat_local.ptr(),
560 sctx->runtime.win_size,
561 sctx->runtime.mval,
562 reinterpret_cast<float (*)[4]>(nearest2d.clip_planes.data()),
563 nearest2d.clip_planes.size(),
564 &nearest,
566 &nearest2d);
567 }
568
569 if (treedata.tree) {
570 /* Snap to corner_tris verts. */
572 treedata.tree,
573 nearest2d.pmat_local.ptr(),
574 sctx->runtime.win_size,
575 sctx->runtime.mval,
576 reinterpret_cast<float (*)[4]>(nearest2d.clip_planes.data()),
577 nearest2d.clip_planes.size(),
578 &nearest,
580 &nearest2d);
581 }
582
583 if (last_index != nearest.index) {
585 }
586 }
587
588 if (nearest.index != -1) {
589 nearest2d.nearest_point = nearest;
590 nearest2d.register_result(sctx, ob_eval, &mesh_eval->id);
591 return elem;
592 }
593
594 return SCE_SNAP_TO_NONE;
595}
596
598
600 const Object *ob_eval,
601 const ID *id,
602 const float4x4 &obmat,
603 eSnapMode snap_to_flag,
604 bool skip_hidden,
605 bool is_editmesh)
606{
608 const Mesh *mesh_eval = reinterpret_cast<const Mesh *>(id);
609
610 if (snap_to_flag & (SNAP_TO_EDGE_ELEMENTS | SCE_SNAP_TO_POINT)) {
611 elem = snapMesh(sctx, ob_eval, mesh_eval, obmat, skip_hidden, is_editmesh, snap_to_flag);
612 if (elem) {
613 return elem;
614 }
615 }
616
617 if (snap_to_flag & SCE_SNAP_TO_FACE) {
618 if (raycastMesh(sctx, ob_eval, mesh_eval, obmat, sctx->runtime.object_index++, skip_hidden)) {
619 return SCE_SNAP_TO_FACE;
620 }
621 }
622
623 if (snap_to_flag & SCE_SNAP_INDIVIDUAL_NEAREST) {
624 if (nearest_world_mesh(sctx, ob_eval, mesh_eval, obmat, skip_hidden)) {
626 }
627 }
628
629 return SCE_SNAP_TO_NONE;
630}
631
632} // namespace blender::ed::transform
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BVH_RAYCAST_DIST_MAX
int BLI_bvhtree_find_nearest_projected(const BVHTree *tree, float projmat[4][4], float winsize[2], float mval[2], float(*clip_planes)[4], int clip_plane_len, BVHTreeNearest *nearest, BVHTree_NearestProjectedCallback callback, void *userdata)
void BLI_bvhtree_ray_cast_all(const BVHTree *tree, const float co[3], const float dir[3], float radius, float hit_dist, BVHTree_RayCastCallback callback, void *userdata)
int BLI_bvhtree_ray_cast(const BVHTree *tree, const float co[3], const float dir[3], float radius, BVHTreeRayHit *hit, BVHTree_RayCastCallback callback, void *userdata)
bool isect_ray_aabb_v3_simple(const float orig[3], const float dir[3], const float bb_min[3], const float bb_max[3], float *tmin, float *tmax)
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE float normalize_v3_v3(float r[3], const float a[3])
MINLINE void madd_v3_v3v3fl(float r[3], const float a[3], const float b[3], float f)
unsigned int uint
#define UNPACK3(a)
#define ELEM(...)
@ OB_DRAW_IN_FRONT
@ SCE_SNAP_INDIVIDUAL_NEAREST
@ SCE_SNAP_TO_EDGE
@ SCE_SNAP_TO_FACE
@ SCE_SNAP_TO_EDGE_ENDPOINT
@ SCE_SNAP_TO_EDGE_MIDPOINT
@ SCE_SNAP_TO_EDGE_PERPENDICULAR
@ SCE_SNAP_TO_POINT
@ SCE_SNAP_TO_NONE
#define XRAY_FLAG_ENABLED(v3d)
BMesh const char void * data
constexpr int64_t size() const
constexpr int64_t start() const
void copy_vert_no(const int index, float r_no[3]) override
SnapData_Mesh(SnapObjectContext *sctx, const Mesh *mesh_eval, const float4x4 &obmat)
void get_edge_verts_index(const int index, int r_v_index[2]) override
void get_vert_co(const int index, const float **r_co) override
void clip_planes_enable(SnapObjectContext *sctx, const Object *ob_eval, bool skip_occlusion_plane=false)
Vector< float4, MAX_CLIPPLANE_LEN+1 > clip_planes
SnapData(SnapObjectContext *sctx, const float4x4 &obmat=float4x4::identity())
static void register_result_raycast(SnapObjectContext *sctx, const Object *ob_eval, const ID *id_eval, const float4x4 &obmat, const BVHTreeRayHit *hit, const bool is_in_front)
eSnapMode snap_edge_points_impl(SnapObjectContext *sctx, int edge_index, float dist_px_sq_orig)
static void register_result(SnapObjectContext *sctx, const Object *ob_eval, const ID *id_eval, const float4x4 &obmat, BVHTreeNearest *r_nearest)
bool snap_boundbox(const float3 &min, const float3 &max)
int count
float bvhtree_ray_tri_intersection(const BVHTreeRay *ray, float m_dist, const float v0[3], const float v1[3], const float v2[3])
Definition bvhutils.cc:28
static eSnapMode snapMesh(SnapObjectContext *sctx, const Object *ob_eval, const Mesh *mesh_eval, const float4x4 &obmat, bool skip_hidden, bool is_editmesh, eSnapMode snap_to)
bool nearest_world_tree(SnapObjectContext *sctx, const BVHTree *tree, BVHTree_NearestPointCallback nearest_cb, const blender::float4x4 &obmat, void *treedata, BVHTreeNearest *r_nearest)
static eSnapMode mesh_snap_mode_supported(const Mesh *mesh, bool skip_hidden)
void raycast_all_cb(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
static void cb_snap_edge_verts(void *userdata, int index, const DistProjectedAABBPrecalc *precalc, const float(*clip_plane)[4], const int clip_plane_len, BVHTreeNearest *nearest)
eSnapMode snap_object_mesh(SnapObjectContext *sctx, const Object *ob_eval, const ID *id, const float4x4 &obmat, eSnapMode snap_to_flag, bool skip_hidden, bool is_editmesh=false)
bool raycast_tri_backface_culling_test(const float dir[3], const float v0[3], const float v1[3], const float v2[3], float no[3])
eSnapMode snap_edge_points_mesh(SnapObjectContext *sctx, const Object *ob_eval, const ID *id, const float4x4 &obmat, float dist_px_sq_orig, int edge_index)
void cb_snap_vert(void *userdata, int index, const DistProjectedAABBPrecalc *precalc, const float(*clip_plane)[4], const int clip_plane_len, BVHTreeNearest *nearest)
static bool nearest_world_mesh(SnapObjectContext *sctx, const Object *ob_eval, const Mesh *mesh_eval, const float4x4 &obmat, bool use_hide)
void cb_snap_edge(void *userdata, int index, const DistProjectedAABBPrecalc *precalc, const float(*clip_plane)[4], const int clip_plane_len, BVHTreeNearest *nearest)
static void mesh_corner_tris_raycast_backface_culling_cb(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
static void snap_object_data_mesh_get(const Mesh *mesh_eval, bool skip_hidden, bke::BVHTreeFromMesh *r_treedata)
static void cb_snap_tri_verts(void *userdata, int index, const DistProjectedAABBPrecalc *precalc, const float(*clip_plane)[4], const int clip_plane_len, BVHTreeNearest *nearest)
static bool raycastMesh(SnapObjectContext *sctx, const Object *ob_eval, const Mesh *mesh_eval, const float4x4 &obmat, const uint ob_index, bool use_hide)
static void cb_snap_tri_edges(void *userdata, int index, const DistProjectedAABBPrecalc *precalc, const float(*clip_plane)[4], const int clip_plane_len, BVHTreeNearest *nearest)
eSnapMode snap_polygon_mesh(SnapObjectContext *sctx, const Object *ob_eval, const ID *id, const float4x4 &obmat, eSnapMode snap_to_flag, int face_index)
QuaternionBase< T > normalize_and_get_length(const QuaternionBase< T > &q, T &out_length)
CartesianBasis invert(const CartesianBasis &basis)
VecBase< T, 3 > transform_direction(const MatBase< T, 3, 3 > &mat, const VecBase< T, 3 > &direction)
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
MatBase< float, 4, 4 > float4x4
VecBase< int32_t, 2 > int2
VecBase< int32_t, 3 > int3
VecBase< float, 3 > float3
float origin[3]
float direction[3]
Definition DNA_ID.h:414
int faces_num
const c_style_mat & ptr() const
BVHTree_NearestPointCallback nearest_callback
BVHTree_RayCastCallback raycast_callback
struct blender::ed::transform::SnapObjectContext::@170374026073064374202114033260227063176045253050 runtime
struct blender::ed::transform::SnapObjectContext::Output ret
i
Definition text_draw.cc:230
#define SNAP_TO_EDGE_ELEMENTS