diff options
author | Campbell Barton <ideasman42@gmail.com> | 2015-01-13 15:54:14 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2015-01-13 17:36:03 +0300 |
commit | a2a7260915633eda8a3d26aa678baba49b2429ce (patch) | |
tree | 41e042f052e8629a57d0b8d7a0153a420addb605 /source/blender/blenkernel/intern/editmesh_bvh.c | |
parent | bd0077071521f212e8408638c6bf05b55a140eac (diff) |
BMesh: option to filter out faces during raycast
This allows us to more easily cast from the surface of a mesh
without normal offsets (Which can give precision issues).
Diffstat (limited to 'source/blender/blenkernel/intern/editmesh_bvh.c')
-rw-r--r-- | source/blender/blenkernel/intern/editmesh_bvh.c | 96 |
1 files changed, 79 insertions, 17 deletions
diff --git a/source/blender/blenkernel/intern/editmesh_bvh.c b/source/blender/blenkernel/intern/editmesh_bvh.c index 442ab26ffc8..5f2660b5365 100644 --- a/source/blender/blenkernel/intern/editmesh_bvh.c +++ b/source/blender/blenkernel/intern/editmesh_bvh.c @@ -239,6 +239,32 @@ struct RayCastUserData { float uv[2]; }; + +static BMFace *bmbvh_ray_cast_handle_hit( + BMBVHTree *bmtree, struct RayCastUserData *bmcb_data, const BVHTreeRayHit *hit, + float *r_dist, float r_hitout[3], float r_cagehit[3]) +{ + if (r_hitout) { + if (bmtree->flag & BMBVH_RETURN_ORIG) { + BMLoop **ltri = bmtree->looptris[hit->index]; + interp_v3_v3v3v3_uv(r_hitout, ltri[0]->v->co, ltri[1]->v->co, ltri[2]->v->co, bmcb_data->uv); + } + else { + copy_v3_v3(r_hitout, hit->co); + } + + if (r_cagehit) { + copy_v3_v3(r_cagehit, hit->co); + } + } + + if (r_dist) { + *r_dist = hit->dist; + } + + return bmtree->looptris[hit->index][0]->f; +} + static void bmbvh_ray_cast_cb(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit) { struct RayCastUserData *bmcb_data = userdata; @@ -284,32 +310,68 @@ BMFace *BKE_bmbvh_ray_cast(BMBVHTree *bmtree, const float co[3], const float dir bmcb_data.cos_cage = (const float (*)[3])bmtree->cos_cage; BLI_bvhtree_ray_cast(bmtree->tree, co, dir, radius, &hit, bmbvh_ray_cast_cb, &bmcb_data); + if (hit.index != -1 && hit.dist != dist) { - if (r_hitout) { - if (bmtree->flag & BMBVH_RETURN_ORIG) { - BMLoop **ltri = bmtree->looptris[hit.index]; - interp_v3_v3v3v3_uv(r_hitout, ltri[0]->v->co, ltri[1]->v->co, ltri[2]->v->co, bmcb_data.uv); - } - else { - copy_v3_v3(r_hitout, hit.co); - } + return bmbvh_ray_cast_handle_hit(bmtree, &bmcb_data, &hit, r_dist, r_hitout, r_cagehit); + } - if (r_cagehit) { - copy_v3_v3(r_cagehit, hit.co); - } - } + return NULL; +} - if (r_dist) { - *r_dist = hit.dist; - } +/* -------------------------------------------------------------------- */ +/* bmbvh_ray_cast_cb_filter */ - return bmtree->looptris[hit.index][0]->f; +/* Same as BKE_bmbvh_ray_cast but takes a callback to filter out faces. + */ + +struct RayCastUserData_Filter { + struct RayCastUserData bmcb_data; + + BMBVHTree_FaceFilter filter_cb; + void *filter_userdata; +}; + +static void bmbvh_ray_cast_cb_filter(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit) +{ + struct RayCastUserData_Filter *bmcb_data_filter = userdata; + struct RayCastUserData *bmcb_data = &bmcb_data_filter->bmcb_data; + const BMLoop **ltri = bmcb_data->looptris[index]; + if (bmcb_data_filter->filter_cb(ltri[0]->f, bmcb_data_filter->filter_userdata)) { + bmbvh_ray_cast_cb(bmcb_data, index, ray, hit); + } +} + +BMFace *BKE_bmbvh_ray_cast_filter( + BMBVHTree *bmtree, const float co[3], const float dir[3], const float radius, + float *r_dist, float r_hitout[3], float r_cagehit[3], + BMBVHTree_FaceFilter filter_cb, void *filter_userdata) +{ + BVHTreeRayHit hit; + struct RayCastUserData_Filter bmcb_data_filter; + struct RayCastUserData *bmcb_data = &bmcb_data_filter.bmcb_data; + + const float dist = r_dist ? *r_dist : FLT_MAX; + + bmcb_data_filter.filter_cb = filter_cb; + bmcb_data_filter.filter_userdata = filter_userdata; + + if (bmtree->cos_cage) BLI_assert(!(bmtree->bm->elem_index_dirty & BM_VERT)); + + hit.dist = dist; + hit.index = -1; + + /* ok to leave 'uv' uninitialized */ + bmcb_data->looptris = (const BMLoop *(*)[3])bmtree->looptris; + bmcb_data->cos_cage = (const float (*)[3])bmtree->cos_cage; + + BLI_bvhtree_ray_cast(bmtree->tree, co, dir, radius, &hit, bmbvh_ray_cast_cb_filter, &bmcb_data_filter); + if (hit.index != -1 && hit.dist != dist) { + return bmbvh_ray_cast_handle_hit(bmtree, bmcb_data, &hit, r_dist, r_hitout, r_cagehit); } return NULL; } - /* -------------------------------------------------------------------- */ /* BKE_bmbvh_find_face_segment */ |