int closest_point_on_surface(SurfaceModifierData *surmd, const float co[3], float surface_co[3], float surface_nor[3], float surface_vel[3]) { BVHTreeNearest nearest; nearest.index = -1; nearest.dist = FLT_MAX; BLI_bvhtree_find_nearest(surmd->bvhtree->tree, co, &nearest, surmd->bvhtree->nearest_callback, surmd->bvhtree); if (nearest.index != -1) { copy_v3_v3(surface_co, nearest.co); if (surface_nor) { copy_v3_v3(surface_nor, nearest.no); } if (surface_vel) { MFace *mface = CDDM_get_tessface(surmd->dm, nearest.index); copy_v3_v3(surface_vel, surmd->v[mface->v1].co); add_v3_v3(surface_vel, surmd->v[mface->v2].co); add_v3_v3(surface_vel, surmd->v[mface->v3].co); if (mface->v4) add_v3_v3(surface_vel, surmd->v[mface->v4].co); mul_v3_fl(surface_vel, mface->v4 ? 0.25f : (1.0f / 3.0f)); } return 1; } return 0; }
int closest_point_on_surface(SurfaceModifierData *surmd, const float co[3], float surface_co[3], float surface_nor[3], float surface_vel[3]) { BVHTreeNearest nearest; nearest.index = -1; nearest.dist_sq = FLT_MAX; BLI_bvhtree_find_nearest(surmd->bvhtree->tree, co, &nearest, surmd->bvhtree->nearest_callback, surmd->bvhtree); if (nearest.index != -1) { copy_v3_v3(surface_co, nearest.co); if (surface_nor) { copy_v3_v3(surface_nor, nearest.no); } if (surface_vel) { const MLoop *mloop = surmd->bvhtree->loop; const MLoopTri *lt = &surmd->bvhtree->looptri[nearest.index]; copy_v3_v3(surface_vel, surmd->v[mloop[lt->tri[0]].v].co); add_v3_v3(surface_vel, surmd->v[mloop[lt->tri[1]].v].co); add_v3_v3(surface_vel, surmd->v[mloop[lt->tri[2]].v].co); mul_v3_fl(surface_vel, (1.0f / 3.0f)); } return 1; } return 0; }
void rna_Object_closest_point_on_mesh(Object *ob, ReportList *reports, float point_co[3], float max_dist, float n_location[3], float n_normal[3], int *index) { BVHTreeFromMesh treeData= {NULL}; if(ob->derivedFinal==NULL) { BKE_reportf(reports, RPT_ERROR, "object \"%s\" has no mesh data to be used for finding nearest point", ob->id.name+2); return; } /* no need to managing allocation or freeing of the BVH data. this is generated and freed as needed */ bvhtree_from_mesh_faces(&treeData, ob->derivedFinal, 0.0f, 4, 6); if(treeData.tree==NULL) { BKE_reportf(reports, RPT_ERROR, "object \"%s\" could not create internal data for finding nearest point", ob->id.name+2); return; } else { BVHTreeNearest nearest; nearest.index = -1; nearest.dist = max_dist * max_dist; if(BLI_bvhtree_find_nearest(treeData.tree, point_co, &nearest, treeData.nearest_callback, &treeData) != -1) { copy_v3_v3(n_location, nearest.co); copy_v3_v3(n_normal, nearest.no); *index= nearest.index; return; } } zero_v3(n_location); zero_v3(n_normal); *index= -1; }
static void rna_Object_closest_point_on_mesh(Object *ob, bContext *C, ReportList *reports, float origin[3], float distance, PointerRNA *rnaptr_depsgraph, bool *r_success, float r_location[3], float r_normal[3], int *r_index) { BVHTreeFromMesh treeData = {NULL}; if (ob->runtime.mesh_eval == NULL && (ob = eval_object_ensure(ob, C, reports, rnaptr_depsgraph)) == NULL) { return; } /* No need to managing allocation or freeing of the BVH data. * this is generated and freed as needed. */ BKE_bvhtree_from_mesh_get(&treeData, ob->runtime.mesh_eval, BVHTREE_FROM_LOOPTRI, 4); if (treeData.tree == NULL) { BKE_reportf(reports, RPT_ERROR, "Object '%s' could not create internal data for finding nearest point", ob->id.name + 2); return; } else { BVHTreeNearest nearest; nearest.index = -1; nearest.dist_sq = distance * distance; if (BLI_bvhtree_find_nearest( treeData.tree, origin, &nearest, treeData.nearest_callback, &treeData) != -1) { *r_success = true; copy_v3_v3(r_location, nearest.co); copy_v3_v3(r_normal, nearest.no); *r_index = mesh_looptri_to_poly_index(ob->runtime.mesh_eval, &treeData.looptri[nearest.index]); goto finally; } } *r_success = false; zero_v3(r_location); zero_v3(r_normal); *r_index = -1; finally: free_bvhtree_from_mesh(&treeData); }
static void rna_Object_closest_point_on_mesh( Object *ob, ReportList *reports, float origin[3], float distance, int *r_success, float r_location[3], float r_normal[3], int *r_index) { BVHTreeFromMesh treeData = {NULL}; if (ob->derivedFinal == NULL) { BKE_reportf(reports, RPT_ERROR, "Object '%s' has no mesh data to be used for finding nearest point", ob->id.name + 2); return; } /* no need to managing allocation or freeing of the BVH data. this is generated and freed as needed */ bvhtree_from_mesh_looptri(&treeData, ob->derivedFinal, 0.0f, 4, 6); if (treeData.tree == NULL) { BKE_reportf(reports, RPT_ERROR, "Object '%s' could not create internal data for finding nearest point", ob->id.name + 2); return; } else { BVHTreeNearest nearest; nearest.index = -1; nearest.dist_sq = distance * distance; if (BLI_bvhtree_find_nearest(treeData.tree, origin, &nearest, treeData.nearest_callback, &treeData) != -1) { *r_success = true; copy_v3_v3(r_location, nearest.co); copy_v3_v3(r_normal, nearest.no); *r_index = dm_looptri_to_poly_index(ob->derivedFinal, &treeData.looptri[nearest.index]); goto finally; } } *r_success = false; zero_v3(r_location); zero_v3(r_normal); *r_index = -1; finally: free_bvhtree_from_mesh(&treeData); }
/** * Callback used by BLI_task 'for loop' helper. */ static void vert2geom_task_cb(void *userdata, void *userdata_chunk, int iter) { Vert2GeomData *data = userdata; Vert2GeomDataChunk *data_chunk = userdata_chunk; float tmp_co[3]; int i; /* Convert the vertex to tree coordinates. */ copy_v3_v3(tmp_co, data->v_cos[iter]); BLI_space_transform_apply(data->loc2trgt, tmp_co); for (i = 0; i < ARRAY_SIZE(data->dist); i++) { if (data->dist[i]) { BVHTreeNearest nearest = {0}; /* Note that we use local proximity heuristics (to reduce the nearest search). * * If we already had an hit before in same chunk of tasks (i.e. previous vertex by index), * we assume this vertex is going to have a close hit to that other vertex, so we can initiate * the "nearest.dist" with the expected value to that last hit. * This will lead in pruning of the search tree. */ nearest.dist_sq = data_chunk->is_init[i] ? len_squared_v3v3(tmp_co, data_chunk->last_hit_co[i]) : FLT_MAX; nearest.index = -1; /* Compute and store result. If invalid (-1 idx), keep FLT_MAX dist. */ BLI_bvhtree_find_nearest(data->treeData[i]->tree, tmp_co, &nearest, data->treeData[i]->nearest_callback, data->treeData[i]); data->dist[i][iter] = sqrtf(nearest.dist_sq); if (nearest.index != -1) { copy_v3_v3(data_chunk->last_hit_co[i], nearest.co); data_chunk->is_init[i] = true; } } } }
BMVert *BKE_bmbvh_find_vert_closest(BMBVHTree *bmtree, const float co[3], const float dist_max) { BVHTreeNearest hit; struct VertSearchUserData bmcb_data; const float dist_max_sq = dist_max * dist_max; if (bmtree->cos_cage) BLI_assert(!(bmtree->bm->elem_index_dirty & BM_VERT)); hit.dist_sq = dist_max_sq; hit.index = -1; bmcb_data.looptris = (const BMLoop *(*)[3])bmtree->looptris; bmcb_data.cos_cage = (const float (*)[3])bmtree->cos_cage; bmcb_data.dist_max_sq = dist_max_sq; BLI_bvhtree_find_nearest(bmtree->tree, co, &hit, bmbvh_find_vert_closest_cb, &bmcb_data); if (hit.index != -1) { BMLoop **ltri = bmtree->looptris[hit.index]; return ltri[bmcb_data.index_tri]->v; } return NULL; }
/* * Shrinkwrap moving vertexs to the nearest surface point on the target * * it builds a BVHTree from the target mesh and then performs a * NN matches for each vertex */ static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc) { int i; BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh; BVHTreeNearest nearest = NULL_BVHTreeNearest; /* Create a bvh-tree of the given target */ bvhtree_from_mesh_faces(&treeData, calc->target, 0.0, 2, 6); if (treeData.tree == NULL) { OUT_OF_MEMORY(); return; } /* Setup nearest */ nearest.index = -1; nearest.dist_sq = FLT_MAX; /* Find the nearest vertex */ #ifndef __APPLE__ #pragma omp parallel for default(none) private(i) firstprivate(nearest) shared(calc, treeData) schedule(static) #endif for (i = 0; i < calc->numVerts; ++i) { float *co = calc->vertexCos[i]; float tmp_co[3]; float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup); if (weight == 0.0f) continue; /* Convert the vertex to tree coordinates */ if (calc->vert) { copy_v3_v3(tmp_co, calc->vert[i].co); } else { copy_v3_v3(tmp_co, co); } space_transform_apply(&calc->local2target, tmp_co); /* Use local proximity heuristics (to reduce the nearest search) * * If we already had an hit before.. we assume this vertex is going to have a close hit to that other vertex * so we can initiate the "nearest.dist" with the expected value to that last hit. * This will lead in pruning of the search tree. */ if (nearest.index != -1) nearest.dist_sq = len_squared_v3v3(tmp_co, nearest.co); else nearest.dist_sq = FLT_MAX; BLI_bvhtree_find_nearest(treeData.tree, tmp_co, &nearest, treeData.nearest_callback, &treeData); /* Found the nearest vertex */ if (nearest.index != -1) { if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_KEEP_ABOVE_SURFACE) { /* Make the vertex stay on the front side of the face */ madd_v3_v3v3fl(tmp_co, nearest.co, nearest.no, calc->keepDist); } else { /* Adjusting the vertex weight, * so that after interpolating it keeps a certain distance from the nearest position */ const float dist = sasqrt(nearest.dist_sq); if (dist > FLT_EPSILON) { /* linear interpolation */ interp_v3_v3v3(tmp_co, tmp_co, nearest.co, (dist - calc->keepDist) / dist); } else { copy_v3_v3(tmp_co, nearest.co); } } /* Convert the coordinates back to mesh coordinates */ space_transform_invert(&calc->local2target, tmp_co); interp_v3_v3v3(co, co, tmp_co, weight); /* linear interpolation */ } } free_bvhtree_from_mesh(&treeData); }
/** * Find nearest vertex and/or edge and/or face, for each vertex (adapted from shrinkwrap.c). */ static void get_vert2geom_distance(int numVerts, float (*v_cos)[3], float *dist_v, float *dist_e, float *dist_f, DerivedMesh *target, const SpaceTransform *loc2trgt) { int i; BVHTreeFromMesh treeData_v = NULL_BVHTreeFromMesh; BVHTreeFromMesh treeData_e = NULL_BVHTreeFromMesh; BVHTreeFromMesh treeData_f = NULL_BVHTreeFromMesh; BVHTreeNearest nearest_v = NULL_BVHTreeNearest; BVHTreeNearest nearest_e = NULL_BVHTreeNearest; BVHTreeNearest nearest_f = NULL_BVHTreeNearest; if (dist_v) { /* Create a bvh-tree of the given target's verts. */ bvhtree_from_mesh_verts(&treeData_v, target, 0.0, 2, 6); if (treeData_v.tree == NULL) { OUT_OF_MEMORY(); return; } } if (dist_e) { /* Create a bvh-tree of the given target's edges. */ bvhtree_from_mesh_edges(&treeData_e, target, 0.0, 2, 6); if (treeData_e.tree == NULL) { OUT_OF_MEMORY(); return; } } if (dist_f) { /* Create a bvh-tree of the given target's faces. */ bvhtree_from_mesh_faces(&treeData_f, target, 0.0, 2, 6); if (treeData_f.tree == NULL) { OUT_OF_MEMORY(); return; } } /* Setup nearest. */ nearest_v.index = nearest_e.index = nearest_f.index = -1; /*nearest_v.dist = nearest_e.dist = nearest_f.dist = FLT_MAX;*/ /* Find the nearest vert/edge/face. */ #ifndef __APPLE__ #pragma omp parallel for default(none) private(i) firstprivate(nearest_v,nearest_e,nearest_f) \ shared(treeData_v,treeData_e,treeData_f,numVerts,v_cos,dist_v,dist_e, \ dist_f,loc2trgt) \ schedule(static) #endif for (i = 0; i < numVerts; i++) { float tmp_co[3]; /* Convert the vertex to tree coordinates. */ copy_v3_v3(tmp_co, v_cos[i]); space_transform_apply(loc2trgt, tmp_co); /* Use local proximity heuristics (to reduce the nearest search). * * If we already had an hit before, we assume this vertex is going to have a close hit to * that other vertex, so we can initiate the "nearest.dist" with the expected value to that * last hit. * This will lead in prunning of the search tree. */ if (dist_v) { nearest_v.dist = nearest_v.index != -1 ? len_squared_v3v3(tmp_co, nearest_v.co) : FLT_MAX; /* Compute and store result. If invalid (-1 idx), keep FLT_MAX dist. */ BLI_bvhtree_find_nearest(treeData_v.tree, tmp_co, &nearest_v, treeData_v.nearest_callback, &treeData_v); dist_v[i] = sqrtf(nearest_v.dist); } if (dist_e) { nearest_e.dist = nearest_e.index != -1 ? len_squared_v3v3(tmp_co, nearest_e.co) : FLT_MAX; /* Compute and store result. If invalid (-1 idx), keep FLT_MAX dist. */ BLI_bvhtree_find_nearest(treeData_e.tree, tmp_co, &nearest_e, treeData_e.nearest_callback, &treeData_e); dist_e[i] = sqrtf(nearest_e.dist); } if (dist_f) { nearest_f.dist = nearest_f.index != -1 ? len_squared_v3v3(tmp_co, nearest_f.co) : FLT_MAX; /* Compute and store result. If invalid (-1 idx), keep FLT_MAX dist. */ BLI_bvhtree_find_nearest(treeData_f.tree, tmp_co, &nearest_f, treeData_f.nearest_callback, &treeData_f); dist_f[i] = sqrtf(nearest_f.dist); } } if (dist_v) free_bvhtree_from_mesh(&treeData_v); if (dist_e) free_bvhtree_from_mesh(&treeData_e); if (dist_f) free_bvhtree_from_mesh(&treeData_f); }
/* from/to_world_space : whether from/to particles are in world or hair space * from/to_mat : additional transform for from/to particles (e.g. for using object space copying) */ static bool remap_hair_emitter(Scene *scene, Object *ob, ParticleSystem *psys, Object *target_ob, ParticleSystem *target_psys, PTCacheEdit *target_edit, float from_mat[4][4], float to_mat[4][4], bool from_global, bool to_global) { ParticleSystemModifierData *target_psmd = psys_get_modifier(target_ob, target_psys); ParticleData *pa, *tpa; PTCacheEditPoint *edit_point; PTCacheEditKey *ekey; BVHTreeFromMesh bvhtree= {NULL}; MFace *mface = NULL, *mf; MEdge *medge = NULL, *me; MVert *mvert; DerivedMesh *dm, *target_dm; int numverts; int i, k; float from_ob_imat[4][4], to_ob_imat[4][4]; float from_imat[4][4], to_imat[4][4]; if (!target_psmd->dm) return false; if (!psys->part || psys->part->type != PART_HAIR) return false; if (!target_psys->part || target_psys->part->type != PART_HAIR) return false; edit_point = target_edit ? target_edit->points : NULL; invert_m4_m4(from_ob_imat, ob->obmat); invert_m4_m4(to_ob_imat, target_ob->obmat); invert_m4_m4(from_imat, from_mat); invert_m4_m4(to_imat, to_mat); if (target_psmd->dm->deformedOnly) { /* we don't want to mess up target_psmd->dm when converting to global coordinates below */ dm = target_psmd->dm; } else { /* warning: this rebuilds target_psmd->dm! */ dm = mesh_get_derived_deform(scene, target_ob, CD_MASK_BAREMESH | CD_MASK_MFACE); } target_dm = target_psmd->dm; /* don't modify the original vertices */ dm = CDDM_copy(dm); /* BMESH_ONLY, deform dm may not have tessface */ DM_ensure_tessface(dm); numverts = dm->getNumVerts(dm); mvert = dm->getVertArray(dm); /* convert to global coordinates */ for (i=0; i<numverts; i++) mul_m4_v3(to_mat, mvert[i].co); if (dm->getNumTessFaces(dm) != 0) { mface = dm->getTessFaceArray(dm); bvhtree_from_mesh_faces(&bvhtree, dm, 0.0, 2, 6); } else if (dm->getNumEdges(dm) != 0) { medge = dm->getEdgeArray(dm); bvhtree_from_mesh_edges(&bvhtree, dm, 0.0, 2, 6); } else { dm->release(dm); return false; } for (i = 0, tpa = target_psys->particles, pa = psys->particles; i < target_psys->totpart; i++, tpa++, pa++) { float from_co[3]; BVHTreeNearest nearest; if (from_global) mul_v3_m4v3(from_co, from_ob_imat, pa->hair[0].co); else mul_v3_m4v3(from_co, from_ob_imat, pa->hair[0].world_co); mul_m4_v3(from_mat, from_co); nearest.index = -1; nearest.dist_sq = FLT_MAX; BLI_bvhtree_find_nearest(bvhtree.tree, from_co, &nearest, bvhtree.nearest_callback, &bvhtree); if (nearest.index == -1) { if (G.debug & G_DEBUG) printf("No nearest point found for hair root!"); continue; } if (mface) { float v[4][3]; mf = &mface[nearest.index]; copy_v3_v3(v[0], mvert[mf->v1].co); copy_v3_v3(v[1], mvert[mf->v2].co); copy_v3_v3(v[2], mvert[mf->v3].co); if (mf->v4) { copy_v3_v3(v[3], mvert[mf->v4].co); interp_weights_poly_v3(tpa->fuv, v, 4, nearest.co); } else interp_weights_poly_v3(tpa->fuv, v, 3, nearest.co); tpa->foffset = 0.0f; tpa->num = nearest.index; tpa->num_dmcache = psys_particle_dm_face_lookup(target_ob, target_dm, tpa->num, tpa->fuv, NULL); } else { me = &medge[nearest.index]; tpa->fuv[1] = line_point_factor_v3(nearest.co, mvert[me->v1].co, mvert[me->v2].co); tpa->fuv[0] = 1.0f - tpa->fuv[1]; tpa->fuv[2] = tpa->fuv[3] = 0.0f; tpa->foffset = 0.0f; tpa->num = nearest.index; tpa->num_dmcache = -1; } /* translate hair keys */ { HairKey *key, *tkey; float hairmat[4][4], imat[4][4]; float offset[3]; if (to_global) copy_m4_m4(imat, target_ob->obmat); else { /* note: using target_dm here, which is in target_ob object space and has full modifiers */ psys_mat_hair_to_object(target_ob, target_dm, target_psys->part->from, tpa, hairmat); invert_m4_m4(imat, hairmat); } mul_m4_m4m4(imat, imat, to_imat); /* offset in world space */ sub_v3_v3v3(offset, nearest.co, from_co); if (edit_point) { for (k=0, key=pa->hair, tkey=tpa->hair, ekey = edit_point->keys; k<tpa->totkey; k++, key++, tkey++, ekey++) { float co_orig[3]; if (from_global) mul_v3_m4v3(co_orig, from_ob_imat, key->co); else mul_v3_m4v3(co_orig, from_ob_imat, key->world_co); mul_m4_v3(from_mat, co_orig); add_v3_v3v3(tkey->co, co_orig, offset); mul_m4_v3(imat, tkey->co); ekey->flag |= PEK_USE_WCO; } edit_point++; } else { for (k=0, key=pa->hair, tkey=tpa->hair; k<tpa->totkey; k++, key++, tkey++) { float co_orig[3]; if (from_global) mul_v3_m4v3(co_orig, from_ob_imat, key->co); else mul_v3_m4v3(co_orig, from_ob_imat, key->world_co); mul_m4_v3(from_mat, co_orig); add_v3_v3v3(tkey->co, co_orig, offset); mul_m4_v3(imat, tkey->co); } } } } free_bvhtree_from_mesh(&bvhtree); dm->release(dm); psys_free_path_cache(target_psys, target_edit); PE_update_object(scene, target_ob, 0); return true; }
static int connect_hair(Scene *scene, Object *ob, ParticleSystem *psys) { ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys); ParticleData *pa; PTCacheEdit *edit; PTCacheEditPoint *point; PTCacheEditKey *ekey = NULL; HairKey *key; BVHTreeFromMesh bvhtree= {NULL}; BVHTreeNearest nearest; MFace *mface, *mf; MVert *mvert; DerivedMesh *dm = NULL; int numverts; int i, k; float hairmat[4][4], imat[4][4]; float v[4][3], vec[3]; if (!psys || !psys->part || psys->part->type != PART_HAIR || !psmd->dm) return FALSE; edit= psys->edit; point= edit ? edit->points : NULL; if (psmd->dm->deformedOnly) { /* we don't want to mess up psmd->dm when converting to global coordinates below */ dm = psmd->dm; } else { dm = mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH); } /* don't modify the original vertices */ dm = CDDM_copy(dm); /* BMESH_ONLY, deform dm may not have tessface */ DM_ensure_tessface(dm); numverts = dm->getNumVerts(dm); mvert = dm->getVertArray(dm); mface = dm->getTessFaceArray(dm); /* convert to global coordinates */ for (i=0; i<numverts; i++) mul_m4_v3(ob->obmat, mvert[i].co); bvhtree_from_mesh_faces(&bvhtree, dm, 0.0, 2, 6); for (i=0, pa= psys->particles; i<psys->totpart; i++, pa++) { key = pa->hair; nearest.index = -1; nearest.dist = FLT_MAX; BLI_bvhtree_find_nearest(bvhtree.tree, key->co, &nearest, bvhtree.nearest_callback, &bvhtree); if (nearest.index == -1) { if (G.debug & G_DEBUG) printf("No nearest point found for hair root!"); continue; } mf = &mface[nearest.index]; copy_v3_v3(v[0], mvert[mf->v1].co); copy_v3_v3(v[1], mvert[mf->v2].co); copy_v3_v3(v[2], mvert[mf->v3].co); if (mf->v4) { copy_v3_v3(v[3], mvert[mf->v4].co); interp_weights_poly_v3(pa->fuv, v, 4, nearest.co); } else interp_weights_poly_v3(pa->fuv, v, 3, nearest.co); pa->num = nearest.index; pa->num_dmcache = psys_particle_dm_face_lookup(ob, psmd->dm, pa->num, pa->fuv, NULL); psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat); invert_m4_m4(imat, hairmat); sub_v3_v3v3(vec, nearest.co, key->co); if (point) { ekey = point->keys; point++; } for (k=0, key=pa->hair; k<pa->totkey; k++, key++) { add_v3_v3(key->co, vec); mul_m4_v3(imat, key->co); if (ekey) { ekey->flag |= PEK_USE_WCO; ekey++; } } } free_bvhtree_from_mesh(&bvhtree); dm->release(dm); psys_free_path_cache(psys, psys->edit); psys->flag &= ~PSYS_GLOBAL_HAIR; PE_update_object(scene, ob, 0); return TRUE; }
/* * Shrinkwrap to the nearest vertex * * it builds a kdtree of vertexs we can attach to and then * for each vertex performs a nearest vertex search on the tree */ static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc) { int i; BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh; BVHTreeNearest nearest = NULL_BVHTreeNearest; BENCH(bvhtree_from_mesh_verts(&treeData, calc->target, 0.0, 2, 6)); if (treeData.tree == NULL) { OUT_OF_MEMORY(); return; } //Setup nearest nearest.index = -1; nearest.dist = FLT_MAX; #ifndef __APPLE__ #pragma omp parallel for default(none) private(i) firstprivate(nearest) shared(treeData,calc) schedule(static) #endif for (i = 0; i<calc->numVerts; ++i) { float *co = calc->vertexCos[i]; float tmp_co[3]; float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup); if (weight == 0.0f) continue; //Convert the vertex to tree coordinates if (calc->vert) { copy_v3_v3(tmp_co, calc->vert[i].co); } else { copy_v3_v3(tmp_co, co); } space_transform_apply(&calc->local2target, tmp_co); //Use local proximity heuristics (to reduce the nearest search) // //If we already had an hit before.. we assume this vertex is going to have a close hit to that other vertex //so we can initiate the "nearest.dist" with the expected value to that last hit. //This will lead in prunning of the search tree. if (nearest.index != -1) nearest.dist = len_squared_v3v3(tmp_co, nearest.co); else nearest.dist = FLT_MAX; BLI_bvhtree_find_nearest(treeData.tree, tmp_co, &nearest, treeData.nearest_callback, &treeData); //Found the nearest vertex if (nearest.index != -1) { //Adjusting the vertex weight, so that after interpolating it keeps a certain distance from the nearest position float dist = sasqrt(nearest.dist); if (dist > FLT_EPSILON) weight *= (dist - calc->keepDist)/dist; //Convert the coordinates back to mesh coordinates copy_v3_v3(tmp_co, nearest.co); space_transform_invert(&calc->local2target, tmp_co); interp_v3_v3v3(co, co, tmp_co, weight); //linear interpolation } } free_bvhtree_from_mesh(&treeData); }