static void hook_co_apply(struct HookData_cb *hd, const int j) { float *co = hd->vertexCos[j]; float fac; if (hd->use_falloff) { float len_sq; if (hd->use_uniform) { float co_uniform[3]; mul_v3_m3v3(co_uniform, hd->mat_uniform, co); len_sq = len_squared_v3v3(hd->cent, co_uniform); } else { len_sq = len_squared_v3v3(hd->cent, co); } fac = hook_falloff(hd, len_sq); } else { fac = hd->fac_orig; } if (fac) { if (hd->dvert) { fac *= defvert_find_weight(&hd->dvert[j], hd->defgrp_index); } if (fac) { float co_tmp[3]; mul_v3_m4v3(co_tmp, hd->mat, co); interp_v3_v3v3(co, co, co_tmp, fac); } } }
//Determines the nearest point of the given node BV. Returns the squared distance to that point. static float calc_nearest_point(const float proj[3], BVHNode *node, float *nearest) { int i; const float *bv = node->bv; //nearest on AABB hull for (i=0; i != 3; i++, bv += 2) { if (bv[0] > proj[i]) nearest[i] = bv[0]; else if (bv[1] < proj[i]) nearest[i] = bv[1]; else nearest[i] = proj[i]; } #if 0 //nearest on a general hull copy_v3_v3(nearest, data->co); for (i = data->tree->start_axis; i != data->tree->stop_axis; i++, bv+=2) { float proj = dot_v3v3( nearest, KDOP_AXES[i]); float dl = bv[0] - proj; float du = bv[1] - proj; if (dl > 0) { madd_v3_v3fl(nearest, KDOP_AXES[i], dl); } else if (du < 0) { madd_v3_v3fl(nearest, KDOP_AXES[i], du); } } #endif return len_squared_v3v3(proj, nearest); }
/* Callback to bvh tree nearest point. The tree must have been built using bvhtree_from_mesh_faces. * userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree. */ static void mesh_faces_nearest_point(void *userdata, int index, const float co[3], BVHTreeNearest *nearest) { const BVHTreeFromMesh *data = (BVHTreeFromMesh *) userdata; const MVert *vert = data->vert; const MFace *face = data->face + index; const float *t0, *t1, *t2, *t3; t0 = vert[face->v1].co; t1 = vert[face->v2].co; t2 = vert[face->v3].co; t3 = face->v4 ? vert[face->v4].co : NULL; do { float nearest_tmp[3], dist_sq; closest_on_tri_to_point_v3(nearest_tmp, co, t0, t1, t2); dist_sq = len_squared_v3v3(co, nearest_tmp); if (dist_sq < nearest->dist_sq) { nearest->index = index; nearest->dist_sq = dist_sq; copy_v3_v3(nearest->co, nearest_tmp); normal_tri_v3(nearest->no, t0, t1, t2); } t1 = t2; t2 = t3; t3 = NULL; } while (t2); }
static bool bmbvh_overlap_cb(void *userdata, int index_a, int index_b, int UNUSED(thread)) { struct BMBVHTree_OverlapData *data = userdata; const BMBVHTree *bmtree_a = data->tree_pair[0]; const BMBVHTree *bmtree_b = data->tree_pair[1]; BMLoop **tri_a = bmtree_a->looptris[index_a]; BMLoop **tri_b = bmtree_b->looptris[index_b]; const float *tri_a_co[3] = {tri_a[0]->v->co, tri_a[1]->v->co, tri_a[2]->v->co}; const float *tri_b_co[3] = {tri_b[0]->v->co, tri_b[1]->v->co, tri_b[2]->v->co}; float ix_pair[2][3]; int verts_shared = 0; if (bmtree_a->looptris == bmtree_b->looptris) { if (UNLIKELY(tri_a[0]->f == tri_b[0]->f)) { return false; } verts_shared = ( ELEM(tri_a_co[0], UNPACK3(tri_b_co)) + ELEM(tri_a_co[1], UNPACK3(tri_b_co)) + ELEM(tri_a_co[2], UNPACK3(tri_b_co))); /* if 2 points are shared, bail out */ if (verts_shared >= 2) { return false; } } return (isect_tri_tri_epsilon_v3(UNPACK3(tri_a_co), UNPACK3(tri_b_co), ix_pair[0], ix_pair[1], data->epsilon) && /* if we share a vertex, check the intersection isn't a 'point' */ ((verts_shared == 0) || (len_squared_v3v3(ix_pair[0], ix_pair[1]) > data->epsilon))); }
/* copy of function above (warning, should de-duplicate with editmesh_bvh.c) */ static void editmesh_faces_nearest_point(void *userdata, int index, const float co[3], BVHTreeNearest *nearest) { const BVHTreeFromMesh *data = (BVHTreeFromMesh *) userdata; BMEditMesh *em = data->em_evil; const BMLoop **ltri = (const BMLoop **)em->looptris[index]; const float *t0, *t1, *t2; t0 = ltri[0]->v->co; t1 = ltri[1]->v->co; t2 = ltri[2]->v->co; { float nearest_tmp[3], dist_sq; closest_on_tri_to_point_v3(nearest_tmp, co, t0, t1, t2); dist_sq = len_squared_v3v3(co, nearest_tmp); if (dist_sq < nearest->dist_sq) { nearest->index = index; nearest->dist_sq = dist_sq; copy_v3_v3(nearest->co, nearest_tmp); normal_tri_v3(nearest->no, t0, t1, t2); } } }
/** * A version of #BLI_kdtree_range_search which runs a callback * instead of allocating an array. * * \param search_cb: Called for every node found in \a range, false return value performs an early exit. * * \note the order of calls isn't sorted based on distance. */ void BLI_kdtree_range_search_cb( const KDTree *tree, const float co[3], float range, bool (*search_cb)(void *user_data, int index, const float co[3], float dist_sq), void *user_data) { const KDTreeNode *nodes = tree->nodes; uint *stack, defaultstack[KD_STACK_INIT]; float range_sq = range * range, dist_sq; uint totstack, cur = 0; #ifdef DEBUG BLI_assert(tree->is_balanced == true); #endif if (UNLIKELY(tree->root == KD_NODE_UNSET)) return; stack = defaultstack; totstack = KD_STACK_INIT; stack[cur++] = tree->root; while (cur--) { const KDTreeNode *node = &nodes[stack[cur]]; if (co[node->d] + range < node->co[node->d]) { if (node->left != KD_NODE_UNSET) stack[cur++] = node->left; } else if (co[node->d] - range > node->co[node->d]) { if (node->right != KD_NODE_UNSET) stack[cur++] = node->right; } else { dist_sq = len_squared_v3v3(node->co, co); if (dist_sq <= range_sq) { if (search_cb(user_data, node->index, node->co, dist_sq) == false) { goto finally; } } if (node->left != KD_NODE_UNSET) stack[cur++] = node->left; if (node->right != KD_NODE_UNSET) stack[cur++] = node->right; } if (UNLIKELY(cur + 3 > totstack)) { stack = realloc_nodes(stack, &totstack, defaultstack != stack); } } finally: if (stack != defaultstack) MEM_freeN(stack); }
void BLI_removeDoubleNodes(BGraph *graph, float limit) { const float limit_sq = limit * limit; BNode *node_src, *node_replaced; for (node_src = graph->nodes.first; node_src; node_src = node_src->next) { for (node_replaced = graph->nodes.first; node_replaced; node_replaced = node_replaced->next) { if (node_replaced != node_src && len_squared_v3v3(node_replaced->p, node_src->p) <= limit_sq) { BLI_replaceNode(graph, node_src, node_replaced); } } } }
static float hook_falloff(float *co_1, float *co_2, const float falloff_squared, float fac) { if(falloff_squared) { float len_squared = len_squared_v3v3(co_1, co_2); if(len_squared > falloff_squared) { return 0.0f; } else if(len_squared > 0.0) { return fac * (1.0 - (len_squared / falloff_squared)); } } return fac; }
BNode *BLI_FindNodeByPosition(BGraph *graph, const float p[3], const float limit) { const float limit_sq = limit * limit; BNode *closest_node = NULL, *node; float min_distance = 0.0f; for (node = graph->nodes.first; node; node = node->next) { float distance = len_squared_v3v3(p, node->p); if (distance <= limit_sq && (closest_node == NULL || distance < min_distance)) { closest_node = node; min_distance = distance; } } return closest_node; }
static void testAxialSymmetry(BGraph *graph, BNode *root_node, BNode *node1, BNode *node2, BArc *arc1, BArc *arc2, float axis[3], float limit, int group) { const float limit_sq = limit * limit; float nor[3], vec[3], p[3]; sub_v3_v3v3(p, node1->p, root_node->p); cross_v3_v3v3(nor, p, axis); sub_v3_v3v3(p, root_node->p, node2->p); cross_v3_v3v3(vec, p, axis); add_v3_v3(vec, nor); cross_v3_v3v3(nor, vec, axis); if (fabsf(nor[0]) > fabsf(nor[1]) && fabsf(nor[0]) > fabsf(nor[2]) && nor[0] < 0) { negate_v3(nor); } else if (fabsf(nor[1]) > fabsf(nor[0]) && fabsf(nor[1]) > fabsf(nor[2]) && nor[1] < 0) { negate_v3(nor); } else if (fabsf(nor[2]) > fabsf(nor[1]) && fabsf(nor[2]) > fabsf(nor[0]) && nor[2] < 0) { negate_v3(nor); } /* mirror node2 along axis */ copy_v3_v3(p, node2->p); BLI_mirrorAlongAxis(p, root_node->p, nor); /* check if it's within limit before continuing */ if (len_squared_v3v3(node1->p, p) <= limit_sq) { /* mark node as symmetric physically */ copy_v3_v3(root_node->symmetry_axis, nor); root_node->symmetry_flag |= SYM_PHYSICAL; root_node->symmetry_flag |= SYM_AXIAL; /* flag side on arcs */ flagAxialSymmetry(root_node, node1, arc1, group); flagAxialSymmetry(root_node, node2, arc2, group); if (graph->axial_symmetry) { graph->axial_symmetry(root_node, node1, node2, arc1, arc2); } } else { /* NOT SYMMETRIC */ } }
static void bmbvh_find_face_closest_cb(void *userdata, int index, const float co[3], BVHTreeNearest *hit) { struct FaceSearchUserData *bmcb_data = userdata; const BMLoop **ltri = bmcb_data->looptris[index]; const float dist_max_sq = bmcb_data->dist_max_sq; const float *tri_cos[3]; bmbvh_tri_from_face(tri_cos, ltri, bmcb_data->cos_cage); float co_close[3]; closest_on_tri_to_point_v3(co_close, co, UNPACK3(tri_cos)); const float dist_sq = len_squared_v3v3(co, co_close); if (dist_sq < hit->dist_sq && dist_sq < dist_max_sq) { /* XXX, normal ignores cage */ copy_v3_v3(hit->no, ltri[0]->f->no); hit->dist_sq = dist_sq; hit->index = index; } }
/* Callback to bvh tree raycast. The tree must have been built using bvhtree_from_mesh_edges. * userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree. */ static void mesh_edges_spherecast(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit) { const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata; const MVert *vert = data->vert; const MEdge *edge = &data->edge[index]; const float radius_sq = SQUARE(data->sphere_radius); float dist; const float *v1, *v2, *r1; float r2[3], i1[3], i2[3]; v1 = vert[edge->v1].co; v2 = vert[edge->v2].co; /* In case we get a zero-length edge, handle it as a point! */ if (equals_v3v3(v1, v2)) { mesh_verts_spherecast_do(data, index, v1, ray, hit); return; } r1 = ray->origin; add_v3_v3v3(r2, r1, ray->direction); if (isect_line_line_v3(v1, v2, r1, r2, i1, i2)) { /* No hit if intersection point is 'behind' the origin of the ray, or too far away from it. */ if ((dot_v3v3v3(r1, i2, r2) >= 0.0f) && ((dist = len_v3v3(r1, i2)) < hit->dist)) { const float e_fac = line_point_factor_v3(i1, v1, v2); if (e_fac < 0.0f) { copy_v3_v3(i1, v1); } else if (e_fac > 1.0f) { copy_v3_v3(i1, v2); } /* Ensure ray is really close enough from edge! */ if (len_squared_v3v3(i1, i2) <= radius_sq) { hit->index = index; hit->dist = dist; copy_v3_v3(hit->co, i2); } } } }
/* Callback to bvh tree nearest point. The tree must have been built using bvhtree_from_mesh_edges. * userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree. */ static void mesh_edges_nearest_point(void *userdata, int index, const float co[3], BVHTreeNearest *nearest) { const BVHTreeFromMesh *data = (BVHTreeFromMesh *) userdata; const MVert *vert = data->vert; const MEdge *edge = data->edge + index; float nearest_tmp[3], dist_sq; const float *t0, *t1; t0 = vert[edge->v1].co; t1 = vert[edge->v2].co; closest_to_line_segment_v3(nearest_tmp, co, t0, t1); dist_sq = len_squared_v3v3(nearest_tmp, co); if (dist_sq < nearest->dist_sq) { nearest->index = index; nearest->dist_sq = dist_sq; copy_v3_v3(nearest->co, nearest_tmp); sub_v3_v3v3(nearest->no, t0, t1); normalize_v3(nearest->no); } }
/* copy of function above */ static void mesh_looptri_nearest_point(void *userdata, int index, const float co[3], BVHTreeNearest *nearest) { const BVHTreeFromMesh *data = (BVHTreeFromMesh *) userdata; const MVert *vert = data->vert; const MLoopTri *lt = &data->looptri[index]; const float *vtri_co[3] = { vert[data->loop[lt->tri[0]].v].co, vert[data->loop[lt->tri[1]].v].co, vert[data->loop[lt->tri[2]].v].co, }; float nearest_tmp[3], dist_sq; closest_on_tri_to_point_v3(nearest_tmp, co, UNPACK3(vtri_co)); dist_sq = len_squared_v3v3(co, nearest_tmp); if (dist_sq < nearest->dist_sq) { nearest->index = index; nearest->dist_sq = dist_sq; copy_v3_v3(nearest->co, nearest_tmp); normal_tri_v3(nearest->no, UNPACK3(vtri_co)); } }
static void edge_verts_sort(const float co[3], struct LinkBase *v_ls_base) { /* not optimal but list will be typically < 5 */ unsigned int i; struct vert_sort_t *vert_sort = BLI_array_alloca(vert_sort, v_ls_base->list_len); LinkNode *node; BLI_assert(v_ls_base->list_len > 1); for (i = 0, node = v_ls_base->list; i < v_ls_base->list_len; i++, node = node->next) { BMVert *v = node->link; BLI_assert(v->head.htype == BM_VERT); vert_sort[i].val = len_squared_v3v3(co, v->co); vert_sort[i].v = v; } qsort(vert_sort, v_ls_base->list_len, sizeof(*vert_sort), BLI_sortutil_cmp_float); for (i = 0, node = v_ls_base->list; i < v_ls_base->list_len; i++, node = node->next) { node->link = vert_sort[i].v; } }
/** * 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; } } } }
static void bmbvh_find_vert_closest_cb(void *userdata, int index, const float co[3], BVHTreeNearest *hit) { struct VertSearchUserData *bmcb_data = userdata; const BMLoop **ltri = bmcb_data->looptris[index]; const float dist_max_sq = bmcb_data->dist_max_sq; int i; const float *tri_cos[3]; bmbvh_tri_from_face(tri_cos, ltri, bmcb_data->cos_cage); for (i = 0; i < 3; i++) { const float dist_sq = len_squared_v3v3(co, tri_cos[i]); if (dist_sq < hit->dist_sq && dist_sq < dist_max_sq) { copy_v3_v3(hit->co, tri_cos[i]); /* XXX, normal ignores cage */ copy_v3_v3(hit->no, ltri[i]->v->no); hit->dist_sq = dist_sq; hit->index = index; bmcb_data->index_tri = i; } } }
// Callback to bvh tree nearest point. The tree must bust have been built using bvhtree_from_mesh_edges. // userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree. static void mesh_edges_nearest_point(void *userdata, int index, const float *co, BVHTreeNearest *nearest) { const BVHTreeFromMesh *data = (BVHTreeFromMesh*) userdata; MVert *vert = data->vert; MEdge *edge = data->edge + index; float nearest_tmp[3], dist; float *t0, *t1; t0 = vert[ edge->v1 ].co; t1 = vert[ edge->v2 ].co; // NOTE: casts to "float*" here are due to co being "const float*" closest_to_line_segment_v3(nearest_tmp, (float*)co, t0, t1); dist = len_squared_v3v3(nearest_tmp, (float*)co); if(dist < nearest->dist) { nearest->index = index; nearest->dist = dist; VECCOPY(nearest->co, nearest_tmp); sub_v3_v3v3(nearest->no, t0, t1); normalize_v3(nearest->no); } }
static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for_render) { int i; /* Options about projection direction */ const float proj_limit_squared = calc->smd->projLimit * calc->smd->projLimit; 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; BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh; /* auxiliary target */ DerivedMesh *auxMesh = NULL; BVHTreeFromMesh auxData = NULL_BVHTreeFromMesh; SpaceTransform local2aux; /* If the user doesn't allows to project in any direction of projection axis * then theres 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->smd->auxTarget) { auxMesh = object_get_derived_final(calc->smd->auxTarget, for_render); if (!auxMesh) return; SPACE_TRANSFORM_SETUP(&local2aux, calc->ob, calc->smd->auxTarget); } /* After sucessufuly build the trees, start projection vertexs */ if (bvhtree_from_mesh_faces(&treeData, calc->target, 0.0, 4, 6) && (auxMesh == NULL || bvhtree_from_mesh_faces(&auxData, auxMesh, 0.0, 4, 6))) { #ifndef __APPLE__ #pragma omp parallel for private(i, hit) schedule(static) #endif for (i = 0; i < calc->numVerts; ++i) { float *co = calc->vertexCos[i]; float tmp_co[3], tmp_no[3]; const float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup); if (weight == 0.0f) { continue; } if (calc->vert) { /* calc->vert contains verts from derivedMesh */ /* this coordinated are deformed by vertexCos only for normal projection (to get correct normals) */ /* for other cases calc->varts contains undeformed coordinates and vertexCos should be used */ if (calc->smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL) { 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); } } else { copy_v3_v3(tmp_co, co); copy_v3_v3(tmp_no, proj_axis); } hit.index = -1; hit.dist = 10000.0f; /* TODO: we should use FLT_MAX here, but sweepsphere code isn't prepared for that */ /* Project over positive direction of axis */ if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR) { if (auxData.tree) { BKE_shrinkwrap_project_normal(0, tmp_co, tmp_no, &local2aux, auxData.tree, &hit, auxData.raycast_callback, &auxData); } BKE_shrinkwrap_project_normal(calc->smd->shrinkOpts, tmp_co, tmp_no, &calc->local2target, treeData.tree, &hit, treeData.raycast_callback, &treeData); } /* 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); if (auxData.tree) { BKE_shrinkwrap_project_normal(0, tmp_co, inv_no, &local2aux, auxData.tree, &hit, auxData.raycast_callback, &auxData); } BKE_shrinkwrap_project_normal(calc->smd->shrinkOpts, tmp_co, inv_no, &calc->local2target, treeData.tree, &hit, treeData.raycast_callback, &treeData); } /* 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 (len_squared_v3v3(hit.co, co) > proj_limit_squared) { hit.index = -1; } } if (hit.index != -1) { madd_v3_v3v3fl(hit.co, hit.co, tmp_no, calc->keepDist); interp_v3_v3v3(co, co, hit.co, weight); } } } /* free data structures */ free_bvhtree_from_mesh(&treeData); free_bvhtree_from_mesh(&auxData); }
/* computes where the cloth would be if it were subject to perfectly stiff edges * (edge distance constraints) in a lagrangian solver. then add forces to help * guide the implicit solver to that state. this function is called after * collisions*/ static int UNUSED_FUNCTION(cloth_calc_helper_forces)(Object *UNUSED(ob), ClothModifierData *clmd, float (*initial_cos)[3], float UNUSED(step), float dt) { Cloth *cloth= clmd->clothObject; float (*cos)[3] = (float (*)[3])MEM_callocN(sizeof(float[3]) * cloth->mvert_num, "cos cloth_calc_helper_forces"); float *masses = (float *)MEM_callocN(sizeof(float) * cloth->mvert_num, "cos cloth_calc_helper_forces"); LinkNode *node; ClothSpring *spring; ClothVertex *cv; int i, steps; cv = cloth->verts; for (i = 0; i < cloth->mvert_num; i++, cv++) { copy_v3_v3(cos[i], cv->tx); if (cv->goal == 1.0f || len_squared_v3v3(initial_cos[i], cv->tx) != 0.0f) { masses[i] = 1e+10; } else { masses[i] = cv->mass; } } steps = 55; for (i=0; i<steps; i++) { for (node=cloth->springs; node; node=node->next) { /* ClothVertex *cv1, *cv2; */ /* UNUSED */ int v1, v2; float len, c, l, vec[3]; spring = (ClothSpring *)node->link; if (spring->type != CLOTH_SPRING_TYPE_STRUCTURAL && spring->type != CLOTH_SPRING_TYPE_SHEAR) continue; v1 = spring->ij; v2 = spring->kl; /* cv1 = cloth->verts + v1; */ /* UNUSED */ /* cv2 = cloth->verts + v2; */ /* UNUSED */ len = len_v3v3(cos[v1], cos[v2]); sub_v3_v3v3(vec, cos[v1], cos[v2]); normalize_v3(vec); c = (len - spring->restlen); if (c == 0.0f) continue; l = c / ((1.0f / masses[v1]) + (1.0f / masses[v2])); mul_v3_fl(vec, -(1.0f / masses[v1]) * l); add_v3_v3(cos[v1], vec); sub_v3_v3v3(vec, cos[v2], cos[v1]); normalize_v3(vec); mul_v3_fl(vec, -(1.0f / masses[v2]) * l); add_v3_v3(cos[v2], vec); } } cv = cloth->verts; for (i = 0; i < cloth->mvert_num; i++, cv++) { float vec[3]; /*compute forces*/ sub_v3_v3v3(vec, cos[i], cv->tx); mul_v3_fl(vec, cv->mass*dt*20.0f); add_v3_v3(cv->tv, vec); //copy_v3_v3(cv->tx, cos[i]); } MEM_freeN(cos); MEM_freeN(masses); return 1; }
/* bone adding between selected joints */ static int armature_fill_bones_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); bArmature *arm = (obedit) ? obedit->data : NULL; Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); ListBase points = {NULL, NULL}; EditBone *newbone = NULL; int count; /* sanity checks */ if (ELEM(NULL, obedit, arm)) return OPERATOR_CANCELLED; /* loop over all bones, and only consider if visible */ CTX_DATA_BEGIN(C, EditBone *, ebone, visible_bones) { if (!(ebone->flag & BONE_CONNECTED) && (ebone->flag & BONE_ROOTSEL)) fill_add_joint(ebone, 0, &points); if (ebone->flag & BONE_TIPSEL) fill_add_joint(ebone, 1, &points); } CTX_DATA_END; /* the number of joints determines how we fill: * 1) between joint and cursor (joint=head, cursor=tail) * 2) between the two joints (order is dependent on active-bone/hierarchy) * 3+) error (a smarter method involving finding chains needs to be worked out */ count = BLI_listbase_count(&points); if (count == 0) { BKE_report(op->reports, RPT_ERROR, "No joints selected"); return OPERATOR_CANCELLED; } else if (count == 1) { EditBonePoint *ebp; float curs[3]; /* Get Points - selected joint */ ebp = points.first; /* Get points - cursor (tail) */ invert_m4_m4(obedit->imat, obedit->obmat); mul_v3_m4v3(curs, obedit->imat, ED_view3d_cursor3d_get(scene, v3d)); /* Create a bone */ newbone = add_points_bone(obedit, ebp->vec, curs); } else if (count == 2) { EditBonePoint *ebp_a, *ebp_b; float head[3], tail[3]; short headtail = 0; /* check that the points don't belong to the same bone */ ebp_a = (EditBonePoint *)points.first; ebp_b = ebp_a->next; if (((ebp_a->head_owner == ebp_b->tail_owner) && (ebp_a->head_owner != NULL)) || ((ebp_a->tail_owner == ebp_b->head_owner) && (ebp_a->tail_owner != NULL))) { BKE_report(op->reports, RPT_ERROR, "Same bone selected..."); BLI_freelistN(&points); return OPERATOR_CANCELLED; } /* find which one should be the 'head' */ if ((ebp_a->head_owner && ebp_b->head_owner) || (ebp_a->tail_owner && ebp_b->tail_owner)) { /* use active, nice predictable */ if (arm->act_edbone && ELEM(arm->act_edbone, ebp_a->head_owner, ebp_a->tail_owner)) { headtail = 1; } else if (arm->act_edbone && ELEM(arm->act_edbone, ebp_b->head_owner, ebp_b->tail_owner)) { headtail = 2; } else { /* rule: whichever one is closer to 3d-cursor */ float curs[3]; float dist_sq_a, dist_sq_b; /* get cursor location */ invert_m4_m4(obedit->imat, obedit->obmat); mul_v3_m4v3(curs, obedit->imat, ED_view3d_cursor3d_get(scene, v3d)); /* get distances */ dist_sq_a = len_squared_v3v3(ebp_a->vec, curs); dist_sq_b = len_squared_v3v3(ebp_b->vec, curs); /* compare distances - closer one therefore acts as direction for bone to go */ headtail = (dist_sq_a < dist_sq_b) ? 2 : 1; } } else if (ebp_a->head_owner) { headtail = 1; } else if (ebp_b->head_owner) { headtail = 2; } /* assign head/tail combinations */ if (headtail == 2) { copy_v3_v3(head, ebp_a->vec); copy_v3_v3(tail, ebp_b->vec); } else if (headtail == 1) { copy_v3_v3(head, ebp_b->vec); copy_v3_v3(tail, ebp_a->vec); } /* add new bone and parent it to the appropriate end */ if (headtail) { newbone = add_points_bone(obedit, head, tail); /* do parenting (will need to set connected flag too) */ if (headtail == 2) { /* ebp tail or head - tail gets priority */ if (ebp_a->tail_owner) newbone->parent = ebp_a->tail_owner; else newbone->parent = ebp_a->head_owner; } else { /* ebp_b tail or head - tail gets priority */ if (ebp_b->tail_owner) newbone->parent = ebp_b->tail_owner; else newbone->parent = ebp_b->head_owner; } /* don't set for bone connecting two head points of bones */ if (ebp_a->tail_owner || ebp_b->tail_owner) { newbone->flag |= BONE_CONNECTED; } } } else { /* FIXME.. figure out a method for multiple bones */ BKE_reportf(op->reports, RPT_ERROR, "Too many points selected: %d", count); BLI_freelistN(&points); return OPERATOR_CANCELLED; } if (newbone) { ED_armature_edit_deselect_all(obedit); arm->act_edbone = newbone; newbone->flag |= BONE_TIPSEL; } /* updates */ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit); /* free points */ BLI_freelistN(&points); return OPERATOR_FINISHED; }
/* put EditMode back in Object */ void ED_armature_from_edit(bArmature *arm) { EditBone *eBone, *neBone; Bone *newBone; Object *obt; /* armature bones */ BKE_armature_bonelist_free(&arm->bonebase); arm->act_bone = NULL; /* remove zero sized bones, this gives unstable restposes */ for (eBone = arm->edbo->first; eBone; eBone = neBone) { float len_sq = len_squared_v3v3(eBone->head, eBone->tail); neBone = eBone->next; if (len_sq <= SQUARE(0.000001f)) { /* FLT_EPSILON is too large? */ EditBone *fBone; /* Find any bones that refer to this bone */ for (fBone = arm->edbo->first; fBone; fBone = fBone->next) { if (fBone->parent == eBone) fBone->parent = eBone->parent; } if (G.debug & G_DEBUG) printf("Warning: removed zero sized bone: %s\n", eBone->name); bone_free(arm, eBone); } } /* Copy the bones from the editData into the armature */ for (eBone = arm->edbo->first; eBone; eBone = eBone->next) { newBone = MEM_callocN(sizeof(Bone), "bone"); eBone->temp.bone = newBone; /* Associate the real Bones with the EditBones */ BLI_strncpy(newBone->name, eBone->name, sizeof(newBone->name)); copy_v3_v3(newBone->arm_head, eBone->head); copy_v3_v3(newBone->arm_tail, eBone->tail); newBone->arm_roll = eBone->roll; newBone->flag = eBone->flag; if (eBone == arm->act_edbone) { /* don't change active selection, this messes up separate which uses * editmode toggle and can separate active bone which is de-selected originally */ /* newBone->flag |= BONE_SELECTED; */ /* important, editbones can be active with only 1 point selected */ arm->act_bone = newBone; } newBone->roll = 0.0f; newBone->weight = eBone->weight; newBone->dist = eBone->dist; newBone->xwidth = eBone->xwidth; newBone->zwidth = eBone->zwidth; newBone->rad_head = eBone->rad_head; newBone->rad_tail = eBone->rad_tail; newBone->segments = eBone->segments; newBone->layer = eBone->layer; /* Bendy-Bone parameters */ newBone->roll1 = eBone->roll1; newBone->roll2 = eBone->roll2; newBone->curveInX = eBone->curveInX; newBone->curveInY = eBone->curveInY; newBone->curveOutX = eBone->curveOutX; newBone->curveOutY = eBone->curveOutY; newBone->ease1 = eBone->ease1; newBone->ease2 = eBone->ease2; newBone->scaleIn = eBone->scaleIn; newBone->scaleOut = eBone->scaleOut; if (eBone->prop) newBone->prop = IDP_CopyProperty(eBone->prop); } /* Fix parenting in a separate pass to ensure ebone->bone connections are valid at this point. * Do not set bone->head/tail here anymore, using EditBone data for that is not OK since our later fiddling * with parent's arm_mat (for roll conversion) may have some small but visible impact on locations (T46010). */ for (eBone = arm->edbo->first; eBone; eBone = eBone->next) { newBone = eBone->temp.bone; if (eBone->parent) { newBone->parent = eBone->parent->temp.bone; BLI_addtail(&newBone->parent->childbase, newBone); } /* ...otherwise add this bone to the armature's bonebase */ else { BLI_addtail(&arm->bonebase, newBone); } } /* Finalize definition of restpose data (roll, bone_mat, arm_mat, head/tail...). */ armature_finalize_restpose(&arm->bonebase, arm->edbo); /* so all users of this armature should get rebuilt */ for (obt = G.main->object.first; obt; obt = obt->id.next) { if (obt->data == arm) { BKE_pose_rebuild(obt, arm); } } DAG_id_tag_update(&arm->id, 0); }
static void warpModifier_do(WarpModifierData *wmd, const ModifierEvalContext *ctx, Mesh *mesh, float (*vertexCos)[3], int numVerts) { Object *ob = ctx->object; float obinv[4][4]; float mat_from[4][4]; float mat_from_inv[4][4]; float mat_to[4][4]; float mat_unit[4][4]; float mat_final[4][4]; float tmat[4][4]; const float falloff_radius_sq = SQUARE(wmd->falloff_radius); float strength = wmd->strength; float fac = 1.0f, weight; int i; int defgrp_index; MDeformVert *dvert, *dv = NULL; float(*tex_co)[3] = NULL; if (!(wmd->object_from && wmd->object_to)) { return; } MOD_get_vgroup(ob, mesh, wmd->defgrp_name, &dvert, &defgrp_index); if (dvert == NULL) { defgrp_index = -1; } if (wmd->curfalloff == NULL) { /* should never happen, but bad lib linking could cause it */ wmd->curfalloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); } if (wmd->curfalloff) { curvemapping_initialize(wmd->curfalloff); } invert_m4_m4(obinv, ob->obmat); mul_m4_m4m4(mat_from, obinv, wmd->object_from->obmat); mul_m4_m4m4(mat_to, obinv, wmd->object_to->obmat); invert_m4_m4(tmat, mat_from); // swap? mul_m4_m4m4(mat_final, tmat, mat_to); invert_m4_m4(mat_from_inv, mat_from); unit_m4(mat_unit); if (strength < 0.0f) { float loc[3]; strength = -strength; /* inverted location is not useful, just use the negative */ copy_v3_v3(loc, mat_final[3]); invert_m4(mat_final); negate_v3_v3(mat_final[3], loc); } weight = strength; Tex *tex_target = wmd->texture; if (mesh != NULL && tex_target != NULL) { tex_co = MEM_malloc_arrayN(numVerts, sizeof(*tex_co), "warpModifier_do tex_co"); MOD_get_texture_coords((MappingInfoModifierData *)wmd, ctx, ob, mesh, vertexCos, tex_co); MOD_init_texture((MappingInfoModifierData *)wmd, ctx); } for (i = 0; i < numVerts; i++) { float *co = vertexCos[i]; if (wmd->falloff_type == eWarp_Falloff_None || ((fac = len_squared_v3v3(co, mat_from[3])) < falloff_radius_sq && (fac = (wmd->falloff_radius - sqrtf(fac)) / wmd->falloff_radius))) { /* skip if no vert group found */ if (defgrp_index != -1) { dv = &dvert[i]; weight = defvert_find_weight(dv, defgrp_index) * strength; if (weight <= 0.0f) { continue; } } /* closely match PROP_SMOOTH and similar */ switch (wmd->falloff_type) { case eWarp_Falloff_None: fac = 1.0f; break; case eWarp_Falloff_Curve: fac = curvemapping_evaluateF(wmd->curfalloff, 0, fac); break; case eWarp_Falloff_Sharp: fac = fac * fac; break; case eWarp_Falloff_Smooth: fac = 3.0f * fac * fac - 2.0f * fac * fac * fac; break; case eWarp_Falloff_Root: fac = sqrtf(fac); break; case eWarp_Falloff_Linear: /* pass */ break; case eWarp_Falloff_Const: fac = 1.0f; break; case eWarp_Falloff_Sphere: fac = sqrtf(2 * fac - fac * fac); break; case eWarp_Falloff_InvSquare: fac = fac * (2.0f - fac); break; } fac *= weight; if (tex_co) { struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); TexResult texres; texres.nor = NULL; BKE_texture_get_value(scene, tex_target, tex_co[i], &texres, false); fac *= texres.tin; } if (fac != 0.0f) { /* into the 'from' objects space */ mul_m4_v3(mat_from_inv, co); if (fac == 1.0f) { mul_m4_v3(mat_final, co); } else { if (wmd->flag & MOD_WARP_VOLUME_PRESERVE) { /* interpolate the matrix for nicer locations */ blend_m4_m4m4(tmat, mat_unit, mat_final, fac); mul_m4_v3(tmat, co); } else { float tvec[3]; mul_v3_m4v3(tvec, mat_final, co); interp_v3_v3v3(co, co, tvec, fac); } } /* out of the 'from' objects space */ mul_m4_v3(mat_from, co); } } } if (tex_co) { MEM_freeN(tex_co); } }
static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd, Object *ob, DerivedMesh *dm, int axis) { const float tolerance_sq = mmd->tolerance * mmd->tolerance; const int do_vtargetmap = !(mmd->flag & MOD_MIR_NO_MERGE); int is_vtargetmap = FALSE; /* true when it should be used */ DerivedMesh *result; const int maxVerts = dm->getNumVerts(dm); const int maxEdges = dm->getNumEdges(dm); const int maxLoops = dm->getNumLoops(dm); const int maxPolys = dm->getNumPolys(dm); MVert *mv, *mv_prev; MEdge *me; MLoop *ml; MPoly *mp; float mtx[4][4]; int i, j; int a, totshape; int *vtargetmap = NULL, *vtmap_a = NULL, *vtmap_b = NULL; /* mtx is the mirror transformation */ unit_m4(mtx); mtx[axis][axis] = -1.0f; if (mmd->mirror_ob) { float tmp[4][4]; float itmp[4][4]; /* tmp is a transform from coords relative to the object's own origin, * to coords relative to the mirror object origin */ invert_m4_m4(tmp, mmd->mirror_ob->obmat); mult_m4_m4m4(tmp, tmp, ob->obmat); /* itmp is the reverse transform back to origin-relative coordinates */ invert_m4_m4(itmp, tmp); /* combine matrices to get a single matrix that translates coordinates into * mirror-object-relative space, does the mirror, and translates back to * origin-relative space */ mult_m4_m4m4(mtx, mtx, tmp); mult_m4_m4m4(mtx, itmp, mtx); } result = CDDM_from_template(dm, maxVerts * 2, maxEdges * 2, 0, maxLoops * 2, maxPolys * 2); /*copy customdata to original geometry*/ DM_copy_vert_data(dm, result, 0, 0, maxVerts); DM_copy_edge_data(dm, result, 0, 0, maxEdges); DM_copy_loop_data(dm, result, 0, 0, maxLoops); DM_copy_poly_data(dm, result, 0, 0, maxPolys); /* subsurf for eg wont have mesh data in the */ /* now add mvert/medge/mface layers */ if (!CustomData_has_layer(&dm->vertData, CD_MVERT)) { dm->copyVertArray(dm, CDDM_get_verts(result)); } if (!CustomData_has_layer(&dm->edgeData, CD_MEDGE)) { dm->copyEdgeArray(dm, CDDM_get_edges(result)); } if (!CustomData_has_layer(&dm->polyData, CD_MPOLY)) { dm->copyLoopArray(dm, CDDM_get_loops(result)); dm->copyPolyArray(dm, CDDM_get_polys(result)); } /* copy customdata to new geometry, * copy from its self because this data may have been created in the checks above */ DM_copy_vert_data(result, result, 0, maxVerts, maxVerts); DM_copy_edge_data(result, result, 0, maxEdges, maxEdges); /* loops are copied later */ DM_copy_poly_data(result, result, 0, maxPolys, maxPolys); if (do_vtargetmap) { /* second half is filled with -1 */ vtargetmap = MEM_mallocN(sizeof(int) * maxVerts * 2, "MOD_mirror tarmap"); vtmap_a = vtargetmap; vtmap_b = vtargetmap + maxVerts; } /* mirror vertex coordinates */ mv_prev = CDDM_get_verts(result); mv = mv_prev + maxVerts; for (i = 0; i < maxVerts; i++, mv++, mv_prev++) { mul_m4_v3(mtx, mv->co); if (do_vtargetmap) { /* compare location of the original and mirrored vertex, to see if they * should be mapped for merging */ if (UNLIKELY(len_squared_v3v3(mv_prev->co, mv->co) < tolerance_sq)) { *vtmap_a = maxVerts + i; is_vtargetmap = TRUE; } else { *vtmap_a = -1; } *vtmap_b = -1; /* fill here to avoid 2x loops */ vtmap_a++; vtmap_b++; } } /* handle shape keys */ totshape = CustomData_number_of_layers(&result->vertData, CD_SHAPEKEY); for (a = 0; a < totshape; a++) { float (*cos)[3] = CustomData_get_layer_n(&result->vertData, CD_SHAPEKEY, a); for (i = maxVerts; i < result->numVertData; i++) { mul_m4_v3(mtx, cos[i]); } } /* adjust mirrored edge vertex indices */ me = CDDM_get_edges(result) + maxEdges; for (i = 0; i < maxEdges; i++, me++) { me->v1 += maxVerts; me->v2 += maxVerts; } /* adjust mirrored poly loopstart indices, and reverse loop order (normals) */ mp = CDDM_get_polys(result) + maxPolys; ml = CDDM_get_loops(result); for (i = 0; i < maxPolys; i++, mp++) { MLoop *ml2; int e; /* reverse the loop, but we keep the first vertex in the face the same, * to ensure that quads are split the same way as on the other side */ DM_copy_loop_data(result, result, mp->loopstart, mp->loopstart + maxLoops, 1); for (j = 1; j < mp->totloop; j++) DM_copy_loop_data(result, result, mp->loopstart + j, mp->loopstart + maxLoops + mp->totloop - j, 1); ml2 = ml + mp->loopstart + maxLoops; e = ml2[0].e; for (j = 0; j < mp->totloop - 1; j++) { ml2[j].e = ml2[j + 1].e; } ml2[mp->totloop - 1].e = e; mp->loopstart += maxLoops; } /* adjust mirrored loop vertex and edge indices */ ml = CDDM_get_loops(result) + maxLoops; for (i = 0; i < maxLoops; i++, ml++) { ml->v += maxVerts; ml->e += maxEdges; } /* handle uvs, * let tessface recalc handle updating the MTFace data */ if (mmd->flag & (MOD_MIR_MIRROR_U | MOD_MIR_MIRROR_V)) { const int do_mirr_u = (mmd->flag & MOD_MIR_MIRROR_U) != 0; const int do_mirr_v = (mmd->flag & MOD_MIR_MIRROR_V) != 0; const int totuv = CustomData_number_of_layers(&result->loopData, CD_MLOOPUV); for (a = 0; a < totuv; a++) { MLoopUV *dmloopuv = CustomData_get_layer_n(&result->loopData, CD_MLOOPUV, a); int j = maxLoops; dmloopuv += j; /* second set of loops only */ for (; j-- > 0; dmloopuv++) { if (do_mirr_u) dmloopuv->uv[0] = 1.0f - dmloopuv->uv[0]; if (do_mirr_v) dmloopuv->uv[1] = 1.0f - dmloopuv->uv[1]; } } } /* handle vgroup stuff */ if ((mmd->flag & MOD_MIR_VGROUP) && CustomData_has_layer(&result->vertData, CD_MDEFORMVERT)) { MDeformVert *dvert = (MDeformVert *) CustomData_get_layer(&result->vertData, CD_MDEFORMVERT) + maxVerts; int *flip_map = NULL, flip_map_len = 0; flip_map = defgroup_flip_map(ob, &flip_map_len, FALSE); if (flip_map) { for (i = 0; i < maxVerts; dvert++, i++) { /* merged vertices get both groups, others get flipped */ if (do_vtargetmap && (vtargetmap[i] != -1)) defvert_flip_merged(dvert, flip_map, flip_map_len); else defvert_flip(dvert, flip_map, flip_map_len); } MEM_freeN(flip_map); } } if (do_vtargetmap) { /* slow - so only call if one or more merge verts are found, * users may leave this on and not realize there is nothing to merge - campbell */ if (is_vtargetmap) { result = CDDM_merge_verts(result, vtargetmap); } MEM_freeN(vtargetmap); } return result; }
static void do_bake_shade(void *handle, int x, int y, float u, float v) { BakeShade *bs = handle; VlakRen *vlr = bs->vlr; ObjectInstanceRen *obi = bs->obi; Object *ob = obi->obr->ob; float l, *v1, *v2, *v3, tvn[3], ttang[4]; int quad; ShadeSample *ssamp = &bs->ssamp; ShadeInput *shi = ssamp->shi; /* fast threadsafe break test */ if (R.test_break(R.tbh)) return; /* setup render coordinates */ if (bs->quad) { v1 = vlr->v1->co; v2 = vlr->v3->co; v3 = vlr->v4->co; } else { v1 = vlr->v1->co; v2 = vlr->v2->co; v3 = vlr->v3->co; } l = 1.0f - u - v; /* shrink barycentric coordinates inwards slightly to avoid some issues * where baking selected to active might just miss the other face at the * near the edge of a face */ if (bs->actob) { const float eps = 1.0f - 1e-4f; float invsum; u = (u - 0.5f) * eps + 0.5f; v = (v - 0.5f) * eps + 0.5f; l = (l - 0.5f) * eps + 0.5f; invsum = 1.0f / (u + v + l); u *= invsum; v *= invsum; l *= invsum; } /* renderco */ shi->co[0] = l * v3[0] + u * v1[0] + v * v2[0]; shi->co[1] = l * v3[1] + u * v1[1] + v * v2[1]; shi->co[2] = l * v3[2] + u * v1[2] + v * v2[2]; /* avoid self shadow with vertex bake from adjacent faces [#33729] */ if ((bs->vcol != NULL) && (bs->actob == NULL)) { madd_v3_v3fl(shi->co, vlr->n, 0.0001f); } if (obi->flag & R_TRANSFORMED) mul_m4_v3(obi->mat, shi->co); copy_v3_v3(shi->dxco, bs->dxco); copy_v3_v3(shi->dyco, bs->dyco); quad = bs->quad; bake_set_shade_input(obi, vlr, shi, quad, 0, x, y, u, v); if (bs->type == RE_BAKE_NORMALS && R.r.bake_normal_space == R_BAKE_SPACE_TANGENT) { shade_input_set_shade_texco(shi); copy_v3_v3(tvn, shi->nmapnorm); copy_v4_v4(ttang, shi->nmaptang); } /* if we are doing selected to active baking, find point on other face */ if (bs->actob) { Isect isec, minisec; float co[3], minco[3], dist, mindist = 0.0f; int hit, sign, dir = 1; /* intersect with ray going forward and backward*/ hit = 0; memset(&minisec, 0, sizeof(minisec)); minco[0] = minco[1] = minco[2] = 0.0f; copy_v3_v3(bs->dir, shi->vn); for (sign = -1; sign <= 1; sign += 2) { memset(&isec, 0, sizeof(isec)); isec.mode = RE_RAY_MIRROR; isec.orig.ob = obi; isec.orig.face = vlr; isec.userdata = bs->actob; isec.check = RE_CHECK_VLR_BAKE; isec.skip = RE_SKIP_VLR_NEIGHBOUR; if (bake_intersect_tree(R.raytree, &isec, shi->co, shi->vn, sign, co, &dist)) { if (!hit || len_squared_v3v3(shi->co, co) < len_squared_v3v3(shi->co, minco)) { minisec = isec; mindist = dist; copy_v3_v3(minco, co); hit = 1; dir = sign; } } } if (ELEM(bs->type, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE)) { if (hit) bake_displacement(handle, shi, (dir == -1) ? mindist : -mindist, x, y); else bake_displacement(handle, shi, 0.0f, x, y); return; } /* if hit, we shade from the new point, otherwise from point one starting face */ if (hit) { obi = (ObjectInstanceRen *)minisec.hit.ob; vlr = (VlakRen *)minisec.hit.face; quad = (minisec.isect == 2); copy_v3_v3(shi->co, minco); u = -minisec.u; v = -minisec.v; bake_set_shade_input(obi, vlr, shi, quad, 1, x, y, u, v); } } if (bs->type == RE_BAKE_NORMALS && R.r.bake_normal_space == R_BAKE_SPACE_TANGENT) bake_shade(handle, ob, shi, quad, x, y, u, v, tvn, ttang); else bake_shade(handle, ob, shi, quad, x, y, u, v, NULL, 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); }
static enum ISectType intersect_line_tri( const float p0[3], const float p1[3], const float *t_cos[3], const float t_nor[3], float r_ix[3], const struct ISectEpsilon *e) { float p_dir[3]; unsigned int i_t0; float fac; sub_v3_v3v3(p_dir, p0, p1); normalize_v3(p_dir); for (i_t0 = 0; i_t0 < 3; i_t0++) { const unsigned int i_t1 = (i_t0 + 1) % 3; float te_dir[3]; sub_v3_v3v3(te_dir, t_cos[i_t0], t_cos[i_t1]); normalize_v3(te_dir); if (fabsf(dot_v3v3(p_dir, te_dir)) >= 1.0f - e->eps) { /* co-linear */ } else { float ix_pair[2][3]; int ix_pair_type; ix_pair_type = isect_line_line_epsilon_v3(p0, p1, t_cos[i_t0], t_cos[i_t1], ix_pair[0], ix_pair[1], 0.0f); if (ix_pair_type != 0) { if (ix_pair_type == 1) { copy_v3_v3(ix_pair[1], ix_pair[0]); } if ((ix_pair_type == 1) || (len_squared_v3v3(ix_pair[0], ix_pair[1]) <= e->eps_margin_sq)) { fac = line_point_factor_v3(ix_pair[1], t_cos[i_t0], t_cos[i_t1]); if ((fac >= e->eps_margin) && (fac <= 1.0f - e->eps_margin)) { fac = line_point_factor_v3(ix_pair[0], p0, p1); if ((fac >= e->eps_margin) && (fac <= 1.0f - e->eps_margin)) { copy_v3_v3(r_ix, ix_pair[0]); return (IX_EDGE_TRI_EDGE0 + (enum ISectType)i_t0); } } } } } } /* check ray isn't planar with tri */ if (fabsf(dot_v3v3(p_dir, t_nor)) >= e->eps) { if (isect_line_segment_tri_epsilon_v3(p0, p1, t_cos[0], t_cos[1], t_cos[2], &fac, NULL, 0.0f)) { if ((fac >= e->eps_margin) && (fac <= 1.0f - e->eps_margin)) { interp_v3_v3v3(r_ix, p0, p1, fac); if (min_fff(len_squared_v3v3(t_cos[0], r_ix), len_squared_v3v3(t_cos[1], r_ix), len_squared_v3v3(t_cos[2], r_ix)) >= e->eps_margin_sq) { return IX_EDGE_TRI; } } } } /* r_ix may be unset */ return IX_NONE; }
/** * 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); }
/** * This function populates pixel_array and returns TRUE if things are correct */ static bool cast_ray_highpoly( BVHTreeFromMesh *treeData, TriTessFace *triangles[], BakePixel *pixel_array, BakeHighPolyData *highpoly, const float co[3], const float dir[3], const int pixel_id, const int tot_highpoly, const float du_dx, const float du_dy, const float dv_dx, const float dv_dy) { int i; int primitive_id = -1; float uv[2]; int hit_mesh = -1; float hit_distance = FLT_MAX; BVHTreeRayHit *hits; hits = MEM_mallocN(sizeof(BVHTreeRayHit) * tot_highpoly, "Bake Highpoly to Lowpoly: BVH Rays"); for (i = 0; i < tot_highpoly; i++) { float co_high[3], dir_high[3]; hits[i].index = -1; /* TODO: we should use FLT_MAX here, but sweepsphere code isn't prepared for that */ hits[i].dist = 10000.0f; /* transform the ray from the world space to the highpoly space */ mul_v3_m4v3(co_high, highpoly[i].imat, co); /* rotates */ mul_v3_mat3_m4v3(dir_high, highpoly[i].imat, dir); normalize_v3(dir_high); /* cast ray */ if (treeData[i].tree) { BLI_bvhtree_ray_cast(treeData[i].tree, co_high, dir_high, 0.0f, &hits[i], treeData[i].raycast_callback, &treeData[i]); } if (hits[i].index != -1) { /* cull backface */ const float dot = dot_v3v3(dir_high, hits[i].no); if (dot < 0.0f) { float distance; float hit_world[3]; /* distance comparison in world space */ mul_v3_m4v3(hit_world, highpoly[i].obmat, hits[i].co); distance = len_squared_v3v3(hit_world, co); if (distance < hit_distance) { hit_mesh = i; hit_distance = distance; } } } } if (hit_mesh != -1) { calc_barycentric_from_point(triangles[hit_mesh], hits[hit_mesh].index, hits[hit_mesh].co, &primitive_id, uv); pixel_array[pixel_id].primitive_id = primitive_id; pixel_array[pixel_id].object_id = hit_mesh; copy_v2_v2(pixel_array[pixel_id].uv, uv); /* the differentials are relative to the UV/image space, so the highpoly differentials * are the same as the low poly differentials */ pixel_array[pixel_id].du_dx = du_dx; pixel_array[pixel_id].du_dy = du_dy; pixel_array[pixel_id].dv_dx = dv_dx; pixel_array[pixel_id].dv_dy = dv_dy; } else { pixel_array[pixel_id].primitive_id = -1; pixel_array[pixel_id].object_id = -1; } MEM_freeN(hits); return hit_mesh != -1; }
/** * Makes an NGon from an un-ordered set of verts * * assumes... * - that verts are only once in the list. * - that the verts have roughly planer bounds * - that the verts are roughly circular * there can be concave areas but overlapping folds from the center point will fail. * * a brief explanation of the method used * - find the center point * - find the normal of the vcloud * - order the verts around the face based on their angle to the normal vector at the center point. * * \note Since this is a vcloud there is no direction. */ void BM_verts_sort_radial_plane(BMVert **vert_arr, int len) { struct SortIntByFloat *vang = BLI_array_alloca(vang, len); BMVert **vert_arr_map = BLI_array_alloca(vert_arr_map, len); float totv_inv = 1.0f / (float)len; int i = 0; float cent[3], nor[3]; const float *far = NULL, *far_cross = NULL; float far_vec[3]; float far_cross_vec[3]; float sign_vec[3]; /* work out if we are pos/neg angle */ float far_dist_sq, far_dist_max_sq; float far_cross_dist, far_cross_best = 0.0f; /* get the center point and collect vector array since we loop over these a lot */ zero_v3(cent); for (i = 0; i < len; i++) { madd_v3_v3fl(cent, vert_arr[i]->co, totv_inv); } /* find the far point from cent */ far_dist_max_sq = 0.0f; for (i = 0; i < len; i++) { far_dist_sq = len_squared_v3v3(vert_arr[i]->co, cent); if (far_dist_sq > far_dist_max_sq || far == NULL) { far = vert_arr[i]->co; far_dist_max_sq = far_dist_sq; } } sub_v3_v3v3(far_vec, far, cent); // far_dist = len_v3(far_vec); /* real dist */ /* UNUSED */ /* --- */ /* find a point 90deg about to compare with */ far_cross_best = 0.0f; for (i = 0; i < len; i++) { if (far == vert_arr[i]->co) { continue; } sub_v3_v3v3(far_cross_vec, vert_arr[i]->co, cent); far_cross_dist = normalize_v3(far_cross_vec); /* more of a weight then a distance */ far_cross_dist = (/* first we want to have a value close to zero mapped to 1 */ 1.0f - fabsf(dot_v3v3(far_vec, far_cross_vec)) * /* second we multiply by the distance * so points close to the center are not preferred */ far_cross_dist); if (far_cross_dist > far_cross_best || far_cross == NULL) { far_cross = vert_arr[i]->co; far_cross_best = far_cross_dist; } } sub_v3_v3v3(far_cross_vec, far_cross, cent); /* --- */ /* now we have 2 vectors we can have a cross product */ cross_v3_v3v3(nor, far_vec, far_cross_vec); normalize_v3(nor); cross_v3_v3v3(sign_vec, far_vec, nor); /* this vector should match 'far_cross_vec' closely */ /* --- */ /* now calculate every points angle around the normal (signed) */ for (i = 0; i < len; i++) { vang[i].sort_value = angle_signed_on_axis_v3v3v3_v3(far, cent, vert_arr[i]->co, nor); vang[i].data = i; vert_arr_map[i] = vert_arr[i]; } /* sort by angle and magic! - we have our ngon */ qsort(vang, len, sizeof(*vang), BLI_sortutil_cmp_float); /* --- */ for (i = 0; i < len; i++) { vert_arr[i] = vert_arr_map[vang[i].data]; } }