diff options
author | Campbell Barton <ideasman42@gmail.com> | 2019-04-17 07:17:24 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2019-04-17 07:21:24 +0300 |
commit | e12c08e8d170b7ca40f204a5b0423c23a9fbc2c1 (patch) | |
tree | 8cf3453d12edb177a218ef8009357518ec6cab6a /source/blender/blenkernel/intern/shrinkwrap.c | |
parent | b3dabc200a4b0399ec6b81f2ff2730d07b44fcaa (diff) |
ClangFormat: apply to source, most of intern
Apply clang format as proposed in T53211.
For details on usage and instructions for migrating branches
without conflicts, see:
https://wiki.blender.org/wiki/Tools/ClangFormat
Diffstat (limited to 'source/blender/blenkernel/intern/shrinkwrap.c')
-rw-r--r-- | source/blender/blenkernel/intern/shrinkwrap.c | 2133 |
1 files changed, 1113 insertions, 1020 deletions
diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c index 4c219fa14f2..7a9ccc66824 100644 --- a/source/blender/blenkernel/intern/shrinkwrap.c +++ b/source/blender/blenkernel/intern/shrinkwrap.c @@ -48,7 +48,7 @@ #include "BKE_deform.h" #include "BKE_editmesh.h" -#include "BKE_mesh.h" /* for OMP limits. */ +#include "BKE_mesh.h" /* for OMP limits. */ #include "BKE_subsurf.h" #include "BKE_mesh_runtime.h" @@ -69,261 +69,271 @@ #define OUT_OF_MEMORY() ((void)printf("Shrinkwrap: Out of memory\n")) typedef struct ShrinkwrapCalcData { - ShrinkwrapModifierData *smd; //shrinkwrap modifier data + ShrinkwrapModifierData *smd; //shrinkwrap modifier data - struct Object *ob; //object we are applying shrinkwrap to + struct Object *ob; //object we are applying shrinkwrap to - struct MVert *vert; //Array of verts being projected (to fetch normals or other data) - float(*vertexCos)[3]; //vertexs being shrinkwraped - int numVerts; + struct MVert *vert; //Array of verts being projected (to fetch normals or other data) + float (*vertexCos)[3]; //vertexs being shrinkwraped + int numVerts; - struct MDeformVert *dvert; //Pointer to mdeform array - int vgroup; //Vertex group num - bool invert_vgroup; /* invert vertex group influence */ + struct MDeformVert *dvert; //Pointer to mdeform array + int vgroup; //Vertex group num + bool invert_vgroup; /* invert vertex group influence */ - struct Mesh *target; //mesh we are shrinking to - struct SpaceTransform local2target; //transform to move between local and target space - struct ShrinkwrapTreeData *tree; // mesh BVH tree data + struct Mesh *target; //mesh we are shrinking to + struct SpaceTransform local2target; //transform to move between local and target space + struct ShrinkwrapTreeData *tree; // mesh BVH tree data - struct Object *aux_target; + struct Object *aux_target; - float keepDist; //Distance to keep above target surface (units are in local space) + float keepDist; //Distance to keep above target surface (units are in local space) } ShrinkwrapCalcData; typedef struct ShrinkwrapCalcCBData { - ShrinkwrapCalcData *calc; + ShrinkwrapCalcData *calc; - ShrinkwrapTreeData *tree; - ShrinkwrapTreeData *aux_tree; + ShrinkwrapTreeData *tree; + ShrinkwrapTreeData *aux_tree; - float *proj_axis; - SpaceTransform *local2aux; + float *proj_axis; + SpaceTransform *local2aux; } ShrinkwrapCalcCBData; - /* Checks if the modifier needs target normals with these settings. */ bool BKE_shrinkwrap_needs_normals(int shrinkType, int shrinkMode) { - return (shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) || - (shrinkType != MOD_SHRINKWRAP_NEAREST_VERTEX && shrinkMode == MOD_SHRINKWRAP_ABOVE_SURFACE); + return (shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) || + (shrinkType != MOD_SHRINKWRAP_NEAREST_VERTEX && + shrinkMode == MOD_SHRINKWRAP_ABOVE_SURFACE); } /* Initializes the mesh data structure from the given mesh and settings. */ -bool BKE_shrinkwrap_init_tree(ShrinkwrapTreeData *data, Mesh *mesh, int shrinkType, int shrinkMode, bool force_normals) +bool BKE_shrinkwrap_init_tree( + ShrinkwrapTreeData *data, Mesh *mesh, int shrinkType, int shrinkMode, bool force_normals) { - memset(data, 0, sizeof(*data)); + memset(data, 0, sizeof(*data)); - if (!mesh || mesh->totvert <= 0) { - return false; - } + if (!mesh || mesh->totvert <= 0) { + return false; + } - data->mesh = mesh; + data->mesh = mesh; - if (shrinkType == MOD_SHRINKWRAP_NEAREST_VERTEX) { - data->bvh = BKE_bvhtree_from_mesh_get(&data->treeData, mesh, BVHTREE_FROM_VERTS, 2); + if (shrinkType == MOD_SHRINKWRAP_NEAREST_VERTEX) { + data->bvh = BKE_bvhtree_from_mesh_get(&data->treeData, mesh, BVHTREE_FROM_VERTS, 2); - return data->bvh != NULL; - } - else { - if (mesh->totpoly <= 0) { - return false; - } + return data->bvh != NULL; + } + else { + if (mesh->totpoly <= 0) { + return false; + } - data->bvh = BKE_bvhtree_from_mesh_get(&data->treeData, mesh, BVHTREE_FROM_LOOPTRI, 4); + data->bvh = BKE_bvhtree_from_mesh_get(&data->treeData, mesh, BVHTREE_FROM_LOOPTRI, 4); - if (data->bvh == NULL) { - return false; - } + if (data->bvh == NULL) { + return false; + } - if (force_normals || BKE_shrinkwrap_needs_normals(shrinkType, shrinkMode)) { - data->pnors = CustomData_get_layer(&mesh->pdata, CD_NORMAL); - if ((mesh->flag & ME_AUTOSMOOTH) != 0) { - data->clnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL); - } - } + if (force_normals || BKE_shrinkwrap_needs_normals(shrinkType, shrinkMode)) { + data->pnors = CustomData_get_layer(&mesh->pdata, CD_NORMAL); + if ((mesh->flag & ME_AUTOSMOOTH) != 0) { + data->clnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL); + } + } - if (shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) { - data->boundary = mesh->runtime.shrinkwrap_data; - } + if (shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) { + data->boundary = mesh->runtime.shrinkwrap_data; + } - return true; - } + return true; + } } /* Frees the tree data if necessary. */ void BKE_shrinkwrap_free_tree(ShrinkwrapTreeData *data) { - free_bvhtree_from_mesh(&data->treeData); + free_bvhtree_from_mesh(&data->treeData); } /* Free boundary data for target project */ void BKE_shrinkwrap_discard_boundary_data(struct Mesh *mesh) { - struct ShrinkwrapBoundaryData *data = mesh->runtime.shrinkwrap_data; + struct ShrinkwrapBoundaryData *data = mesh->runtime.shrinkwrap_data; - if (data != NULL) { - MEM_freeN((void *)data->edge_is_boundary); - MEM_freeN((void *)data->looptri_has_boundary); - MEM_freeN((void *)data->vert_boundary_id); - MEM_freeN((void *)data->boundary_verts); + if (data != NULL) { + MEM_freeN((void *)data->edge_is_boundary); + MEM_freeN((void *)data->looptri_has_boundary); + MEM_freeN((void *)data->vert_boundary_id); + MEM_freeN((void *)data->boundary_verts); - MEM_freeN(data); - } + MEM_freeN(data); + } - mesh->runtime.shrinkwrap_data = NULL; + mesh->runtime.shrinkwrap_data = NULL; } /* Accumulate edge for average boundary edge direction. */ -static void merge_vert_dir(ShrinkwrapBoundaryVertData *vdata, signed char *status, int index, const float edge_dir[3], signed char side) +static void merge_vert_dir(ShrinkwrapBoundaryVertData *vdata, + signed char *status, + int index, + const float edge_dir[3], + signed char side) { - BLI_assert(index >= 0); - float *direction = vdata[index].direction; - - /* Invert the direction vector if either: - * - This is the second edge and both edges have the vertex as start or end. - * - For third and above, if it points in the wrong direction. - */ - if (status[index] >= 0 ? status[index] == side : dot_v3v3(direction, edge_dir) < 0) { - sub_v3_v3(direction, edge_dir); - } - else { - add_v3_v3(direction, edge_dir); - } - - status[index] = (status[index] == 0) ? side : -1; + BLI_assert(index >= 0); + float *direction = vdata[index].direction; + + /* Invert the direction vector if either: + * - This is the second edge and both edges have the vertex as start or end. + * - For third and above, if it points in the wrong direction. + */ + if (status[index] >= 0 ? status[index] == side : dot_v3v3(direction, edge_dir) < 0) { + sub_v3_v3(direction, edge_dir); + } + else { + add_v3_v3(direction, edge_dir); + } + + status[index] = (status[index] == 0) ? side : -1; } static ShrinkwrapBoundaryData *shrinkwrap_build_boundary_data(struct Mesh *mesh) { - const MLoop *mloop = mesh->mloop; - const MEdge *medge = mesh->medge; - const MVert *mvert = mesh->mvert; + const MLoop *mloop = mesh->mloop; + const MEdge *medge = mesh->medge; + const MVert *mvert = mesh->mvert; - /* Count faces per edge (up to 2). */ - char *edge_mode = MEM_calloc_arrayN((size_t)mesh->totedge, sizeof(char), __func__); + /* Count faces per edge (up to 2). */ + char *edge_mode = MEM_calloc_arrayN((size_t)mesh->totedge, sizeof(char), __func__); - for (int i = 0; i < mesh->totloop; i++) { - unsigned int eidx = mloop[i].e; + for (int i = 0; i < mesh->totloop; i++) { + unsigned int eidx = mloop[i].e; - if (edge_mode[eidx] < 2) { - edge_mode[eidx]++; - } - } + if (edge_mode[eidx] < 2) { + edge_mode[eidx]++; + } + } - /* Build the boundary edge bitmask. */ - BLI_bitmap *edge_is_boundary = BLI_BITMAP_NEW(mesh->totedge, "ShrinkwrapBoundaryData::edge_is_boundary"); - unsigned int num_boundary_edges = 0; + /* Build the boundary edge bitmask. */ + BLI_bitmap *edge_is_boundary = BLI_BITMAP_NEW(mesh->totedge, + "ShrinkwrapBoundaryData::edge_is_boundary"); + unsigned int num_boundary_edges = 0; - for (int i = 0; i < mesh->totedge; i++) { - edge_mode[i] = (edge_mode[i] == 1); + for (int i = 0; i < mesh->totedge; i++) { + edge_mode[i] = (edge_mode[i] == 1); - if (edge_mode[i]) { - BLI_BITMAP_ENABLE(edge_is_boundary, i); - num_boundary_edges++; - } - } + if (edge_mode[i]) { + BLI_BITMAP_ENABLE(edge_is_boundary, i); + num_boundary_edges++; + } + } - /* If no boundary, return NULL. */ - if (num_boundary_edges == 0) { - MEM_freeN(edge_is_boundary); - MEM_freeN(edge_mode); - return NULL; - } + /* If no boundary, return NULL. */ + if (num_boundary_edges == 0) { + MEM_freeN(edge_is_boundary); + MEM_freeN(edge_mode); + return NULL; + } - /* Allocate the data object. */ - ShrinkwrapBoundaryData *data = MEM_callocN(sizeof(ShrinkwrapBoundaryData), "ShrinkwrapBoundaryData"); + /* Allocate the data object. */ + ShrinkwrapBoundaryData *data = MEM_callocN(sizeof(ShrinkwrapBoundaryData), + "ShrinkwrapBoundaryData"); - data->edge_is_boundary = edge_is_boundary; + data->edge_is_boundary = edge_is_boundary; - /* Build the boundary looptri bitmask. */ - const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(mesh); - int totlooptri = BKE_mesh_runtime_looptri_len(mesh); + /* Build the boundary looptri bitmask. */ + const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(mesh); + int totlooptri = BKE_mesh_runtime_looptri_len(mesh); - BLI_bitmap *looptri_has_boundary = BLI_BITMAP_NEW(totlooptri, "ShrinkwrapBoundaryData::looptri_is_boundary"); + BLI_bitmap *looptri_has_boundary = BLI_BITMAP_NEW(totlooptri, + "ShrinkwrapBoundaryData::looptri_is_boundary"); - for (int i = 0; i < totlooptri; i++) { - int edges[3]; - BKE_mesh_looptri_get_real_edges(mesh, &mlooptri[i], edges); + for (int i = 0; i < totlooptri; i++) { + int edges[3]; + BKE_mesh_looptri_get_real_edges(mesh, &mlooptri[i], edges); - for (int j = 0; j < 3; j++) { - if (edges[j] >= 0 && edge_mode[edges[j]]) { - BLI_BITMAP_ENABLE(looptri_has_boundary, i); - break; - } - } - } + for (int j = 0; j < 3; j++) { + if (edges[j] >= 0 && edge_mode[edges[j]]) { + BLI_BITMAP_ENABLE(looptri_has_boundary, i); + break; + } + } + } - data->looptri_has_boundary = looptri_has_boundary; + data->looptri_has_boundary = looptri_has_boundary; - /* Find boundary vertices and build a mapping table for compact storage of data. */ - int *vert_boundary_id = MEM_calloc_arrayN((size_t)mesh->totvert, sizeof(int), "ShrinkwrapBoundaryData::vert_boundary_id"); + /* Find boundary vertices and build a mapping table for compact storage of data. */ + int *vert_boundary_id = MEM_calloc_arrayN( + (size_t)mesh->totvert, sizeof(int), "ShrinkwrapBoundaryData::vert_boundary_id"); - for (int i = 0; i < mesh->totedge; i++) { - if (edge_mode[i]) { - const MEdge *edge = &medge[i]; + for (int i = 0; i < mesh->totedge; i++) { + if (edge_mode[i]) { + const MEdge *edge = &medge[i]; - vert_boundary_id[edge->v1] = 1; - vert_boundary_id[edge->v2] = 1; - } - } + vert_boundary_id[edge->v1] = 1; + vert_boundary_id[edge->v2] = 1; + } + } - unsigned int num_boundary_verts = 0; + unsigned int num_boundary_verts = 0; - for (int i = 0; i < mesh->totvert; i++) { - vert_boundary_id[i] = (vert_boundary_id[i] != 0) ? (int)num_boundary_verts++ : -1; - } + for (int i = 0; i < mesh->totvert; i++) { + vert_boundary_id[i] = (vert_boundary_id[i] != 0) ? (int)num_boundary_verts++ : -1; + } - data->vert_boundary_id = vert_boundary_id; - data->num_boundary_verts = num_boundary_verts; + data->vert_boundary_id = vert_boundary_id; + data->num_boundary_verts = num_boundary_verts; - /* Compute average directions. */ - ShrinkwrapBoundaryVertData *boundary_verts = MEM_calloc_arrayN(num_boundary_verts, sizeof(*boundary_verts), "ShrinkwrapBoundaryData::boundary_verts"); + /* Compute average directions. */ + ShrinkwrapBoundaryVertData *boundary_verts = MEM_calloc_arrayN( + num_boundary_verts, sizeof(*boundary_verts), "ShrinkwrapBoundaryData::boundary_verts"); - signed char *vert_status = MEM_calloc_arrayN(num_boundary_verts, sizeof(char), __func__); + signed char *vert_status = MEM_calloc_arrayN(num_boundary_verts, sizeof(char), __func__); - for (int i = 0; i < mesh->totedge; i++) { - if (edge_mode[i]) { - const MEdge *edge = &medge[i]; + for (int i = 0; i < mesh->totedge; i++) { + if (edge_mode[i]) { + const MEdge *edge = &medge[i]; - float dir[3]; - sub_v3_v3v3(dir, mvert[edge->v2].co, mvert[edge->v1].co); - normalize_v3(dir); + float dir[3]; + sub_v3_v3v3(dir, mvert[edge->v2].co, mvert[edge->v1].co); + normalize_v3(dir); - merge_vert_dir(boundary_verts, vert_status, vert_boundary_id[edge->v1], dir, 1); - merge_vert_dir(boundary_verts, vert_status, vert_boundary_id[edge->v2], dir, 2); - } - } + merge_vert_dir(boundary_verts, vert_status, vert_boundary_id[edge->v1], dir, 1); + merge_vert_dir(boundary_verts, vert_status, vert_boundary_id[edge->v2], dir, 2); + } + } - MEM_freeN(vert_status); + MEM_freeN(vert_status); - /* Finalize average direction and compute normal. */ - for (int i = 0; i < mesh->totvert; i++) { - int bidx = vert_boundary_id[i]; + /* Finalize average direction and compute normal. */ + for (int i = 0; i < mesh->totvert; i++) { + int bidx = vert_boundary_id[i]; - if (bidx >= 0) { - ShrinkwrapBoundaryVertData *vdata = &boundary_verts[bidx]; - float no[3], tmp[3]; + if (bidx >= 0) { + ShrinkwrapBoundaryVertData *vdata = &boundary_verts[bidx]; + float no[3], tmp[3]; - normalize_v3(vdata->direction); + normalize_v3(vdata->direction); - normal_short_to_float_v3(no, mesh->mvert[i].no); - cross_v3_v3v3(tmp, no, vdata->direction); - cross_v3_v3v3(vdata->normal_plane, tmp, no); - normalize_v3(vdata->normal_plane); - } - } + normal_short_to_float_v3(no, mesh->mvert[i].no); + cross_v3_v3v3(tmp, no, vdata->direction); + cross_v3_v3v3(vdata->normal_plane, tmp, no); + normalize_v3(vdata->normal_plane); + } + } - data->boundary_verts = boundary_verts; + data->boundary_verts = boundary_verts; - MEM_freeN(edge_mode); - return data; + MEM_freeN(edge_mode); + return data; } void BKE_shrinkwrap_compute_boundary_data(struct Mesh *mesh) { - BKE_shrinkwrap_discard_boundary_data(mesh); + BKE_shrinkwrap_discard_boundary_data(mesh); - mesh->runtime.shrinkwrap_data = shrinkwrap_build_boundary_data(mesh); + mesh->runtime.shrinkwrap_data = shrinkwrap_build_boundary_data(mesh); } /* @@ -332,88 +342,87 @@ void BKE_shrinkwrap_compute_boundary_data(struct Mesh *mesh) * 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_cb_ex( - void *__restrict userdata, - const int i, - const ParallelRangeTLS *__restrict tls) +static void shrinkwrap_calc_nearest_vertex_cb_ex(void *__restrict userdata, + const int i, + const ParallelRangeTLS *__restrict tls) { - ShrinkwrapCalcCBData *data = userdata; - - ShrinkwrapCalcData *calc = data->calc; - BVHTreeFromMesh *treeData = &data->tree->treeData; - BVHTreeNearest *nearest = tls->userdata_chunk; - - float *co = calc->vertexCos[i]; - float tmp_co[3]; - float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup); - - if (calc->invert_vgroup) { - weight = 1.0f - weight; - } - - if (weight == 0.0f) { - return; - } - - /* 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); - } - BLI_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) { - /* Adjusting the vertex weight, - * so that after interpolating it keeps a certain distance from the nearest position */ - if (nearest->dist_sq > FLT_EPSILON) { - const float dist = sqrtf(nearest->dist_sq); - weight *= (dist - calc->keepDist) / dist; - } - - /* Convert the coordinates back to mesh coordinates */ - copy_v3_v3(tmp_co, nearest->co); - BLI_space_transform_invert(&calc->local2target, tmp_co); - - interp_v3_v3v3(co, co, tmp_co, weight); /* linear interpolation */ - } + ShrinkwrapCalcCBData *data = userdata; + + ShrinkwrapCalcData *calc = data->calc; + BVHTreeFromMesh *treeData = &data->tree->treeData; + BVHTreeNearest *nearest = tls->userdata_chunk; + + float *co = calc->vertexCos[i]; + float tmp_co[3]; + float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup); + + if (calc->invert_vgroup) { + weight = 1.0f - weight; + } + + if (weight == 0.0f) { + return; + } + + /* 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); + } + BLI_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) { + /* Adjusting the vertex weight, + * so that after interpolating it keeps a certain distance from the nearest position */ + if (nearest->dist_sq > FLT_EPSILON) { + const float dist = sqrtf(nearest->dist_sq); + weight *= (dist - calc->keepDist) / dist; + } + + /* Convert the coordinates back to mesh coordinates */ + copy_v3_v3(tmp_co, nearest->co); + BLI_space_transform_invert(&calc->local2target, tmp_co); + + interp_v3_v3v3(co, co, tmp_co, weight); /* linear interpolation */ + } } static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc) { - BVHTreeNearest nearest = NULL_BVHTreeNearest; - - /* Setup nearest */ - nearest.index = -1; - nearest.dist_sq = FLT_MAX; - - ShrinkwrapCalcCBData data = { .calc = calc, .tree = calc->tree, }; - ParallelRangeSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = (calc->numVerts > BKE_MESH_OMP_LIMIT); - settings.userdata_chunk = &nearest; - settings.userdata_chunk_size = sizeof(nearest); - BLI_task_parallel_range(0, calc->numVerts, - &data, shrinkwrap_calc_nearest_vertex_cb_ex, - &settings); + BVHTreeNearest nearest = NULL_BVHTreeNearest; + + /* Setup nearest */ + nearest.index = -1; + nearest.dist_sq = FLT_MAX; + + ShrinkwrapCalcCBData data = { + .calc = calc, + .tree = calc->tree, + }; + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (calc->numVerts > BKE_MESH_OMP_LIMIT); + settings.userdata_chunk = &nearest; + settings.userdata_chunk_size = sizeof(nearest); + BLI_task_parallel_range( + 0, calc->numVerts, &data, shrinkwrap_calc_nearest_vertex_cb_ex, &settings); } - /* * This function raycast a single vertex and updates the hit if the "hit" is considered valid. * Returns true if "hit" was updated. @@ -422,267 +431,280 @@ static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc) * - MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE (front faces hits are ignored) * - MOD_SHRINKWRAP_CULL_TARGET_BACKFACE (back faces hits are ignored) */ -bool BKE_shrinkwrap_project_normal( - char options, const float vert[3], const float dir[3], - const float ray_radius, const SpaceTransform *transf, - ShrinkwrapTreeData *tree, BVHTreeRayHit *hit) +bool BKE_shrinkwrap_project_normal(char options, + const float vert[3], + const float dir[3], + const float ray_radius, + const SpaceTransform *transf, + ShrinkwrapTreeData *tree, + BVHTreeRayHit *hit) { - /* don't use this because this dist value could be incompatible - * this value used by the callback for comparing prev/new dist values. - * also, at the moment there is no need to have a corrected 'dist' value */ -// #define USE_DIST_CORRECT + /* don't use this because this dist value could be incompatible + * this value used by the callback for comparing prev/new dist values. + * also, at the moment there is no need to have a corrected 'dist' value */ + // #define USE_DIST_CORRECT - float tmp_co[3], tmp_no[3]; - const float *co, *no; - BVHTreeRayHit hit_tmp; + float tmp_co[3], tmp_no[3]; + const float *co, *no; + BVHTreeRayHit hit_tmp; - /* Copy from hit (we need to convert hit rays from one space coordinates to the other */ - memcpy(&hit_tmp, hit, sizeof(hit_tmp)); + /* Copy from hit (we need to convert hit rays from one space coordinates to the other */ + memcpy(&hit_tmp, hit, sizeof(hit_tmp)); - /* Apply space transform (TODO readjust dist) */ - if (transf) { - copy_v3_v3(tmp_co, vert); - BLI_space_transform_apply(transf, tmp_co); - co = tmp_co; + /* Apply space transform (TODO readjust dist) */ + if (transf) { + copy_v3_v3(tmp_co, vert); + BLI_space_transform_apply(transf, tmp_co); + co = tmp_co; - copy_v3_v3(tmp_no, dir); - BLI_space_transform_apply_normal(transf, tmp_no); - no = tmp_no; + copy_v3_v3(tmp_no, dir); + BLI_space_transform_apply_normal(transf, tmp_no); + no = tmp_no; #ifdef USE_DIST_CORRECT - hit_tmp.dist *= mat4_to_scale(((SpaceTransform *)transf)->local2target); + hit_tmp.dist *= mat4_to_scale(((SpaceTransform *)transf)->local2target); #endif - } - else { - co = vert; - no = dir; - } - - hit_tmp.index = -1; - - BLI_bvhtree_ray_cast(tree->bvh, co, no, ray_radius, &hit_tmp, tree->treeData.raycast_callback, &tree->treeData); - - if (hit_tmp.index != -1) { - /* invert the normal first so face culling works on rotated objects */ - if (transf) { - BLI_space_transform_invert_normal(transf, hit_tmp.no); - } - - if (options & MOD_SHRINKWRAP_CULL_TARGET_MASK) { - /* apply backface */ - const float dot = dot_v3v3(dir, hit_tmp.no); - if (((options & MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE) && dot <= 0.0f) || - ((options & MOD_SHRINKWRAP_CULL_TARGET_BACKFACE) && dot >= 0.0f)) - { - return false; /* Ignore hit */ - } - } - - if (transf) { - /* Inverting space transform (TODO make coeherent with the initial dist readjust) */ - BLI_space_transform_invert(transf, hit_tmp.co); + } + else { + co = vert; + no = dir; + } + + hit_tmp.index = -1; + + BLI_bvhtree_ray_cast( + tree->bvh, co, no, ray_radius, &hit_tmp, tree->treeData.raycast_callback, &tree->treeData); + + if (hit_tmp.index != -1) { + /* invert the normal first so face culling works on rotated objects */ + if (transf) { + BLI_space_transform_invert_normal(transf, hit_tmp.no); + } + + if (options & MOD_SHRINKWRAP_CULL_TARGET_MASK) { + /* apply backface */ + const float dot = dot_v3v3(dir, hit_tmp.no); + if (((options & MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE) && dot <= 0.0f) || + ((options & MOD_SHRINKWRAP_CULL_TARGET_BACKFACE) && dot >= 0.0f)) { + return false; /* Ignore hit */ + } + } + + if (transf) { + /* Inverting space transform (TODO make coeherent with the initial dist readjust) */ + BLI_space_transform_invert(transf, hit_tmp.co); #ifdef USE_DIST_CORRECT - hit_tmp.dist = len_v3v3(vert, hit_tmp.co); + hit_tmp.dist = len_v3v3(vert, hit_tmp.co); #endif - } + } - BLI_assert(hit_tmp.dist <= hit->dist); + BLI_assert(hit_tmp.dist <= hit->dist); - memcpy(hit, &hit_tmp, sizeof(hit_tmp)); - return true; - } - return false; + memcpy(hit, &hit_tmp, sizeof(hit_tmp)); + return true; + } + return false; } -static void shrinkwrap_calc_normal_projection_cb_ex( - void *__restrict userdata, - const int i, - const ParallelRangeTLS *__restrict tls) +static void shrinkwrap_calc_normal_projection_cb_ex(void *__restrict userdata, + const int i, + const ParallelRangeTLS *__restrict tls) { - ShrinkwrapCalcCBData *data = userdata; - - ShrinkwrapCalcData *calc = data->calc; - ShrinkwrapTreeData *tree = data->tree; - ShrinkwrapTreeData *aux_tree = data->aux_tree; - - float *proj_axis = data->proj_axis; - SpaceTransform *local2aux = data->local2aux; - - BVHTreeRayHit *hit = tls->userdata_chunk; - - const float proj_limit_squared = calc->smd->projLimit * calc->smd->projLimit; - float *co = calc->vertexCos[i]; - float tmp_co[3], tmp_no[3]; - float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup); - - if (calc->invert_vgroup) { - weight = 1.0f - weight; - } - - if (weight == 0.0f) { - return; - } - - if (calc->vert != NULL && calc->smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL) { - /* calc->vert contains verts from evaluated mesh. */ - /* These coordinates are deformed by vertexCos only for normal projection (to get correct normals) */ - /* for other cases calc->verts contains undeformed coordinates and vertexCos should be used */ - copy_v3_v3(tmp_co, calc->vert[i].co); - normal_short_to_float_v3(tmp_no, calc->vert[i].no); - } - else { - copy_v3_v3(tmp_co, co); - copy_v3_v3(tmp_no, proj_axis); - } - - hit->index = -1; - hit->dist = BVH_RAYCAST_DIST_MAX; /* TODO: we should use FLT_MAX here, but sweepsphere code isn't prepared for that */ - - bool is_aux = false; - - /* Project over positive direction of axis */ - if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR) { - if (aux_tree) { - if (BKE_shrinkwrap_project_normal( - 0, tmp_co, tmp_no, 0.0, - local2aux, aux_tree, hit)) - { - is_aux = true; - } - } - - if (BKE_shrinkwrap_project_normal( - calc->smd->shrinkOpts, tmp_co, tmp_no, 0.0, - &calc->local2target, tree, hit)) - { - is_aux = false; - } - } - - /* Project over negative direction of axis */ - if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR) { - float inv_no[3]; - negate_v3_v3(inv_no, tmp_no); - - char options = calc->smd->shrinkOpts; - - if ((options & MOD_SHRINKWRAP_INVERT_CULL_TARGET) && (options & MOD_SHRINKWRAP_CULL_TARGET_MASK)) { - options ^= MOD_SHRINKWRAP_CULL_TARGET_MASK; - } - - if (aux_tree) { - if (BKE_shrinkwrap_project_normal( - 0, tmp_co, inv_no, 0.0, - local2aux, aux_tree, hit)) - { - is_aux = true; - } - } - - if (BKE_shrinkwrap_project_normal( - options, tmp_co, inv_no, 0.0, - &calc->local2target, tree, hit)) - { - is_aux = false; - } - } - - /* don't set the initial dist (which is more efficient), - * because its calculated in the targets space, we want the dist in our own space */ - if (proj_limit_squared != 0.0f) { - if (hit->index != -1 && len_squared_v3v3(hit->co, co) > proj_limit_squared) { - hit->index = -1; - } - } - - if (hit->index != -1) { - if (is_aux) { - BKE_shrinkwrap_snap_point_to_surface( - aux_tree, local2aux, calc->smd->shrinkMode, - hit->index, hit->co, hit->no, calc->keepDist, tmp_co, hit->co); - } - else { - BKE_shrinkwrap_snap_point_to_surface( - tree, &calc->local2target, calc->smd->shrinkMode, - hit->index, hit->co, hit->no, calc->keepDist, tmp_co, hit->co); - } - - interp_v3_v3v3(co, co, hit->co, weight); - } + ShrinkwrapCalcCBData *data = userdata; + + ShrinkwrapCalcData *calc = data->calc; + ShrinkwrapTreeData *tree = data->tree; + ShrinkwrapTreeData *aux_tree = data->aux_tree; + + float *proj_axis = data->proj_axis; + SpaceTransform *local2aux = data->local2aux; + + BVHTreeRayHit *hit = tls->userdata_chunk; + + const float proj_limit_squared = calc->smd->projLimit * calc->smd->projLimit; + float *co = calc->vertexCos[i]; + float tmp_co[3], tmp_no[3]; + float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup); + + if (calc->invert_vgroup) { + weight = 1.0f - weight; + } + + if (weight == 0.0f) { + return; + } + + if (calc->vert != NULL && calc->smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL) { + /* calc->vert contains verts from evaluated mesh. */ + /* These coordinates are deformed by vertexCos only for normal projection (to get correct normals) */ + /* for other cases calc->verts contains undeformed coordinates and vertexCos should be used */ + copy_v3_v3(tmp_co, calc->vert[i].co); + normal_short_to_float_v3(tmp_no, calc->vert[i].no); + } + else { + copy_v3_v3(tmp_co, co); + copy_v3_v3(tmp_no, proj_axis); + } + + hit->index = -1; + hit->dist = + BVH_RAYCAST_DIST_MAX; /* TODO: we should use FLT_MAX here, but sweepsphere code isn't prepared for that */ + + bool is_aux = false; + + /* Project over positive direction of axis */ + if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR) { + if (aux_tree) { + if (BKE_shrinkwrap_project_normal(0, tmp_co, tmp_no, 0.0, local2aux, aux_tree, hit)) { + is_aux = true; + } + } + + if (BKE_shrinkwrap_project_normal( + calc->smd->shrinkOpts, tmp_co, tmp_no, 0.0, &calc->local2target, tree, hit)) { + is_aux = false; + } + } + + /* Project over negative direction of axis */ + if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR) { + float inv_no[3]; + negate_v3_v3(inv_no, tmp_no); + + char options = calc->smd->shrinkOpts; + + if ((options & MOD_SHRINKWRAP_INVERT_CULL_TARGET) && + (options & MOD_SHRINKWRAP_CULL_TARGET_MASK)) { + options ^= MOD_SHRINKWRAP_CULL_TARGET_MASK; + } + + if (aux_tree) { + if (BKE_shrinkwrap_project_normal(0, tmp_co, inv_no, 0.0, local2aux, aux_tree, hit)) { + is_aux = true; + } + } + + if (BKE_shrinkwrap_project_normal( + options, tmp_co, inv_no, 0.0, &calc->local2target, tree, hit)) { + is_aux = false; + } + } + + /* don't set the initial dist (which is more efficient), + * because its calculated in the targets space, we want the dist in our own space */ + if (proj_limit_squared != 0.0f) { + if (hit->index != -1 && len_squared_v3v3(hit->co, co) > proj_limit_squared) { + hit->index = -1; + } + } + + if (hit->index != -1) { + if (is_aux) { + BKE_shrinkwrap_snap_point_to_surface(aux_tree, + local2aux, + calc->smd->shrinkMode, + hit->index, + hit->co, + hit->no, + calc->keepDist, + tmp_co, + hit->co); + } + else { + BKE_shrinkwrap_snap_point_to_surface(tree, + &calc->local2target, + calc->smd->shrinkMode, + hit->index, + hit->co, + hit->no, + calc->keepDist, + tmp_co, + hit->co); + } + + interp_v3_v3v3(co, co, hit->co, weight); + } } static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc) { - /* Options about projection direction */ - float proj_axis[3] = {0.0f, 0.0f, 0.0f}; - - /* Raycast and tree stuff */ - - /** \note 'hit.dist' is kept in the targets space, this is only used - * for finding the best hit, to get the real dist, - * measure the len_v3v3() from the input coord to hit.co */ - BVHTreeRayHit hit; - - /* auxiliary target */ - Mesh *auxMesh = NULL; - ShrinkwrapTreeData *aux_tree = NULL; - ShrinkwrapTreeData aux_tree_stack; - SpaceTransform local2aux; - - /* If the user doesn't allows to project in any direction of projection axis - * then there's nothing todo. */ - if ((calc->smd->shrinkOpts & (MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR | MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR)) == 0) - return; - - /* Prepare data to retrieve the direction in which we should project each vertex */ - if (calc->smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL) { - if (calc->vert == NULL) return; - } - else { - /* The code supports any axis that is a combination of X,Y,Z - * although currently UI only allows to set the 3 different axis */ - if (calc->smd->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_X_AXIS) proj_axis[0] = 1.0f; - if (calc->smd->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_Y_AXIS) proj_axis[1] = 1.0f; - if (calc->smd->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_Z_AXIS) proj_axis[2] = 1.0f; - - normalize_v3(proj_axis); - - /* Invalid projection direction */ - if (len_squared_v3(proj_axis) < FLT_EPSILON) { - return; - } - } - - if (calc->aux_target) { - auxMesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(calc->aux_target, false); - if (!auxMesh) - return; - BLI_SPACE_TRANSFORM_SETUP(&local2aux, calc->ob, calc->aux_target); - } - - if (BKE_shrinkwrap_init_tree(&aux_tree_stack, auxMesh, calc->smd->shrinkType, calc->smd->shrinkMode, false)) { - aux_tree = &aux_tree_stack; - } - - /* After successfully build the trees, start projection vertices. */ - ShrinkwrapCalcCBData data = { - .calc = calc, .tree = calc->tree, .aux_tree = aux_tree, - .proj_axis = proj_axis, .local2aux = &local2aux, - }; - ParallelRangeSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = (calc->numVerts > BKE_MESH_OMP_LIMIT); - settings.userdata_chunk = &hit; - settings.userdata_chunk_size = sizeof(hit); - BLI_task_parallel_range(0, calc->numVerts, - &data, - shrinkwrap_calc_normal_projection_cb_ex, - &settings); - - /* free data structures */ - if (aux_tree) { - BKE_shrinkwrap_free_tree(aux_tree); - } + /* Options about projection direction */ + float proj_axis[3] = {0.0f, 0.0f, 0.0f}; + + /* Raycast and tree stuff */ + + /** \note 'hit.dist' is kept in the targets space, this is only used + * for finding the best hit, to get the real dist, + * measure the len_v3v3() from the input coord to hit.co */ + BVHTreeRayHit hit; + + /* auxiliary target */ + Mesh *auxMesh = NULL; + ShrinkwrapTreeData *aux_tree = NULL; + ShrinkwrapTreeData aux_tree_stack; + SpaceTransform local2aux; + + /* If the user doesn't allows to project in any direction of projection axis + * then there's nothing todo. */ + if ((calc->smd->shrinkOpts & + (MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR | MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR)) == 0) + return; + + /* Prepare data to retrieve the direction in which we should project each vertex */ + if (calc->smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL) { + if (calc->vert == NULL) + return; + } + else { + /* The code supports any axis that is a combination of X,Y,Z + * although currently UI only allows to set the 3 different axis */ + if (calc->smd->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_X_AXIS) + proj_axis[0] = 1.0f; + if (calc->smd->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_Y_AXIS) + proj_axis[1] = 1.0f; + if (calc->smd->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_Z_AXIS) + proj_axis[2] = 1.0f; + + normalize_v3(proj_axis); + + /* Invalid projection direction */ + if (len_squared_v3(proj_axis) < FLT_EPSILON) { + return; + } + } + + if (calc->aux_target) { + auxMesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(calc->aux_target, false); + if (!auxMesh) + return; + BLI_SPACE_TRANSFORM_SETUP(&local2aux, calc->ob, calc->aux_target); + } + + if (BKE_shrinkwrap_init_tree( + &aux_tree_stack, auxMesh, calc->smd->shrinkType, calc->smd->shrinkMode, false)) { + aux_tree = &aux_tree_stack; + } + + /* After successfully build the trees, start projection vertices. */ + ShrinkwrapCalcCBData data = { + .calc = calc, + .tree = calc->tree, + .aux_tree = aux_tree, + .proj_axis = proj_axis, + .local2aux = &local2aux, + }; + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (calc->numVerts > BKE_MESH_OMP_LIMIT); + settings.userdata_chunk = &hit; + settings.userdata_chunk_size = sizeof(hit); + BLI_task_parallel_range( + 0, calc->numVerts, &data, shrinkwrap_calc_normal_projection_cb_ex, &settings); + + /* free data structures */ + if (aux_tree) { + BKE_shrinkwrap_free_tree(aux_tree); + } } /* @@ -702,331 +724,375 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc) //#define TRACE_TARGET_PROJECT typedef struct TargetProjectTriData { - const float **vtri_co; - const float (*vtri_no)[3]; - const float *point_co; + const float **vtri_co; + const float (*vtri_no)[3]; + const float *point_co; - float n0_minus_n2[3], n1_minus_n2[3]; - float c0_minus_c2[3], c1_minus_c2[3]; + float n0_minus_n2[3], n1_minus_n2[3]; + float c0_minus_c2[3], c1_minus_c2[3]; - /* Current interpolated position and normal. */ - float co_interp[3], no_interp[3]; + /* Current interpolated position and normal. */ + float co_interp[3], no_interp[3]; } TargetProjectTriData; /* Computes the deviation of the equation system from goal. */ static void target_project_tri_deviation(void *userdata, const float x[3], float r_delta[3]) { - TargetProjectTriData *data = userdata; + TargetProjectTriData *data = userdata; - float w[3] = { x[0], x[1], 1.0f - x[0] - x[1] }; - interp_v3_v3v3v3(data->co_interp, data->vtri_co[0], data->vtri_co[1], data->vtri_co[2], w); - interp_v3_v3v3v3(data->no_interp, data->vtri_no[0], data->vtri_no[1], data->vtri_no[2], w); + float w[3] = {x[0], x[1], 1.0f - x[0] - x[1]}; + interp_v3_v3v3v3(data->co_interp, data->vtri_co[0], data->vtri_co[1], data->vtri_co[2], w); + interp_v3_v3v3v3(data->no_interp, data->vtri_no[0], data->vtri_no[1], data->vtri_no[2], w); - madd_v3_v3v3fl(r_delta, data->co_interp, data->no_interp, x[2]); - sub_v3_v3(r_delta, data->point_co); + madd_v3_v3v3fl(r_delta, data->co_interp, data->no_interp, x[2]); + sub_v3_v3(r_delta, data->point_co); } /* Computes the Jacobian matrix of the equation system. */ static void target_project_tri_jacobian(void *userdata, const float x[3], float r_jacobian[3][3]) { - TargetProjectTriData *data = userdata; + TargetProjectTriData *data = userdata; - madd_v3_v3v3fl(r_jacobian[0], data->c0_minus_c2, data->n0_minus_n2, x[2]); - madd_v3_v3v3fl(r_jacobian[1], data->c1_minus_c2, data->n1_minus_n2, x[2]); + madd_v3_v3v3fl(r_jacobian[0], data->c0_minus_c2, data->n0_minus_n2, x[2]); + madd_v3_v3v3fl(r_jacobian[1], data->c1_minus_c2, data->n1_minus_n2, x[2]); - copy_v3_v3(r_jacobian[2], data->vtri_no[2]); - madd_v3_v3fl(r_jacobian[2], data->n0_minus_n2, x[0]); - madd_v3_v3fl(r_jacobian[2], data->n1_minus_n2, x[1]); + copy_v3_v3(r_jacobian[2], data->vtri_no[2]); + madd_v3_v3fl(r_jacobian[2], data->n0_minus_n2, x[0]); + madd_v3_v3fl(r_jacobian[2], data->n1_minus_n2, x[1]); } /* Clamp barycentric weights to the triangle. */ static void target_project_tri_clamp(float x[3]) { - if (x[0] < 0.0f) { - x[0] = 0.0f; - } - if (x[1] < 0.0f) { - x[1] = 0.0f; - } - if (x[0] + x[1] > 1.0f) { - x[0] = x[0] / (x[0] + x[1]); - x[1] = 1.0f - x[0]; - } + if (x[0] < 0.0f) { + x[0] = 0.0f; + } + if (x[1] < 0.0f) { + x[1] = 0.0f; + } + if (x[0] + x[1] > 1.0f) { + x[0] = x[0] / (x[0] + x[1]); + x[1] = 1.0f - x[0]; + } } /* Correct the Newton's method step to keep the coordinates within the triangle. */ -static bool target_project_tri_correct(void *UNUSED(userdata), const float x[3], float step[3], float x_next[3]) +static bool target_project_tri_correct(void *UNUSED(userdata), + const float x[3], + float step[3], + float x_next[3]) { - /* Insignificant correction threshold */ - const float epsilon = 1e-6f; - const float dir_epsilon = 0.05f; - bool fixed = false, locked = false; - - /* Weight 0 and 1 boundary check. */ - for (int i = 0; i < 2; i++) { - if (step[i] > x[i]) { - if (step[i] > dir_epsilon * fabsf(step[1 - i])) { - /* Abort if the solution is clearly outside the domain. */ - if (x[i] < epsilon) { - return false; - } - - /* Scale a significant step down to arrive at the boundary. */ - mul_v3_fl(step, x[i] / step[i]); - fixed = true; - } - else { - /* Reset precision errors to stay at the boundary. */ - step[i] = x[i]; - fixed = locked = true; - } - } - } - - /* Weight 2 boundary check. */ - float sum = x[0] + x[1]; - float sstep = step[0] + step[1]; - - if (sum - sstep > 1.0f) { - if (sstep < -dir_epsilon * (fabsf(step[0]) + fabsf(step[1]))) { - /* Abort if the solution is clearly outside the domain. */ - if (sum > 1.0f - epsilon) { - return false; - } - - /* Scale a significant step down to arrive at the boundary. */ - mul_v3_fl(step, (1.0f - sum) / -sstep); - fixed = true; - } - else { - /* Reset precision errors to stay at the boundary. */ - if (locked) { - step[0] = step[1] = 0.0f; - } - else { - step[0] -= 0.5f * sstep; - step[1] = -step[0]; - fixed = true; - } - } - } - - /* Recompute and clamp the new coordinates after step correction. */ - if (fixed) { - sub_v3_v3v3(x_next, x, step); - target_project_tri_clamp(x_next); - } - - return true; + /* Insignificant correction threshold */ + const float epsilon = 1e-6f; + const float dir_epsilon = 0.05f; + bool fixed = false, locked = false; + + /* Weight 0 and 1 boundary check. */ + for (int i = 0; i < 2; i++) { + if (step[i] > x[i]) { + if (step[i] > dir_epsilon * fabsf(step[1 - i])) { + /* Abort if the solution is clearly outside the domain. */ + if (x[i] < epsilon) { + return false; + } + + /* Scale a significant step down to arrive at the boundary. */ + mul_v3_fl(step, x[i] / step[i]); + fixed = true; + } + else { + /* Reset precision errors to stay at the boundary. */ + step[i] = x[i]; + fixed = locked = true; + } + } + } + + /* Weight 2 boundary check. */ + float sum = x[0] + x[1]; + float sstep = step[0] + step[1]; + + if (sum - sstep > 1.0f) { + if (sstep < -dir_epsilon * (fabsf(step[0]) + fabsf(step[1]))) { + /* Abort if the solution is clearly outside the domain. */ + if (sum > 1.0f - epsilon) { + return false; + } + + /* Scale a significant step down to arrive at the boundary. */ + mul_v3_fl(step, (1.0f - sum) / -sstep); + fixed = true; + } + else { + /* Reset precision errors to stay at the boundary. */ + if (locked) { + step[0] = step[1] = 0.0f; + } + else { + step[0] -= 0.5f * sstep; + step[1] = -step[0]; + fixed = true; + } + } + } + + /* Recompute and clamp the new coordinates after step correction. */ + if (fixed) { + sub_v3_v3v3(x_next, x, step); + target_project_tri_clamp(x_next); + } + + return true; } -static bool target_project_solve_point_tri( - const float *vtri_co[3], const float vtri_no[3][3], const float point_co[3], - const float hit_co[3], float hit_dist_sq, - float r_hit_co[3], float r_hit_no[3]) +static bool target_project_solve_point_tri(const float *vtri_co[3], + const float vtri_no[3][3], + const float point_co[3], + const float hit_co[3], + float hit_dist_sq, + float r_hit_co[3], + float r_hit_no[3]) { - float x[3], tmp[3]; - float dist = sqrtf(hit_dist_sq); - float epsilon = dist * 1.0e-5f; + float x[3], tmp[3]; + float dist = sqrtf(hit_dist_sq); + float epsilon = dist * 1.0e-5f; - CLAMP_MIN(epsilon, 1.0e-5f); + CLAMP_MIN(epsilon, 1.0e-5f); - /* Initial solution vector: barycentric weights plus distance along normal. */ - interp_weights_tri_v3(x, UNPACK3(vtri_co), hit_co); + /* Initial solution vector: barycentric weights plus distance along normal. */ + interp_weights_tri_v3(x, UNPACK3(vtri_co), hit_co); - interp_v3_v3v3v3(r_hit_no, UNPACK3(vtri_no), x); - sub_v3_v3v3(tmp, point_co, hit_co); + interp_v3_v3v3v3(r_hit_no, UNPACK3(vtri_no), x); + sub_v3_v3v3(tmp, point_co, hit_co); - x[2] = (dot_v3v3(tmp, r_hit_no) < 0) ? -dist : dist; + x[2] = (dot_v3v3(tmp, r_hit_no) < 0) ? -dist : dist; - /* Solve the equations iteratively. */ - TargetProjectTriData tri_data = { .vtri_co = vtri_co, .vtri_no = vtri_no, .point_co = point_co, }; + /* Solve the equations iteratively. */ + TargetProjectTriData tri_data = { + .vtri_co = vtri_co, + .vtri_no = vtri_no, + .point_co = point_co, + }; - sub_v3_v3v3(tri_data.n0_minus_n2, vtri_no[0], vtri_no[2]); - sub_v3_v3v3(tri_data.n1_minus_n2, vtri_no[1], vtri_no[2]); - sub_v3_v3v3(tri_data.c0_minus_c2, vtri_co[0], vtri_co[2]); - sub_v3_v3v3(tri_data.c1_minus_c2, vtri_co[1], vtri_co[2]); + sub_v3_v3v3(tri_data.n0_minus_n2, vtri_no[0], vtri_no[2]); + sub_v3_v3v3(tri_data.n1_minus_n2, vtri_no[1], vtri_no[2]); + sub_v3_v3v3(tri_data.c0_minus_c2, vtri_co[0], vtri_co[2]); + sub_v3_v3v3(tri_data.c1_minus_c2, vtri_co[1], vtri_co[2]); - target_project_tri_clamp(x); + target_project_tri_clamp(x); #ifdef TRACE_TARGET_PROJECT - const bool trace = true; + const bool trace = true; #else - const bool trace = false; + const bool trace = false; #endif - bool ok = BLI_newton3d_solve(target_project_tri_deviation, target_project_tri_jacobian, target_project_tri_correct, &tri_data, epsilon, 20, trace, x, x); + bool ok = BLI_newton3d_solve(target_project_tri_deviation, + target_project_tri_jacobian, + target_project_tri_correct, + &tri_data, + epsilon, + 20, + trace, + x, + x); - if (ok) { - copy_v3_v3(r_hit_co, tri_data.co_interp); - copy_v3_v3(r_hit_no, tri_data.no_interp); + if (ok) { + copy_v3_v3(r_hit_co, tri_data.co_interp); + copy_v3_v3(r_hit_no, tri_data.no_interp); - return true; - } + return true; + } - return false; + return false; } -static bool update_hit(BVHTreeNearest *nearest, int index, const float co[3], const float hit_co[3], const float hit_no[3]) +static bool update_hit(BVHTreeNearest *nearest, + int index, + const float co[3], + const float hit_co[3], + const float hit_no[3]) { - float dist_sq = len_squared_v3v3(hit_co, co); + float dist_sq = len_squared_v3v3(hit_co, co); - if (dist_sq < nearest->dist_sq) { + if (dist_sq < nearest->dist_sq) { #ifdef TRACE_TARGET_PROJECT - printf("===> %d (%.3f,%.3f,%.3f) %g < %g\n", index, UNPACK3(hit_co), dist_sq, nearest->dist_sq); + printf( + "===> %d (%.3f,%.3f,%.3f) %g < %g\n", index, UNPACK3(hit_co), dist_sq, nearest->dist_sq); #endif - nearest->index = index; - nearest->dist_sq = dist_sq; - copy_v3_v3(nearest->co, hit_co); - normalize_v3_v3(nearest->no, hit_no); - return true; - } - - return false; + nearest->index = index; + nearest->dist_sq = dist_sq; + copy_v3_v3(nearest->co, hit_co); + normalize_v3_v3(nearest->no, hit_no); + return true; + } + + return false; } /* Target projection on a non-manifold boundary edge - treats it like an infinitely thin cylinder. */ -static void target_project_edge(const ShrinkwrapTreeData *tree, int index, const float co[3], BVHTreeNearest *nearest, int eidx) +static void target_project_edge(const ShrinkwrapTreeData *tree, + int index, + const float co[3], + BVHTreeNearest *nearest, + int eidx) { - const BVHTreeFromMesh *data = &tree->treeData; - const MEdge *edge = &tree->mesh->medge[eidx]; - const float *vedge_co[2] = { data->vert[edge->v1].co, data->vert[edge->v2].co }; + const BVHTreeFromMesh *data = &tree->treeData; + const MEdge *edge = &tree->mesh->medge[eidx]; + const float *vedge_co[2] = {data->vert[edge->v1].co, data->vert[edge->v2].co}; #ifdef TRACE_TARGET_PROJECT - printf("EDGE %d (%.3f,%.3f,%.3f) (%.3f,%.3f,%.3f)\n", eidx, UNPACK3(vedge_co[0]), UNPACK3(vedge_co[1])); + printf("EDGE %d (%.3f,%.3f,%.3f) (%.3f,%.3f,%.3f)\n", + eidx, + UNPACK3(vedge_co[0]), + UNPACK3(vedge_co[1])); #endif - /* Retrieve boundary vertex IDs */ - const int *vert_boundary_id = tree->boundary->vert_boundary_id; - int bid1 = vert_boundary_id[edge->v1], bid2 = vert_boundary_id[edge->v2]; + /* Retrieve boundary vertex IDs */ + const int *vert_boundary_id = tree->boundary->vert_boundary_id; + int bid1 = vert_boundary_id[edge->v1], bid2 = vert_boundary_id[edge->v2]; - if (bid1 < 0 || bid2 < 0) { - return; - } + if (bid1 < 0 || bid2 < 0) { + return; + } - /* Retrieve boundary vertex normals and align them to direction. */ - const ShrinkwrapBoundaryVertData *boundary_verts = tree->boundary->boundary_verts; - float vedge_dir[2][3], dir[3]; + /* Retrieve boundary vertex normals and align them to direction. */ + const ShrinkwrapBoundaryVertData *boundary_verts = tree->boundary->boundary_verts; + float vedge_dir[2][3], dir[3]; - copy_v3_v3(vedge_dir[0], boundary_verts[bid1].normal_plane); - copy_v3_v3(vedge_dir[1], boundary_verts[bid2].normal_plane); + copy_v3_v3(vedge_dir[0], boundary_verts[bid1].normal_plane); + copy_v3_v3(vedge_dir[1], boundary_verts[bid2].normal_plane); - sub_v3_v3v3(dir, vedge_co[1], vedge_co[0]); + sub_v3_v3v3(dir, vedge_co[1], vedge_co[0]); - if (dot_v3v3(boundary_verts[bid1].direction, dir) < 0) { - negate_v3(vedge_dir[0]); - } - if (dot_v3v3(boundary_verts[bid2].direction, dir) < 0) { - negate_v3(vedge_dir[1]); - } + if (dot_v3v3(boundary_verts[bid1].direction, dir) < 0) { + negate_v3(vedge_dir[0]); + } + if (dot_v3v3(boundary_verts[bid2].direction, dir) < 0) { + negate_v3(vedge_dir[1]); + } - /* Solve a quadratic equation: lerp(d0,d1,x) * (co - lerp(v0,v1,x)) = 0 */ - float d0v0 = dot_v3v3(vedge_dir[0], vedge_co[0]), d0v1 = dot_v3v3(vedge_dir[0], vedge_co[1]); - float d1v0 = dot_v3v3(vedge_dir[1], vedge_co[0]), d1v1 = dot_v3v3(vedge_dir[1], vedge_co[1]); - float d0co = dot_v3v3(vedge_dir[0], co); + /* Solve a quadratic equation: lerp(d0,d1,x) * (co - lerp(v0,v1,x)) = 0 */ + float d0v0 = dot_v3v3(vedge_dir[0], vedge_co[0]), d0v1 = dot_v3v3(vedge_dir[0], vedge_co[1]); + float d1v0 = dot_v3v3(vedge_dir[1], vedge_co[0]), d1v1 = dot_v3v3(vedge_dir[1], vedge_co[1]); + float d0co = dot_v3v3(vedge_dir[0], co); - float a = d0v1 - d0v0 + d1v0 - d1v1; - float b = 2 * d0v0 - d0v1 - d0co - d1v0 + dot_v3v3(vedge_dir[1], co); - float c = d0co - d0v0; - float det = b * b - 4 * a * c; + float a = d0v1 - d0v0 + d1v0 - d1v1; + float b = 2 * d0v0 - d0v1 - d0co - d1v0 + dot_v3v3(vedge_dir[1], co); + float c = d0co - d0v0; + float det = b * b - 4 * a * c; - if (det >= 0) { - const float epsilon = 1e-6f; - float sdet = sqrtf(det); - float hit_co[3], hit_no[3]; + if (det >= 0) { + const float epsilon = 1e-6f; + float sdet = sqrtf(det); + float hit_co[3], hit_no[3]; - for (int i = (det > 0 ? 2 : 0); i >= 0; i -= 2) { - float x = (- b + ((float)i - 1) * sdet) / (2 * a); + for (int i = (det > 0 ? 2 : 0); i >= 0; i -= 2) { + float x = (-b + ((float)i - 1) * sdet) / (2 * a); - if (x >= -epsilon && x <= 1.0f + epsilon) { - CLAMP(x, 0, 1); + if (x >= -epsilon && x <= 1.0f + epsilon) { + CLAMP(x, 0, 1); - float vedge_no[2][3]; - normal_short_to_float_v3(vedge_no[0], data->vert[edge->v1].no); - normal_short_to_float_v3(vedge_no[1], data->vert[edge->v2].no); + float vedge_no[2][3]; + normal_short_to_float_v3(vedge_no[0], data->vert[edge->v1].no); + normal_short_to_float_v3(vedge_no[1], data->vert[edge->v2].no); - interp_v3_v3v3(hit_co, vedge_co[0], vedge_co[1], x); - interp_v3_v3v3(hit_no, vedge_no[0], vedge_no[1], x); + interp_v3_v3v3(hit_co, vedge_co[0], vedge_co[1], x); + interp_v3_v3v3(hit_no, vedge_no[0], vedge_no[1], x); - update_hit(nearest, index, co, hit_co, hit_no); - } - } - } + update_hit(nearest, index, co, hit_co, hit_no); + } + } + } } /* Target normal projection BVH callback - based on mesh_looptri_nearest_point. */ -static void mesh_looptri_target_project(void *userdata, int index, const float co[3], BVHTreeNearest *nearest) +static void mesh_looptri_target_project(void *userdata, + int index, + const float co[3], + BVHTreeNearest *nearest) { - const ShrinkwrapTreeData *tree = (ShrinkwrapTreeData *)userdata; - const BVHTreeFromMesh *data = &tree->treeData; - const MLoopTri *lt = &data->looptri[index]; - const MLoop *loop[3] = { &data->loop[lt->tri[0]], &data->loop[lt->tri[1]], &data->loop[lt->tri[2]] }; - const MVert *vtri[3] = { &data->vert[loop[0]->v], &data->vert[loop[1]->v], &data->vert[loop[2]->v] }; - const float *vtri_co[3] = { vtri[0]->co, vtri[1]->co, vtri[2]->co }; - float raw_hit_co[3], hit_co[3], hit_no[3], dist_sq, vtri_no[3][3]; - - /* First find the closest point and bail out if it's worse than the current solution. */ - closest_on_tri_to_point_v3(raw_hit_co, co, UNPACK3(vtri_co)); - dist_sq = len_squared_v3v3(co, raw_hit_co); + const ShrinkwrapTreeData *tree = (ShrinkwrapTreeData *)userdata; + const BVHTreeFromMesh *data = &tree->treeData; + const MLoopTri *lt = &data->looptri[index]; + const MLoop *loop[3] = { + &data->loop[lt->tri[0]], &data->loop[lt->tri[1]], &data->loop[lt->tri[2]]}; + const MVert *vtri[3] = { + &data->vert[loop[0]->v], &data->vert[loop[1]->v], &data->vert[loop[2]->v]}; + const float *vtri_co[3] = {vtri[0]->co, vtri[1]->co, vtri[2]->co}; + float raw_hit_co[3], hit_co[3], hit_no[3], dist_sq, vtri_no[3][3]; + + /* First find the closest point and bail out if it's worse than the current solution. */ + closest_on_tri_to_point_v3(raw_hit_co, co, UNPACK3(vtri_co)); + dist_sq = len_squared_v3v3(co, raw_hit_co); #ifdef TRACE_TARGET_PROJECT - printf("TRIANGLE %d (%.3f,%.3f,%.3f) (%.3f,%.3f,%.3f) (%.3f,%.3f,%.3f) %g %g\n", - index, UNPACK3(vtri_co[0]), UNPACK3(vtri_co[1]), UNPACK3(vtri_co[2]), dist_sq, nearest->dist_sq); + printf("TRIANGLE %d (%.3f,%.3f,%.3f) (%.3f,%.3f,%.3f) (%.3f,%.3f,%.3f) %g %g\n", + index, + UNPACK3(vtri_co[0]), + UNPACK3(vtri_co[1]), + UNPACK3(vtri_co[2]), + dist_sq, + nearest->dist_sq); #endif - if (dist_sq >= nearest->dist_sq) - return; - - /* Decode normals */ - normal_short_to_float_v3(vtri_no[0], vtri[0]->no); - normal_short_to_float_v3(vtri_no[1], vtri[1]->no); - normal_short_to_float_v3(vtri_no[2], vtri[2]->no); - - /* Solve the equations for the triangle */ - if (target_project_solve_point_tri(vtri_co, vtri_no, co, raw_hit_co, dist_sq, hit_co, hit_no)) { - update_hit(nearest, index, co, hit_co, hit_no); - } - /* Boundary edges */ - else if (tree->boundary && BLI_BITMAP_TEST(tree->boundary->looptri_has_boundary, index)) { - const BLI_bitmap *is_boundary = tree->boundary->edge_is_boundary; - int edges[3]; - - BKE_mesh_looptri_get_real_edges(tree->mesh, lt, edges); - - for (int i = 0; i < 3; i++) { - if (edges[i] >= 0 && BLI_BITMAP_TEST(is_boundary, edges[i])) { - target_project_edge(tree, index, co, nearest, edges[i]); - } - } - } + if (dist_sq >= nearest->dist_sq) + return; + + /* Decode normals */ + normal_short_to_float_v3(vtri_no[0], vtri[0]->no); + normal_short_to_float_v3(vtri_no[1], vtri[1]->no); + normal_short_to_float_v3(vtri_no[2], vtri[2]->no); + + /* Solve the equations for the triangle */ + if (target_project_solve_point_tri(vtri_co, vtri_no, co, raw_hit_co, dist_sq, hit_co, hit_no)) { + update_hit(nearest, index, co, hit_co, hit_no); + } + /* Boundary edges */ + else if (tree->boundary && BLI_BITMAP_TEST(tree->boundary->looptri_has_boundary, index)) { + const BLI_bitmap *is_boundary = tree->boundary->edge_is_boundary; + int edges[3]; + + BKE_mesh_looptri_get_real_edges(tree->mesh, lt, edges); + + for (int i = 0; i < 3; i++) { + if (edges[i] >= 0 && BLI_BITMAP_TEST(is_boundary, edges[i])) { + target_project_edge(tree, index, co, nearest, edges[i]); + } + } + } } /* * Maps the point to the nearest surface, either by simple nearest, or by target normal projection. */ -void BKE_shrinkwrap_find_nearest_surface(struct ShrinkwrapTreeData *tree, BVHTreeNearest *nearest, float co[3], int type) +void BKE_shrinkwrap_find_nearest_surface(struct ShrinkwrapTreeData *tree, + BVHTreeNearest *nearest, + float co[3], + int type) { - BVHTreeFromMesh *treeData = &tree->treeData; + BVHTreeFromMesh *treeData = &tree->treeData; - if (type == MOD_SHRINKWRAP_TARGET_PROJECT) { + if (type == MOD_SHRINKWRAP_TARGET_PROJECT) { #ifdef TRACE_TARGET_PROJECT - printf("====== TARGET PROJECT START ======\n"); + printf("====== TARGET PROJECT START ======\n"); #endif - BLI_bvhtree_find_nearest_ex(tree->bvh, co, nearest, mesh_looptri_target_project, tree, BVH_NEAREST_OPTIMAL_ORDER); + BLI_bvhtree_find_nearest_ex( + tree->bvh, co, nearest, mesh_looptri_target_project, tree, BVH_NEAREST_OPTIMAL_ORDER); #ifdef TRACE_TARGET_PROJECT - printf("====== TARGET PROJECT END: %d %g ======\n", nearest->index, nearest->dist_sq); + printf("====== TARGET PROJECT END: %d %g ======\n", nearest->index, nearest->dist_sq); #endif - if (nearest->index < 0) { - /* fallback to simple nearest */ - BLI_bvhtree_find_nearest(tree->bvh, co, nearest, treeData->nearest_callback, treeData); - } - } - else { - BLI_bvhtree_find_nearest(tree->bvh, co, nearest, treeData->nearest_callback, treeData); - } + if (nearest->index < 0) { + /* fallback to simple nearest */ + BLI_bvhtree_find_nearest(tree->bvh, co, nearest, treeData->nearest_callback, treeData); + } + } + else { + BLI_bvhtree_find_nearest(tree->bvh, co, nearest, treeData->nearest_callback, treeData); + } } /* @@ -1035,67 +1101,72 @@ void BKE_shrinkwrap_find_nearest_surface(struct ShrinkwrapTreeData *tree, BVHTre * it builds a BVHTree from the target mesh and then performs a * NN matches for each vertex */ -static void shrinkwrap_calc_nearest_surface_point_cb_ex( - void *__restrict userdata, - const int i, - const ParallelRangeTLS *__restrict tls) +static void shrinkwrap_calc_nearest_surface_point_cb_ex(void *__restrict userdata, + const int i, + const ParallelRangeTLS *__restrict tls) { - ShrinkwrapCalcCBData *data = userdata; - - ShrinkwrapCalcData *calc = data->calc; - BVHTreeNearest *nearest = tls->userdata_chunk; - - float *co = calc->vertexCos[i]; - float tmp_co[3]; - float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup); - - if (calc->invert_vgroup) { - weight = 1.0f - weight; - } - - if (weight == 0.0f) { - return; - } - - /* 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); - } - BLI_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) { - if (calc->smd->shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) { - /* Heuristic doesn't work because of additional restrictions. */ - nearest->index = -1; - nearest->dist_sq = FLT_MAX; - } - else { - nearest->dist_sq = len_squared_v3v3(tmp_co, nearest->co); - } - } - else - nearest->dist_sq = FLT_MAX; - - BKE_shrinkwrap_find_nearest_surface(data->tree, nearest, tmp_co, calc->smd->shrinkType); - - /* Found the nearest vertex */ - if (nearest->index != -1) { - BKE_shrinkwrap_snap_point_to_surface( - data->tree, NULL, calc->smd->shrinkMode, - nearest->index, nearest->co, nearest->no, calc->keepDist, tmp_co, tmp_co); - - /* Convert the coordinates back to mesh coordinates */ - BLI_space_transform_invert(&calc->local2target, tmp_co); - interp_v3_v3v3(co, co, tmp_co, weight); /* linear interpolation */ - } + ShrinkwrapCalcCBData *data = userdata; + + ShrinkwrapCalcData *calc = data->calc; + BVHTreeNearest *nearest = tls->userdata_chunk; + + float *co = calc->vertexCos[i]; + float tmp_co[3]; + float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup); + + if (calc->invert_vgroup) { + weight = 1.0f - weight; + } + + if (weight == 0.0f) { + return; + } + + /* 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); + } + BLI_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) { + if (calc->smd->shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) { + /* Heuristic doesn't work because of additional restrictions. */ + nearest->index = -1; + nearest->dist_sq = FLT_MAX; + } + else { + nearest->dist_sq = len_squared_v3v3(tmp_co, nearest->co); + } + } + else + nearest->dist_sq = FLT_MAX; + + BKE_shrinkwrap_find_nearest_surface(data->tree, nearest, tmp_co, calc->smd->shrinkType); + + /* Found the nearest vertex */ + if (nearest->index != -1) { + BKE_shrinkwrap_snap_point_to_surface(data->tree, + NULL, + calc->smd->shrinkMode, + nearest->index, + nearest->co, + nearest->no, + calc->keepDist, + tmp_co, + tmp_co); + + /* Convert the coordinates back to mesh coordinates */ + BLI_space_transform_invert(&calc->local2target, tmp_co); + interp_v3_v3v3(co, co, tmp_co, weight); /* linear interpolation */ + } } /** @@ -1105,92 +1176,101 @@ static void shrinkwrap_calc_nearest_surface_point_cb_ex( * \param transform: transform from the hit coordinate space to the object space; may be null * \param r_no: output in hit coordinate space; may be shared with inputs */ -void BKE_shrinkwrap_compute_smooth_normal( - const struct ShrinkwrapTreeData *tree, const struct SpaceTransform *transform, - int looptri_idx, const float hit_co[3], const float hit_no[3], float r_no[3]) +void BKE_shrinkwrap_compute_smooth_normal(const struct ShrinkwrapTreeData *tree, + const struct SpaceTransform *transform, + int looptri_idx, + const float hit_co[3], + const float hit_no[3], + float r_no[3]) { - const BVHTreeFromMesh *treeData = &tree->treeData; - const MLoopTri *tri = &treeData->looptri[looptri_idx]; - - /* Interpolate smooth normals if enabled. */ - if ((tree->mesh->mpoly[tri->poly].flag & ME_SMOOTH) != 0) { - const MVert *verts[] = { - &treeData->vert[treeData->loop[tri->tri[0]].v], - &treeData->vert[treeData->loop[tri->tri[1]].v], - &treeData->vert[treeData->loop[tri->tri[2]].v], - }; - float w[3], no[3][3], tmp_co[3]; - - /* Custom and auto smooth split normals. */ - if (tree->clnors) { - copy_v3_v3(no[0], tree->clnors[tri->tri[0]]); - copy_v3_v3(no[1], tree->clnors[tri->tri[1]]); - copy_v3_v3(no[2], tree->clnors[tri->tri[2]]); - } - /* Ordinary vertex normals. */ - else { - normal_short_to_float_v3(no[0], verts[0]->no); - normal_short_to_float_v3(no[1], verts[1]->no); - normal_short_to_float_v3(no[2], verts[2]->no); - } - - /* Barycentric weights from hit point. */ - copy_v3_v3(tmp_co, hit_co); - - if (transform) { - BLI_space_transform_apply(transform, tmp_co); - } - - interp_weights_tri_v3(w, verts[0]->co, verts[1]->co, verts[2]->co, tmp_co); - - /* Interpolate using weights. */ - interp_v3_v3v3v3(r_no, no[0], no[1], no[2], w); - - if (transform) { - BLI_space_transform_invert_normal(transform, r_no); - } - else { - normalize_v3(r_no); - } - } - /* Use the polygon normal if flat. */ - else if (tree->pnors != NULL) { - copy_v3_v3(r_no, tree->pnors[tri->poly]); - } - /* Finally fallback to the looptri normal. */ - else { - copy_v3_v3(r_no, hit_no); - } + const BVHTreeFromMesh *treeData = &tree->treeData; + const MLoopTri *tri = &treeData->looptri[looptri_idx]; + + /* Interpolate smooth normals if enabled. */ + if ((tree->mesh->mpoly[tri->poly].flag & ME_SMOOTH) != 0) { + const MVert *verts[] = { + &treeData->vert[treeData->loop[tri->tri[0]].v], + &treeData->vert[treeData->loop[tri->tri[1]].v], + &treeData->vert[treeData->loop[tri->tri[2]].v], + }; + float w[3], no[3][3], tmp_co[3]; + + /* Custom and auto smooth split normals. */ + if (tree->clnors) { + copy_v3_v3(no[0], tree->clnors[tri->tri[0]]); + copy_v3_v3(no[1], tree->clnors[tri->tri[1]]); + copy_v3_v3(no[2], tree->clnors[tri->tri[2]]); + } + /* Ordinary vertex normals. */ + else { + normal_short_to_float_v3(no[0], verts[0]->no); + normal_short_to_float_v3(no[1], verts[1]->no); + normal_short_to_float_v3(no[2], verts[2]->no); + } + + /* Barycentric weights from hit point. */ + copy_v3_v3(tmp_co, hit_co); + + if (transform) { + BLI_space_transform_apply(transform, tmp_co); + } + + interp_weights_tri_v3(w, verts[0]->co, verts[1]->co, verts[2]->co, tmp_co); + + /* Interpolate using weights. */ + interp_v3_v3v3v3(r_no, no[0], no[1], no[2], w); + + if (transform) { + BLI_space_transform_invert_normal(transform, r_no); + } + else { + normalize_v3(r_no); + } + } + /* Use the polygon normal if flat. */ + else if (tree->pnors != NULL) { + copy_v3_v3(r_no, tree->pnors[tri->poly]); + } + /* Finally fallback to the looptri normal. */ + else { + copy_v3_v3(r_no, hit_no); + } } /* Helper for MOD_SHRINKWRAP_INSIDE, MOD_SHRINKWRAP_OUTSIDE and MOD_SHRINKWRAP_OUTSIDE_SURFACE. */ -static void shrinkwrap_snap_with_side(float r_point_co[3], const float point_co[3], const float hit_co[3], const float hit_no[3], float goal_dist, float forcesign, bool forcesnap) +static void shrinkwrap_snap_with_side(float r_point_co[3], + const float point_co[3], + const float hit_co[3], + const float hit_no[3], + float goal_dist, + float forcesign, + bool forcesnap) { - float dist = len_v3v3(point_co, hit_co); - - /* If exactly on the surface, push out along normal */ - if (dist < FLT_EPSILON) { - if (forcesnap || goal_dist > 0) { - madd_v3_v3v3fl(r_point_co, hit_co, hit_no, goal_dist * forcesign); - } - else { - copy_v3_v3(r_point_co, hit_co); - } - } - /* Move to the correct side if needed */ - else { - float delta[3]; - sub_v3_v3v3(delta, point_co, hit_co); - float dsign = signf(dot_v3v3(delta, hit_no) * forcesign); - - /* If on the wrong side or too close, move to correct */ - if (forcesnap || dsign * dist < goal_dist) { - interp_v3_v3v3(r_point_co, point_co, hit_co, (dist - goal_dist * dsign) / dist); - } - else { - copy_v3_v3(r_point_co, point_co); - } - } + float dist = len_v3v3(point_co, hit_co); + + /* If exactly on the surface, push out along normal */ + if (dist < FLT_EPSILON) { + if (forcesnap || goal_dist > 0) { + madd_v3_v3v3fl(r_point_co, hit_co, hit_no, goal_dist * forcesign); + } + else { + copy_v3_v3(r_point_co, hit_co); + } + } + /* Move to the correct side if needed */ + else { + float delta[3]; + sub_v3_v3v3(delta, point_co, hit_co); + float dsign = signf(dot_v3v3(delta, hit_no) * forcesign); + + /* If on the wrong side or too close, move to correct */ + if (forcesnap || dsign * dist < goal_dist) { + interp_v3_v3v3(r_point_co, point_co, hit_co, (dist - goal_dist * dsign) / dist); + } + else { + copy_v3_v3(r_point_co, point_co); + } + } } /** @@ -1200,174 +1280,187 @@ static void shrinkwrap_snap_with_side(float r_point_co[3], const float point_co[ * \param transform: transform from the hit coordinate space to the object space; may be null * \param r_point_co: may be the same memory location as point_co, hit_co, or hit_no. */ -void BKE_shrinkwrap_snap_point_to_surface( - const struct ShrinkwrapTreeData *tree, const struct SpaceTransform *transform, - int mode, int hit_idx, const float hit_co[3], const float hit_no[3], float goal_dist, - const float point_co[3], float r_point_co[3]) +void BKE_shrinkwrap_snap_point_to_surface(const struct ShrinkwrapTreeData *tree, + const struct SpaceTransform *transform, + int mode, + int hit_idx, + const float hit_co[3], + const float hit_no[3], + float goal_dist, + const float point_co[3], + float r_point_co[3]) { - float dist, tmp[3]; - - switch (mode) { - /* Offsets along the line between point_co and hit_co. */ - case MOD_SHRINKWRAP_ON_SURFACE: - if (goal_dist != 0 && (dist = len_v3v3(point_co, hit_co)) > FLT_EPSILON) { - interp_v3_v3v3(r_point_co, point_co, hit_co, (dist - goal_dist) / dist); - } - else { - copy_v3_v3(r_point_co, hit_co); - } - break; - - case MOD_SHRINKWRAP_INSIDE: - shrinkwrap_snap_with_side(r_point_co, point_co, hit_co, hit_no, goal_dist, -1, false); - break; - - case MOD_SHRINKWRAP_OUTSIDE: - shrinkwrap_snap_with_side(r_point_co, point_co, hit_co, hit_no, goal_dist, +1, false); - break; - - case MOD_SHRINKWRAP_OUTSIDE_SURFACE: - if (goal_dist != 0) { - shrinkwrap_snap_with_side(r_point_co, point_co, hit_co, hit_no, goal_dist, +1, true); - } - else { - copy_v3_v3(r_point_co, hit_co); - } - break; - - /* Offsets along the normal */ - case MOD_SHRINKWRAP_ABOVE_SURFACE: - if (goal_dist != 0) { - BKE_shrinkwrap_compute_smooth_normal(tree, transform, hit_idx, hit_co, hit_no, tmp); - madd_v3_v3v3fl(r_point_co, hit_co, tmp, goal_dist); - } - else { - copy_v3_v3(r_point_co, hit_co); - } - break; - - default: - printf("Unknown Shrinkwrap surface snap mode: %d\n", mode); - copy_v3_v3(r_point_co, hit_co); - } + float dist, tmp[3]; + + switch (mode) { + /* Offsets along the line between point_co and hit_co. */ + case MOD_SHRINKWRAP_ON_SURFACE: + if (goal_dist != 0 && (dist = len_v3v3(point_co, hit_co)) > FLT_EPSILON) { + interp_v3_v3v3(r_point_co, point_co, hit_co, (dist - goal_dist) / dist); + } + else { + copy_v3_v3(r_point_co, hit_co); + } + break; + + case MOD_SHRINKWRAP_INSIDE: + shrinkwrap_snap_with_side(r_point_co, point_co, hit_co, hit_no, goal_dist, -1, false); + break; + + case MOD_SHRINKWRAP_OUTSIDE: + shrinkwrap_snap_with_side(r_point_co, point_co, hit_co, hit_no, goal_dist, +1, false); + break; + + case MOD_SHRINKWRAP_OUTSIDE_SURFACE: + if (goal_dist != 0) { + shrinkwrap_snap_with_side(r_point_co, point_co, hit_co, hit_no, goal_dist, +1, true); + } + else { + copy_v3_v3(r_point_co, hit_co); + } + break; + + /* Offsets along the normal */ + case MOD_SHRINKWRAP_ABOVE_SURFACE: + if (goal_dist != 0) { + BKE_shrinkwrap_compute_smooth_normal(tree, transform, hit_idx, hit_co, hit_no, tmp); + madd_v3_v3v3fl(r_point_co, hit_co, tmp, goal_dist); + } + else { + copy_v3_v3(r_point_co, hit_co); + } + break; + + default: + printf("Unknown Shrinkwrap surface snap mode: %d\n", mode); + copy_v3_v3(r_point_co, hit_co); + } } static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc) { - BVHTreeNearest nearest = NULL_BVHTreeNearest; - - /* Setup nearest */ - nearest.index = -1; - nearest.dist_sq = FLT_MAX; - - /* Find the nearest vertex */ - ShrinkwrapCalcCBData data = { .calc = calc, .tree = calc->tree, }; - ParallelRangeSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = (calc->numVerts > BKE_MESH_OMP_LIMIT); - settings.userdata_chunk = &nearest; - settings.userdata_chunk_size = sizeof(nearest); - BLI_task_parallel_range(0, calc->numVerts, - &data, - shrinkwrap_calc_nearest_surface_point_cb_ex, - &settings); + BVHTreeNearest nearest = NULL_BVHTreeNearest; + + /* Setup nearest */ + nearest.index = -1; + nearest.dist_sq = FLT_MAX; + + /* Find the nearest vertex */ + ShrinkwrapCalcCBData data = { + .calc = calc, + .tree = calc->tree, + }; + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (calc->numVerts > BKE_MESH_OMP_LIMIT); + settings.userdata_chunk = &nearest; + settings.userdata_chunk_size = sizeof(nearest); + BLI_task_parallel_range( + 0, calc->numVerts, &data, shrinkwrap_calc_nearest_surface_point_cb_ex, &settings); } /* Main shrinkwrap function */ -void shrinkwrapModifier_deform( - ShrinkwrapModifierData *smd, const ModifierEvalContext *ctx, - struct Scene *scene, Object *ob, Mesh *mesh, - MDeformVert *dvert, const int defgrp_index, float (*vertexCos)[3], int numVerts) +void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, + const ModifierEvalContext *ctx, + struct Scene *scene, + Object *ob, + Mesh *mesh, + MDeformVert *dvert, + const int defgrp_index, + float (*vertexCos)[3], + int numVerts) { - DerivedMesh *ss_mesh = NULL; - ShrinkwrapCalcData calc = NULL_ShrinkwrapCalcData; - - /* remove loop dependencies on derived meshes (TODO should this be done elsewhere?) */ - if (smd->target == ob) smd->target = NULL; - if (smd->auxTarget == ob) smd->auxTarget = NULL; - - - /* Configure Shrinkwrap calc data */ - calc.smd = smd; - calc.ob = ob; - calc.numVerts = numVerts; - calc.vertexCos = vertexCos; - calc.dvert = dvert; - calc.vgroup = defgrp_index; - calc.invert_vgroup = (smd->shrinkOpts & MOD_SHRINKWRAP_INVERT_VGROUP) != 0; - - if (smd->target != NULL) { - Object *ob_target = DEG_get_evaluated_object(ctx->depsgraph, smd->target); - calc.target = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob_target, false); - - /* TODO there might be several "bugs" on non-uniform scales matrixs - * because it will no longer be nearest surface, not sphere projection - * because space has been deformed */ - BLI_SPACE_TRANSFORM_SETUP(&calc.local2target, ob, ob_target); - - /* TODO: smd->keepDist is in global units.. must change to local */ - calc.keepDist = smd->keepDist; - } - calc.aux_target = DEG_get_evaluated_object(ctx->depsgraph, smd->auxTarget); - - if (mesh != NULL && smd->shrinkType == MOD_SHRINKWRAP_PROJECT) { - /* Setup arrays to get vertexs positions, normals and deform weights */ - calc.vert = mesh->mvert; - - /* Using vertexs positions/normals as if a subsurface was applied */ - if (smd->subsurfLevels) { - SubsurfModifierData ssmd = {{NULL}}; - ssmd.subdivType = ME_CC_SUBSURF; /* catmull clark */ - ssmd.levels = smd->subsurfLevels; /* levels */ - - /* TODO to be moved to Mesh once we are done with changes in subsurf code. */ - DerivedMesh *dm = CDDM_from_mesh(mesh); - - ss_mesh = subsurf_make_derived_from_derived(dm, &ssmd, scene, NULL, (ob->mode & OB_MODE_EDIT) ? SUBSURF_IN_EDIT_MODE : 0); - - if (ss_mesh) { - calc.vert = ss_mesh->getVertDataArray(ss_mesh, CD_MVERT); - if (calc.vert) { - /* TRICKY: this code assumes subsurface will have the transformed original vertices - * in their original order at the end of the vert array. */ - calc.vert = calc.vert + ss_mesh->getNumVerts(ss_mesh) - dm->getNumVerts(dm); - } - } - - /* Just to make sure we are not leaving any memory behind */ - BLI_assert(ssmd.emCache == NULL); - BLI_assert(ssmd.mCache == NULL); - - dm->release(dm); - } - } - - /* Projecting target defined - lets work! */ - ShrinkwrapTreeData tree; - - if (BKE_shrinkwrap_init_tree(&tree, calc.target, smd->shrinkType, smd->shrinkMode, false)) { - calc.tree = &tree; - - switch (smd->shrinkType) { - case MOD_SHRINKWRAP_NEAREST_SURFACE: - case MOD_SHRINKWRAP_TARGET_PROJECT: - TIMEIT_BENCH(shrinkwrap_calc_nearest_surface_point(&calc), deform_surface); - break; - - case MOD_SHRINKWRAP_PROJECT: - TIMEIT_BENCH(shrinkwrap_calc_normal_projection(&calc), deform_project); - break; - - case MOD_SHRINKWRAP_NEAREST_VERTEX: - TIMEIT_BENCH(shrinkwrap_calc_nearest_vertex(&calc), deform_vertex); - break; - } - - BKE_shrinkwrap_free_tree(&tree); - } - - /* free memory */ - if (ss_mesh) - ss_mesh->release(ss_mesh); + DerivedMesh *ss_mesh = NULL; + ShrinkwrapCalcData calc = NULL_ShrinkwrapCalcData; + + /* remove loop dependencies on derived meshes (TODO should this be done elsewhere?) */ + if (smd->target == ob) + smd->target = NULL; + if (smd->auxTarget == ob) + smd->auxTarget = NULL; + + /* Configure Shrinkwrap calc data */ + calc.smd = smd; + calc.ob = ob; + calc.numVerts = numVerts; + calc.vertexCos = vertexCos; + calc.dvert = dvert; + calc.vgroup = defgrp_index; + calc.invert_vgroup = (smd->shrinkOpts & MOD_SHRINKWRAP_INVERT_VGROUP) != 0; + + if (smd->target != NULL) { + Object *ob_target = DEG_get_evaluated_object(ctx->depsgraph, smd->target); + calc.target = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob_target, false); + + /* TODO there might be several "bugs" on non-uniform scales matrixs + * because it will no longer be nearest surface, not sphere projection + * because space has been deformed */ + BLI_SPACE_TRANSFORM_SETUP(&calc.local2target, ob, ob_target); + + /* TODO: smd->keepDist is in global units.. must change to local */ + calc.keepDist = smd->keepDist; + } + calc.aux_target = DEG_get_evaluated_object(ctx->depsgraph, smd->auxTarget); + + if (mesh != NULL && smd->shrinkType == MOD_SHRINKWRAP_PROJECT) { + /* Setup arrays to get vertexs positions, normals and deform weights */ + calc.vert = mesh->mvert; + + /* Using vertexs positions/normals as if a subsurface was applied */ + if (smd->subsurfLevels) { + SubsurfModifierData ssmd = {{NULL}}; + ssmd.subdivType = ME_CC_SUBSURF; /* catmull clark */ + ssmd.levels = smd->subsurfLevels; /* levels */ + + /* TODO to be moved to Mesh once we are done with changes in subsurf code. */ + DerivedMesh *dm = CDDM_from_mesh(mesh); + + ss_mesh = subsurf_make_derived_from_derived( + dm, &ssmd, scene, NULL, (ob->mode & OB_MODE_EDIT) ? SUBSURF_IN_EDIT_MODE : 0); + + if (ss_mesh) { + calc.vert = ss_mesh->getVertDataArray(ss_mesh, CD_MVERT); + if (calc.vert) { + /* TRICKY: this code assumes subsurface will have the transformed original vertices + * in their original order at the end of the vert array. */ + calc.vert = calc.vert + ss_mesh->getNumVerts(ss_mesh) - dm->getNumVerts(dm); + } + } + + /* Just to make sure we are not leaving any memory behind */ + BLI_assert(ssmd.emCache == NULL); + BLI_assert(ssmd.mCache == NULL); + + dm->release(dm); + } + } + + /* Projecting target defined - lets work! */ + ShrinkwrapTreeData tree; + + if (BKE_shrinkwrap_init_tree(&tree, calc.target, smd->shrinkType, smd->shrinkMode, false)) { + calc.tree = &tree; + + switch (smd->shrinkType) { + case MOD_SHRINKWRAP_NEAREST_SURFACE: + case MOD_SHRINKWRAP_TARGET_PROJECT: + TIMEIT_BENCH(shrinkwrap_calc_nearest_surface_point(&calc), deform_surface); + break; + + case MOD_SHRINKWRAP_PROJECT: + TIMEIT_BENCH(shrinkwrap_calc_normal_projection(&calc), deform_project); + break; + + case MOD_SHRINKWRAP_NEAREST_VERTEX: + TIMEIT_BENCH(shrinkwrap_calc_nearest_vertex(&calc), deform_vertex); + break; + } + + BKE_shrinkwrap_free_tree(&tree); + } + + /* free memory */ + if (ss_mesh) + ss_mesh->release(ss_mesh); } |