diff options
Diffstat (limited to 'source/blender/modifiers/intern/MOD_weightvgproximity.c')
-rw-r--r-- | source/blender/modifiers/intern/MOD_weightvgproximity.c | 133 |
1 files changed, 83 insertions, 50 deletions
diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c index 08d7d77c74e..f126e499fc2 100644 --- a/source/blender/modifiers/intern/MOD_weightvgproximity.c +++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c @@ -33,6 +33,7 @@ #include "BLI_listbase.h" #include "BLI_math.h" #include "BLI_rand.h" +#include "BLI_task.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" @@ -42,6 +43,7 @@ #include "BKE_cdderivedmesh.h" #include "BKE_deform.h" #include "BKE_library.h" +#include "BKE_library_query.h" #include "BKE_modifier.h" #include "BKE_texture.h" /* Texture masking. */ @@ -51,7 +53,7 @@ #include "MEM_guardedalloc.h" #include "MOD_weightvg_util.h" -// #define USE_TIMEIT +//#define USE_TIMEIT #ifdef USE_TIMEIT # include "PIL_time.h" @@ -65,6 +67,67 @@ /* Util macro. */ #define OUT_OF_MEMORY() ((void)printf("WeightVGProximity: Out of memory.\n")) +typedef struct Vert2GeomData { + /* Read-only data */ + float (*v_cos)[3]; + + const SpaceTransform *loc2trgt; + + BVHTreeFromMesh *treeData[3]; + + /* Write data, but not needing locking (two different threads will never write same index). */ + float *dist[3]; +} Vert2GeomData; + +/* Data which is localized to each computed chunk (i.e. thread-safe, and with continous subset of index range). */ +typedef struct Vert2GeomDataChunk { + /* Read-only data */ + float last_hit_co[3][3]; + bool is_init[3]; +} Vert2GeomDataChunk; + +/** + * Callback used by BLI_task 'for loop' helper. + */ +static void vert2geom_task_cb_ex(void *userdata, void *userdata_chunk, const int iter, const int UNUSED(thread_id)) +{ + 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; + } + } + } +} + /** * Find nearest vertex and/or edge and/or face, for each vertex (adapted from shrinkwrap.c). */ @@ -72,13 +135,12 @@ 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; + Vert2GeomData data = {0}; + Vert2GeomDataChunk data_chunk = {{{0}}}; + BVHTreeFromMesh treeData_v = {NULL}; BVHTreeFromMesh treeData_e = {NULL}; BVHTreeFromMesh treeData_f = {NULL}; - BVHTreeNearest nearest_v = {0}; - BVHTreeNearest nearest_e = {0}; - BVHTreeNearest nearest_f = {0}; if (dist_v) { /* Create a bvh-tree of the given target's verts. */ @@ -105,45 +167,18 @@ static void get_vert2geom_distance(int numVerts, float (*v_cos)[3], } } - /* 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. */ -#pragma omp parallel for default(shared) private(i) firstprivate(nearest_v, nearest_e, nearest_f) \ - schedule(static) if (numVerts > 10000) - for (i = 0; i < numVerts; i++) { - float tmp_co[3]; - - /* Convert the vertex to tree coordinates. */ - copy_v3_v3(tmp_co, v_cos[i]); - BLI_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_sq = 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_sq); - } - if (dist_e) { - nearest_e.dist_sq = 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_sq); - } - if (dist_f) { - nearest_f.dist_sq = 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_sq); - } - } + data.v_cos = v_cos; + data.loc2trgt = loc2trgt; + data.treeData[0] = &treeData_v; + data.treeData[1] = &treeData_e; + data.treeData[2] = &treeData_f; + data.dist[0] = dist_v; + data.dist[1] = dist_e; + data.dist[2] = dist_f; + + BLI_task_parallel_range_ex( + 0, numVerts, &data, &data_chunk, sizeof(data_chunk), vert2geom_task_cb_ex, + numVerts > 10000, false); if (dist_v) free_bvhtree_from_mesh(&treeData_v); @@ -287,20 +322,18 @@ static bool dependsOnTime(ModifierData *md) return 0; } -static void foreachObjectLink(ModifierData *md, Object *ob, - void (*walk)(void *userData, Object *ob, Object **obpoin), - void *userData) +static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData) { WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *) md; - walk(userData, ob, &wmd->proximity_ob_target); - walk(userData, ob, &wmd->mask_tex_map_obj); + walk(userData, ob, &wmd->proximity_ob_target, IDWALK_NOP); + walk(userData, ob, &wmd->mask_tex_map_obj, IDWALK_NOP); } static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData) { WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *) md; - walk(userData, ob, (ID **)&wmd->mask_texture); + walk(userData, ob, (ID **)&wmd->mask_texture, IDWALK_USER); foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData); } |