static void initSystem(LaplacianDeformModifierData *lmd, Object *ob, DerivedMesh *dm, float (*vertexCos)[3], int numVerts) { int i; int defgrp_index; int total_anchors; float wpaint; MDeformVert *dvert = NULL; MDeformVert *dv = NULL; LaplacianSystem *sys; if (isValidVertexGroup(lmd, ob, dm)) { int *index_anchors = MEM_mallocN(sizeof(int) * numVerts, __func__); /* over-alloc */ const MLoopTri *mlooptri; const MLoop *mloop; STACK_DECLARE(index_anchors); STACK_INIT(index_anchors, numVerts); modifier_get_vgroup(ob, dm, lmd->anchor_grp_name, &dvert, &defgrp_index); BLI_assert(dvert != NULL); dv = dvert; for (i = 0; i < numVerts; i++) { wpaint = defvert_find_weight(dv, defgrp_index); dv++; if (wpaint > 0.0f) { STACK_PUSH(index_anchors, i); } } DM_ensure_looptri(dm); total_anchors = STACK_SIZE(index_anchors); lmd->cache_system = initLaplacianSystem(numVerts, dm->getNumEdges(dm), dm->getNumLoopTri(dm), total_anchors, lmd->anchor_grp_name, lmd->repeat); sys = (LaplacianSystem *)lmd->cache_system; memcpy(sys->index_anchors, index_anchors, sizeof(int) * total_anchors); memcpy(sys->co, vertexCos, sizeof(float[3]) * numVerts); MEM_freeN(index_anchors); lmd->vertexco = MEM_mallocN(sizeof(float[3]) * numVerts, "ModDeformCoordinates"); memcpy(lmd->vertexco, vertexCos, sizeof(float[3]) * numVerts); lmd->total_verts = numVerts; createFaceRingMap( dm->getNumVerts(dm), dm->getLoopTriArray(dm), dm->getNumLoopTri(dm), dm->getLoopArray(dm), &sys->ringf_map, &sys->ringf_indices); createVertRingMap( dm->getNumVerts(dm), dm->getEdgeArray(dm), dm->getNumEdges(dm), &sys->ringv_map, &sys->ringv_indices); mlooptri = dm->getLoopTriArray(dm); mloop = dm->getLoopArray(dm); for (i = 0; i < sys->total_tris; i++) { sys->tris[i][0] = mloop[mlooptri[i].tri[0]].v; sys->tris[i][1] = mloop[mlooptri[i].tri[1]].v; sys->tris[i][2] = mloop[mlooptri[i].tri[2]].v; } } }
static bool isValidVertexGroup(LaplacianDeformModifierData *lmd, Object *ob, DerivedMesh *dm) { int defgrp_index; MDeformVert *dvert = NULL; modifier_get_vgroup(ob, dm, lmd->anchor_grp_name, &dvert, &defgrp_index); return (dvert != NULL); }
static int isSystemDifferent(LaplacianDeformModifierData *lmd, Object *ob, DerivedMesh *dm, int numVerts) { int i; int defgrp_index; int total_anchors = 0; float wpaint; MDeformVert *dvert = NULL; MDeformVert *dv = NULL; LaplacianSystem *sys = (LaplacianSystem *)lmd->cache_system; if (sys->total_verts != numVerts) { return LAPDEFORM_SYSTEM_CHANGE_VERTEXES; } if (sys->total_edges != dm->getNumEdges(dm)) { return LAPDEFORM_SYSTEM_CHANGE_EDGES; } if (!STREQ(lmd->anchor_grp_name, sys->anchor_grp_name)) { return LAPDEFORM_SYSTEM_ONLY_CHANGE_GROUP; } modifier_get_vgroup(ob, dm, lmd->anchor_grp_name, &dvert, &defgrp_index); if (!dvert) { return LAPDEFORM_SYSTEM_CHANGE_NOT_VALID_GROUP; } dv = dvert; for (i = 0; i < numVerts; i++) { wpaint = defvert_find_weight(dv, defgrp_index); dv++; if (wpaint > 0.0f) { total_anchors++; } } if (sys->total_anchors != total_anchors) { return LAPDEFORM_SYSTEM_ONLY_CHANGE_ANCHORS; } return LAPDEFORM_SYSTEM_NOT_CHANGE; }
static void sphere_do( CastModifierData *cmd, Object *ob, DerivedMesh *dm, float (*vertexCos)[3], int numVerts) { MDeformVert *dvert = NULL; Object *ctrl_ob = NULL; int i, defgrp_index; bool has_radius = false; short flag, type; float len = 0.0f; float fac = cmd->fac; float facm = 1.0f - fac; const float fac_orig = fac; float vec[3], center[3] = {0.0f, 0.0f, 0.0f}; float mat[4][4], imat[4][4]; flag = cmd->flag; type = cmd->type; /* projection type: sphere or cylinder */ if (type == MOD_CAST_TYPE_CYLINDER) flag &= ~MOD_CAST_Z; ctrl_ob = cmd->object; /* spherify's center is {0, 0, 0} (the ob's own center in its local * space), by default, but if the user defined a control object, * we use its location, transformed to ob's local space */ if (ctrl_ob) { if (flag & MOD_CAST_USE_OB_TRANSFORM) { invert_m4_m4(imat, ctrl_ob->obmat); mul_m4_m4m4(mat, imat, ob->obmat); invert_m4_m4(imat, mat); } invert_m4_m4(ob->imat, ob->obmat); mul_v3_m4v3(center, ob->imat, ctrl_ob->obmat[3]); } /* now we check which options the user wants */ /* 1) (flag was checked in the "if (ctrl_ob)" block above) */ /* 2) cmd->radius > 0.0f: only the vertices within this radius from * the center of the effect should be deformed */ if (cmd->radius > FLT_EPSILON) has_radius = 1; /* 3) if we were given a vertex group name, * only those vertices should be affected */ modifier_get_vgroup(ob, dm, cmd->defgrp_name, &dvert, &defgrp_index); if (flag & MOD_CAST_SIZE_FROM_RADIUS) { len = cmd->radius; } else { len = cmd->size; } if (len <= 0) { for (i = 0; i < numVerts; i++) { len += len_v3v3(center, vertexCos[i]); } len /= numVerts; if (len == 0.0f) len = 10.0f; } for (i = 0; i < numVerts; i++) { float tmp_co[3]; copy_v3_v3(tmp_co, vertexCos[i]); if (ctrl_ob) { if (flag & MOD_CAST_USE_OB_TRANSFORM) { mul_m4_v3(mat, tmp_co); } else { sub_v3_v3(tmp_co, center); } } copy_v3_v3(vec, tmp_co); if (type == MOD_CAST_TYPE_CYLINDER) vec[2] = 0.0f; if (has_radius) { if (len_v3(vec) > cmd->radius) continue; } if (dvert) { const float weight = defvert_find_weight(&dvert[i], defgrp_index); if (weight == 0.0f) { continue; } fac = fac_orig * weight; facm = 1.0f - fac; } normalize_v3(vec); if (flag & MOD_CAST_X) tmp_co[0] = fac * vec[0] * len + facm * tmp_co[0]; if (flag & MOD_CAST_Y) tmp_co[1] = fac * vec[1] * len + facm * tmp_co[1]; if (flag & MOD_CAST_Z) tmp_co[2] = fac * vec[2] * len + facm * tmp_co[2]; if (ctrl_ob) { if (flag & MOD_CAST_USE_OB_TRANSFORM) { mul_m4_v3(imat, tmp_co); } else { add_v3_v3(tmp_co, center); } } copy_v3_v3(vertexCos[i], tmp_co); } }
static void cuboid_do( CastModifierData *cmd, Object *ob, DerivedMesh *dm, float (*vertexCos)[3], int numVerts) { MDeformVert *dvert = NULL; Object *ctrl_ob = NULL; int i, defgrp_index; bool has_radius = false; short flag; float fac = cmd->fac; float facm = 1.0f - fac; const float fac_orig = fac; float min[3], max[3], bb[8][3]; float center[3] = {0.0f, 0.0f, 0.0f}; float mat[4][4], imat[4][4]; flag = cmd->flag; ctrl_ob = cmd->object; /* now we check which options the user wants */ /* 1) (flag was checked in the "if (ctrl_ob)" block above) */ /* 2) cmd->radius > 0.0f: only the vertices within this radius from * the center of the effect should be deformed */ if (cmd->radius > FLT_EPSILON) has_radius = 1; /* 3) if we were given a vertex group name, * only those vertices should be affected */ modifier_get_vgroup(ob, dm, cmd->defgrp_name, &dvert, &defgrp_index); if (ctrl_ob) { if (flag & MOD_CAST_USE_OB_TRANSFORM) { invert_m4_m4(imat, ctrl_ob->obmat); mul_m4_m4m4(mat, imat, ob->obmat); invert_m4_m4(imat, mat); } invert_m4_m4(ob->imat, ob->obmat); mul_v3_m4v3(center, ob->imat, ctrl_ob->obmat[3]); } if ((flag & MOD_CAST_SIZE_FROM_RADIUS) && has_radius) { for (i = 0; i < 3; i++) { min[i] = -cmd->radius; max[i] = cmd->radius; } } else if (!(flag & MOD_CAST_SIZE_FROM_RADIUS) && cmd->size > 0) { for (i = 0; i < 3; i++) { min[i] = -cmd->size; max[i] = cmd->size; } } else { /* get bound box */ /* We can't use the object's bound box because other modifiers * may have changed the vertex data. */ INIT_MINMAX(min, max); /* Cast's center is the ob's own center in its local space, * by default, but if the user defined a control object, we use * its location, transformed to ob's local space. */ if (ctrl_ob) { float vec[3]; /* let the center of the ctrl_ob be part of the bound box: */ minmax_v3v3_v3(min, max, center); for (i = 0; i < numVerts; i++) { sub_v3_v3v3(vec, vertexCos[i], center); minmax_v3v3_v3(min, max, vec); } } else { for (i = 0; i < numVerts; i++) { minmax_v3v3_v3(min, max, vertexCos[i]); } } /* we want a symmetric bound box around the origin */ if (fabsf(min[0]) > fabsf(max[0])) max[0] = fabsf(min[0]); if (fabsf(min[1]) > fabsf(max[1])) max[1] = fabsf(min[1]); if (fabsf(min[2]) > fabsf(max[2])) max[2] = fabsf(min[2]); min[0] = -max[0]; min[1] = -max[1]; min[2] = -max[2]; } /* building our custom bounding box */ bb[0][0] = bb[2][0] = bb[4][0] = bb[6][0] = min[0]; bb[1][0] = bb[3][0] = bb[5][0] = bb[7][0] = max[0]; bb[0][1] = bb[1][1] = bb[4][1] = bb[5][1] = min[1]; bb[2][1] = bb[3][1] = bb[6][1] = bb[7][1] = max[1]; bb[0][2] = bb[1][2] = bb[2][2] = bb[3][2] = min[2]; bb[4][2] = bb[5][2] = bb[6][2] = bb[7][2] = max[2]; /* ready to apply the effect, one vertex at a time */ for (i = 0; i < numVerts; i++) { int octant, coord; float d[3], dmax, apex[3], fbb; float tmp_co[3]; copy_v3_v3(tmp_co, vertexCos[i]); if (ctrl_ob) { if (flag & MOD_CAST_USE_OB_TRANSFORM) { mul_m4_v3(mat, tmp_co); } else { sub_v3_v3(tmp_co, center); } } if (has_radius) { if (fabsf(tmp_co[0]) > cmd->radius || fabsf(tmp_co[1]) > cmd->radius || fabsf(tmp_co[2]) > cmd->radius) { continue; } } if (dvert) { const float weight = defvert_find_weight(&dvert[i], defgrp_index); if (weight == 0.0f) { continue; } fac = fac_orig * weight; facm = 1.0f - fac; } /* The algo used to project the vertices to their * bounding box (bb) is pretty simple: * for each vertex v: * 1) find in which octant v is in; * 2) find which outer "wall" of that octant is closer to v; * 3) calculate factor (var fbb) to project v to that wall; * 4) project. */ /* find in which octant this vertex is in */ octant = 0; if (tmp_co[0] > 0.0f) octant += 1; if (tmp_co[1] > 0.0f) octant += 2; if (tmp_co[2] > 0.0f) octant += 4; /* apex is the bb's vertex at the chosen octant */ copy_v3_v3(apex, bb[octant]); /* find which bb plane is closest to this vertex ... */ d[0] = tmp_co[0] / apex[0]; d[1] = tmp_co[1] / apex[1]; d[2] = tmp_co[2] / apex[2]; /* ... (the closest has the higher (closer to 1) d value) */ dmax = d[0]; coord = 0; if (d[1] > dmax) { dmax = d[1]; coord = 1; } if (d[2] > dmax) { /* dmax = d[2]; */ /* commented, we don't need it */ coord = 2; } /* ok, now we know which coordinate of the vertex to use */ if (fabsf(tmp_co[coord]) < FLT_EPSILON) /* avoid division by zero */ continue; /* finally, this is the factor we wanted, to project the vertex * to its bounding box (bb) */ fbb = apex[coord] / tmp_co[coord]; /* calculate the new vertex position */ if (flag & MOD_CAST_X) tmp_co[0] = facm * tmp_co[0] + fac * tmp_co[0] * fbb; if (flag & MOD_CAST_Y) tmp_co[1] = facm * tmp_co[1] + fac * tmp_co[1] * fbb; if (flag & MOD_CAST_Z) tmp_co[2] = facm * tmp_co[2] + fac * tmp_co[2] * fbb; if (ctrl_ob) { if (flag & MOD_CAST_USE_OB_TRANSFORM) { mul_m4_v3(imat, tmp_co); } else { add_v3_v3(tmp_co, center); } } copy_v3_v3(vertexCos[i], tmp_co); } }
/* dm must be a CDDerivedMesh */ static void displaceModifier_do( DisplaceModifierData *dmd, Object *ob, DerivedMesh *dm, float (*vertexCos)[3], int numVerts) { int i; MVert *mvert; MDeformVert *dvert; int defgrp_index; float (*tex_co)[3]; float weight = 1.0f; /* init value unused but some compilers may complain */ const float delta_fixed = 1.0f - dmd->midlevel; /* when no texture is used, we fallback to white */ if (!dmd->texture && dmd->direction == MOD_DISP_DIR_RGB_XYZ) return; if (dmd->strength == 0.0f) return; mvert = CDDM_get_verts(dm); modifier_get_vgroup(ob, dm, dmd->defgrp_name, &dvert, &defgrp_index); if (dmd->texture) { tex_co = MEM_callocN(sizeof(*tex_co) * numVerts, "displaceModifier_do tex_co"); get_texture_coords((MappingInfoModifierData *)dmd, ob, dm, vertexCos, tex_co, numVerts); modifier_init_texture(dmd->modifier.scene, dmd->texture); } else { tex_co = NULL; } for (i = 0; i < numVerts; i++) { TexResult texres; float strength = dmd->strength; float delta; if (dvert) { weight = defvert_find_weight(dvert + i, defgrp_index); if (weight == 0.0f) continue; } if (dmd->texture) { texres.nor = NULL; BKE_texture_get_value(dmd->modifier.scene, dmd->texture, tex_co[i], &texres, false); delta = texres.tin - dmd->midlevel; } else { delta = delta_fixed; /* (1.0f - dmd->midlevel) */ /* never changes */ } if (dvert) strength *= weight; delta *= strength; CLAMP(delta, -10000, 10000); switch (dmd->direction) { case MOD_DISP_DIR_X: vertexCos[i][0] += delta; break; case MOD_DISP_DIR_Y: vertexCos[i][1] += delta; break; case MOD_DISP_DIR_Z: vertexCos[i][2] += delta; break; case MOD_DISP_DIR_RGB_XYZ: vertexCos[i][0] += (texres.tr - dmd->midlevel) * strength; vertexCos[i][1] += (texres.tg - dmd->midlevel) * strength; vertexCos[i][2] += (texres.tb - dmd->midlevel) * strength; break; case MOD_DISP_DIR_NOR: vertexCos[i][0] += delta * (mvert[i].no[0] / 32767.0f); vertexCos[i][1] += delta * (mvert[i].no[1] / 32767.0f); vertexCos[i][2] += delta * (mvert[i].no[2] / 32767.0f); break; } } if (tex_co) { MEM_freeN(tex_co); } }
static void correctivesmooth_modifier_do( ModifierData *md, Object *ob, DerivedMesh *dm, float (*vertexCos)[3], unsigned int numVerts, struct BMEditMesh *em) { CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md; const bool force_delta_cache_update = /* XXX, take care! if mesh data its self changes we need to forcefully recalculate deltas */ ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO) && (((ID *)ob->data)->tag & LIB_TAG_ID_RECALC)); bool use_only_smooth = (csmd->flag & MOD_CORRECTIVESMOOTH_ONLY_SMOOTH) != 0; MDeformVert *dvert = NULL; int defgrp_index; modifier_get_vgroup(ob, dm, csmd->defgrp_name, &dvert, &defgrp_index); /* if rest bind_coords not are defined, set them (only run during bind) */ if ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) && /* signal to recalculate, whoever sets MUST also free bind coords */ (csmd->bind_coords_num == (unsigned int)-1)) { BLI_assert(csmd->bind_coords == NULL); csmd->bind_coords = MEM_dupallocN(vertexCos); csmd->bind_coords_num = numVerts; BLI_assert(csmd->bind_coords != NULL); } if (UNLIKELY(use_only_smooth)) { smooth_verts(csmd, dm, dvert, defgrp_index, vertexCos, numVerts); return; } if ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) && (csmd->bind_coords == NULL)) { modifier_setError(md, "Bind data required"); goto error; } /* If the number of verts has changed, the bind is invalid, so we do nothing */ if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) { if (csmd->bind_coords_num != numVerts) { modifier_setError(md, "Bind vertex count mismatch: %u to %u", csmd->bind_coords_num, numVerts); goto error; } } else { /* MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO */ if (ob->type != OB_MESH) { modifier_setError(md, "Object is not a mesh"); goto error; } else { unsigned int me_numVerts = (unsigned int)((em) ? em->bm->totvert : ((Mesh *)ob->data)->totvert); if (me_numVerts != numVerts) { modifier_setError(md, "Original vertex count mismatch: %u to %u", me_numVerts, numVerts); goto error; } } } /* check to see if our deltas are still valid */ if (!csmd->delta_cache || (csmd->delta_cache_num != numVerts) || force_delta_cache_update) { const float (*rest_coords)[3]; bool is_rest_coords_alloc = false; if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) { /* caller needs to do sanity check here */ csmd->bind_coords_num = numVerts; rest_coords = (const float (*)[3])csmd->bind_coords; } else { int me_numVerts; rest_coords = (const float (*)[3]) ((em) ? BKE_editmesh_vertexCos_get_orco(em, &me_numVerts) : BKE_mesh_vertexCos_get(ob->data, &me_numVerts)); BLI_assert((unsigned int)me_numVerts == numVerts); is_rest_coords_alloc = true; } #ifdef DEBUG_TIME TIMEIT_START(corrective_smooth_deltas); #endif calc_deltas(csmd, dm, dvert, defgrp_index, rest_coords, numVerts); #ifdef DEBUG_TIME TIMEIT_END(corrective_smooth_deltas); #endif if (is_rest_coords_alloc) { MEM_freeN((void *)rest_coords); } } if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) { /* this could be a check, but at this point it _must_ be valid */ BLI_assert(csmd->bind_coords_num == numVerts && csmd->delta_cache); } #ifdef DEBUG_TIME TIMEIT_START(corrective_smooth); #endif /* do the actual delta mush */ smooth_verts(csmd, dm, dvert, defgrp_index, vertexCos, numVerts); { unsigned int i; float (*tangent_spaces)[3][3]; /* calloc, since values are accumulated */ tangent_spaces = MEM_callocN((size_t)numVerts * sizeof(float[3][3]), __func__); calc_tangent_spaces(dm, vertexCos, tangent_spaces); for (i = 0; i < numVerts; i++) { float delta[3]; #ifdef USE_TANGENT_CALC_INLINE calc_tangent_ortho(tangent_spaces[i]); #endif mul_v3_m3v3(delta, tangent_spaces[i], csmd->delta_cache[i]); add_v3_v3(vertexCos[i], delta); } MEM_freeN(tangent_spaces); } #ifdef DEBUG_TIME TIMEIT_END(corrective_smooth); #endif return; /* when the modifier fails to execute */ error: MEM_SAFE_FREE(csmd->delta_cache); csmd->delta_cache_num = 0; }
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *dm, ModifierApplyFlag UNUSED(flag)) { UVWarpModifierData *umd = (UVWarpModifierData *) md; int numPolys, numLoops; MPoly *mpoly; MLoop *mloop; MLoopUV *mloopuv; MDeformVert *dvert; int defgrp_index; char uvname[MAX_CUSTOMDATA_LAYER_NAME]; float mat_src[4][4]; float mat_dst[4][4]; float imat_dst[4][4]; float warp_mat[4][4]; const int axis_u = umd->axis_u; const int axis_v = umd->axis_v; /* make sure there are UV Maps available */ if (!CustomData_has_layer(&dm->loopData, CD_MLOOPUV)) { return dm; } else if (ELEM(NULL, umd->object_src, umd->object_dst)) { modifier_setError(md, "From/To objects must be set"); return dm; } /* make sure anything moving UVs is available */ matrix_from_obj_pchan(mat_src, umd->object_src, umd->bone_src); matrix_from_obj_pchan(mat_dst, umd->object_dst, umd->bone_dst); invert_m4_m4(imat_dst, mat_dst); mul_m4_m4m4(warp_mat, imat_dst, mat_src); /* apply warp */ if (!is_zero_v2(umd->center)) { float mat_cent[4][4]; float imat_cent[4][4]; unit_m4(mat_cent); mat_cent[3][axis_u] = umd->center[0]; mat_cent[3][axis_v] = umd->center[1]; invert_m4_m4(imat_cent, mat_cent); mul_m4_m4m4(warp_mat, warp_mat, imat_cent); mul_m4_m4m4(warp_mat, mat_cent, warp_mat); } /* make sure we're using an existing layer */ CustomData_validate_layer_name(&dm->loopData, CD_MLOOPUV, umd->uvlayer_name, uvname); numPolys = dm->getNumPolys(dm); numLoops = dm->getNumLoops(dm); mpoly = dm->getPolyArray(dm); mloop = dm->getLoopArray(dm); /* make sure we are not modifying the original UV map */ mloopuv = CustomData_duplicate_referenced_layer_named(&dm->loopData, CD_MLOOPUV, uvname, numLoops); modifier_get_vgroup(ob, dm, umd->vgroup_name, &dvert, &defgrp_index); UVWarpData data = {.mpoly = mpoly, .mloop = mloop, .mloopuv = mloopuv, .dvert = dvert, .defgrp_index = defgrp_index, .warp_mat = warp_mat, .axis_u = axis_u, .axis_v = axis_v}; BLI_task_parallel_range(0, numPolys, &data, uv_warp_compute, numPolys > 1000); dm->dirty |= DM_DIRTY_TESS_CDLAYERS; return dm; }
static DerivedMesh *normalEditModifier_do(NormalEditModifierData *enmd, Object *ob, DerivedMesh *dm) { Mesh *me = ob->data; const int num_verts = dm->getNumVerts(dm); const int num_edges = dm->getNumEdges(dm); const int num_loops = dm->getNumLoops(dm); const int num_polys = dm->getNumPolys(dm); MVert *mvert; MEdge *medge; MLoop *mloop; MPoly *mpoly; const bool use_invert_vgroup = ((enmd->flag & MOD_NORMALEDIT_INVERT_VGROUP) != 0); const bool use_current_clnors = !((enmd->mix_mode == MOD_NORMALEDIT_MIX_COPY) && (enmd->mix_factor == 1.0f) && (enmd->defgrp_name[0] == '\0') && (enmd->mix_limit == (float)M_PI)); int defgrp_index; MDeformVert *dvert; float (*loopnors)[3] = NULL; short (*clnors)[2]; float (*polynors)[3]; bool free_polynors = false; /* Do not run that modifier at all if autosmooth is disabled! */ if (!is_valid_target(enmd) || !num_loops) { return dm; } if (!(me->flag & ME_AUTOSMOOTH)) { modifier_setError((ModifierData *)enmd, "Enable 'Auto Smooth' option in mesh settings"); return dm; } medge = dm->getEdgeArray(dm); if (me->medge == medge) { /* We need to duplicate data here, otherwise setting custom normals (which may also affect sharp edges) could * modify org mesh, see T43671. */ dm = CDDM_copy(dm); medge = dm->getEdgeArray(dm); } mvert = dm->getVertArray(dm); mloop = dm->getLoopArray(dm); mpoly = dm->getPolyArray(dm); if (use_current_clnors) { dm->calcLoopNormals(dm, true, me->smoothresh); loopnors = dm->getLoopDataArray(dm, CD_NORMAL); } clnors = CustomData_duplicate_referenced_layer(&dm->loopData, CD_CUSTOMLOOPNORMAL, num_loops); if (!clnors) { DM_add_loop_layer(dm, CD_CUSTOMLOOPNORMAL, CD_CALLOC, NULL); clnors = dm->getLoopDataArray(dm, CD_CUSTOMLOOPNORMAL); } polynors = dm->getPolyDataArray(dm, CD_NORMAL); if (!polynors) { polynors = MEM_malloc_arrayN((size_t)num_polys, sizeof(*polynors), __func__); BKE_mesh_calc_normals_poly(mvert, NULL, num_verts, mloop, mpoly, num_loops, num_polys, polynors, false); free_polynors = true; } modifier_get_vgroup(ob, dm, enmd->defgrp_name, &dvert, &defgrp_index); if (enmd->mode == MOD_NORMALEDIT_MODE_RADIAL) { normalEditModifier_do_radial( enmd, ob, dm, clnors, loopnors, polynors, enmd->mix_mode, enmd->mix_factor, enmd->mix_limit, dvert, defgrp_index, use_invert_vgroup, mvert, num_verts, medge, num_edges, mloop, num_loops, mpoly, num_polys); } else if (enmd->mode == MOD_NORMALEDIT_MODE_DIRECTIONAL) { normalEditModifier_do_directional( enmd, ob, dm, clnors, loopnors, polynors, enmd->mix_mode, enmd->mix_factor, enmd->mix_limit, dvert, defgrp_index, use_invert_vgroup, mvert, num_verts, medge, num_edges, mloop, num_loops, mpoly, num_polys); } if (free_polynors) { MEM_freeN(polynors); } return dm; }
static void waveModifier_do(WaveModifierData *md, Scene *scene, Object *ob, DerivedMesh *dm, float (*vertexCos)[3], int numVerts) { WaveModifierData *wmd = (WaveModifierData*) md; MVert *mvert = NULL; MDeformVert *dvert; int defgrp_index; float ctime = BKE_curframe(scene); float minfac = (float)(1.0 / exp(wmd->width * wmd->narrow * wmd->width * wmd->narrow)); float lifefac = wmd->height; float (*tex_co)[3] = NULL; const int wmd_axis= wmd->flag & (MOD_WAVE_X|MOD_WAVE_Y); const float falloff= wmd->falloff; float falloff_fac= 1.0f; /* when falloff == 0.0f this stays at 1.0f */ if(wmd->flag & MOD_WAVE_NORM && ob->type == OB_MESH) mvert = dm->getVertArray(dm); if(wmd->objectcenter){ float mat[4][4]; /* get the control object's location in local coordinates */ invert_m4_m4(ob->imat, ob->obmat); mul_m4_m4m4(mat, wmd->objectcenter->obmat, ob->imat); wmd->startx = mat[3][0]; wmd->starty = mat[3][1]; } /* get the index of the deform group */ modifier_get_vgroup(ob, dm, wmd->defgrp_name, &dvert, &defgrp_index); if(wmd->damp == 0) wmd->damp = 10.0f; if(wmd->lifetime != 0.0f) { float x = ctime - wmd->timeoffs; if(x > wmd->lifetime) { lifefac = x - wmd->lifetime; if(lifefac > wmd->damp) lifefac = 0.0; else lifefac = (float)(wmd->height * (1.0f - sqrtf(lifefac / wmd->damp))); } } if(wmd->texture) { tex_co = MEM_mallocN(sizeof(*tex_co) * numVerts, "waveModifier_do tex_co"); wavemod_get_texture_coords(wmd, ob, dm, vertexCos, tex_co, numVerts); } if(lifefac != 0.0f) { /* avoid divide by zero checks within the loop */ float falloff_inv= falloff ? 1.0f / falloff : 1.0f; int i; for(i = 0; i < numVerts; i++) { float *co = vertexCos[i]; float x = co[0] - wmd->startx; float y = co[1] - wmd->starty; float amplit= 0.0f; float def_weight= 1.0f; /* get weights */ if(dvert) { def_weight= defvert_find_weight(&dvert[i], defgrp_index); /* if this vert isn't in the vgroup, don't deform it */ if(def_weight == 0.0f) { continue; } } switch(wmd_axis) { case MOD_WAVE_X|MOD_WAVE_Y: amplit = sqrtf(x*x + y*y); break; case MOD_WAVE_X: amplit = x; break; case MOD_WAVE_Y: amplit = y; break; } /* this way it makes nice circles */ amplit -= (ctime - wmd->timeoffs) * wmd->speed; if(wmd->flag & MOD_WAVE_CYCL) { amplit = (float)fmodf(amplit - wmd->width, 2.0f * wmd->width) + wmd->width; } if(falloff != 0.0f) { float dist = 0.0f; switch(wmd_axis) { case MOD_WAVE_X|MOD_WAVE_Y: dist = sqrtf(x*x + y*y); break; case MOD_WAVE_X: dist = fabsf(x); break; case MOD_WAVE_Y: dist = fabsf(y); break; } falloff_fac = (1.0f - (dist * falloff_inv)); CLAMP(falloff_fac, 0.0f, 1.0f); } /* GAUSSIAN */ if((falloff_fac != 0.0f) && (amplit > -wmd->width) && (amplit < wmd->width)) { amplit = amplit * wmd->narrow; amplit = (float)(1.0f / expf(amplit * amplit) - minfac); /*apply texture*/ if(wmd->texture) { TexResult texres; texres.nor = NULL; get_texture_value(wmd->texture, tex_co[i], &texres); amplit *= texres.tin; } /*apply weight & falloff */ amplit *= def_weight * falloff_fac; if(mvert) { /* move along normals */ if(wmd->flag & MOD_WAVE_NORM_X) { co[0] += (lifefac * amplit) * mvert[i].no[0] / 32767.0f; } if(wmd->flag & MOD_WAVE_NORM_Y) { co[1] += (lifefac * amplit) * mvert[i].no[1] / 32767.0f; } if(wmd->flag & MOD_WAVE_NORM_Z) { co[2] += (lifefac * amplit) * mvert[i].no[2] / 32767.0f; } } else { /* move along local z axis */ co[2] += lifefac * amplit; } } } } if(wmd->texture) MEM_freeN(tex_co); }
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData, ModifierApplyFlag UNUSED(flag)) { DecimateModifierData *dmd = (DecimateModifierData *) md; DerivedMesh *dm = derivedData, *result = NULL; BMesh *bm; bool calc_face_normal; float *vweights = NULL; #ifdef USE_TIMEIT TIMEIT_START(decim); #endif /* set up front so we dont show invalid info in the UI */ dmd->face_count = dm->getNumPolys(dm); switch (dmd->mode) { case MOD_DECIM_MODE_COLLAPSE: if (dmd->percent == 1.0f) { return dm; } calc_face_normal = true; break; case MOD_DECIM_MODE_UNSUBDIV: if (dmd->iter == 0) { return dm; } calc_face_normal = false; break; case MOD_DECIM_MODE_DISSOLVE: if (dmd->angle == 0.0f) { return dm; } calc_face_normal = true; break; default: return dm; } if (dmd->face_count <= 3) { modifier_setError(md, "Modifier requires more than 3 input faces"); return dm; } if (dmd->mode == MOD_DECIM_MODE_COLLAPSE) { if (dmd->defgrp_name[0]) { MDeformVert *dvert; int defgrp_index; modifier_get_vgroup(ob, dm, dmd->defgrp_name, &dvert, &defgrp_index); if (dvert) { const unsigned int vert_tot = dm->getNumVerts(dm); unsigned int i; vweights = MEM_mallocN(vert_tot * sizeof(float), __func__); if (dmd->flag & MOD_DECIM_FLAG_INVERT_VGROUP) { for (i = 0; i < vert_tot; i++) { const float f = 1.0f - defvert_find_weight(&dvert[i], defgrp_index); vweights[i] = f > BM_MESH_DECIM_WEIGHT_EPS ? (1.0f / f) : BM_MESH_DECIM_WEIGHT_MAX; } } else { for (i = 0; i < vert_tot; i++) { const float f = defvert_find_weight(&dvert[i], defgrp_index); vweights[i] = f > BM_MESH_DECIM_WEIGHT_EPS ? (1.0f / f) : BM_MESH_DECIM_WEIGHT_MAX; } } } } } bm = DM_to_bmesh(dm, calc_face_normal); switch (dmd->mode) { case MOD_DECIM_MODE_COLLAPSE: { const int do_triangulate = (dmd->flag & MOD_DECIM_FLAG_TRIANGULATE) != 0; BM_mesh_decimate_collapse(bm, dmd->percent, vweights, do_triangulate); break; } case MOD_DECIM_MODE_UNSUBDIV: { BM_mesh_decimate_unsubdivide(bm, dmd->iter); break; } case MOD_DECIM_MODE_DISSOLVE: { const int do_dissolve_boundaries = (dmd->flag & MOD_DECIM_FLAG_ALL_BOUNDARY_VERTS) != 0; BM_mesh_decimate_dissolve(bm, dmd->angle, do_dissolve_boundaries, (BMO_Delimit)dmd->delimit); break; } } if (vweights) { MEM_freeN(vweights); } /* update for display only */ dmd->face_count = bm->totface; result = CDDM_from_bmesh(bm, false); BLI_assert(bm->vtoolflagpool == NULL && bm->etoolflagpool == NULL && bm->ftoolflagpool == NULL); /* make sure we never alloc'd these */ BLI_assert(bm->vtable == NULL && bm->etable == NULL && bm->ftable == NULL); BM_mesh_free(bm); #ifdef USE_TIMEIT TIMEIT_END(decim); #endif result->dirty = DM_DIRTY_NORMALS; return result; }
static void meshdeformModifier_do( ModifierData *md, Object *ob, DerivedMesh *dm, float (*vertexCos)[3], int numVerts) { MeshDeformModifierData *mmd = (MeshDeformModifierData *) md; struct Mesh *me = (mmd->object) ? mmd->object->data : NULL; BMEditMesh *em = me ? me->edit_btmesh : NULL; DerivedMesh *tmpdm, *cagedm; MDeformVert *dvert = NULL; MDefInfluence *influences; int *offsets; float imat[4][4], cagemat[4][4], iobmat[4][4], icagemat[3][3], cmat[4][4]; float weight, totweight, fac, co[3], (*dco)[3], (*bindcagecos)[3]; int a, b, totvert, totcagevert, defgrp_index; float (*cagecos)[3]; if (!mmd->object || (!mmd->bindcagecos && !mmd->bindfunc)) return; /* get cage derivedmesh */ if (em) { tmpdm = editbmesh_get_derived_cage_and_final(md->scene, ob, em, &cagedm, 0); if (tmpdm) tmpdm->release(tmpdm); } else cagedm = mmd->object->derivedFinal; /* if we don't have one computed, use derivedmesh from data * without any modifiers */ if (!cagedm) { cagedm = get_dm(mmd->object, NULL, NULL, NULL, 0); if (cagedm) cagedm->needsFree = 1; } if (!cagedm) { modifier_setError(md, "Cannot get mesh from cage object"); return; } /* compute matrices to go in and out of cage object space */ invert_m4_m4(imat, mmd->object->obmat); mult_m4_m4m4(cagemat, imat, ob->obmat); mult_m4_m4m4(cmat, mmd->bindmat, cagemat); invert_m4_m4(iobmat, cmat); copy_m3_m4(icagemat, iobmat); /* bind weights if needed */ if (!mmd->bindcagecos) { static int recursive = 0; /* progress bar redraw can make this recursive .. */ if (!recursive) { recursive = 1; mmd->bindfunc(md->scene, mmd, (float *)vertexCos, numVerts, cagemat); recursive = 0; } } /* verify we have compatible weights */ totvert = numVerts; totcagevert = cagedm->getNumVerts(cagedm); if (mmd->totvert != totvert) { modifier_setError(md, "Verts changed from %d to %d", mmd->totvert, totvert); cagedm->release(cagedm); return; } else if (mmd->totcagevert != totcagevert) { modifier_setError(md, "Cage verts changed from %d to %d", mmd->totcagevert, totcagevert); cagedm->release(cagedm); return; } else if (mmd->bindcagecos == NULL) { modifier_setError(md, "Bind data missing"); cagedm->release(cagedm); return; } cagecos = MEM_callocN(sizeof(*cagecos) * totcagevert, "meshdeformModifier vertCos"); /* setup deformation data */ cagedm->getVertCos(cagedm, cagecos); influences = mmd->bindinfluences; offsets = mmd->bindoffsets; bindcagecos = (float(*)[3])mmd->bindcagecos; dco = MEM_callocN(sizeof(*dco) * totcagevert, "MDefDco"); for (a = 0; a < totcagevert; a++) { /* get cage vertex in world space with binding transform */ copy_v3_v3(co, cagecos[a]); if (G.debug_value != 527) { mul_m4_v3(mmd->bindmat, co); /* compute difference with world space bind coord */ sub_v3_v3v3(dco[a], co, bindcagecos[a]); } else copy_v3_v3(dco[a], co); } modifier_get_vgroup(ob, dm, mmd->defgrp_name, &dvert, &defgrp_index); /* do deformation */ fac = 1.0f; for (b = 0; b < totvert; b++) { if (mmd->flag & MOD_MDEF_DYNAMIC_BIND) if (!mmd->dynverts[b]) continue; if (dvert) { fac = defvert_find_weight(&dvert[b], defgrp_index); if (mmd->flag & MOD_MDEF_INVERT_VGROUP) { fac = 1.0f - fac; } if (fac <= 0.0f) { continue; } } if (mmd->flag & MOD_MDEF_DYNAMIC_BIND) { /* transform coordinate into cage's local space */ mul_v3_m4v3(co, cagemat, vertexCos[b]); totweight = meshdeform_dynamic_bind(mmd, dco, co); } else { totweight = 0.0f; zero_v3(co); for (a = offsets[b]; a < offsets[b + 1]; a++) { weight = influences[a].weight; madd_v3_v3fl(co, dco[influences[a].vertex], weight); totweight += weight; } } if (totweight > 0.0f) { mul_v3_fl(co, fac / totweight); mul_m3_v3(icagemat, co); if (G.debug_value != 527) add_v3_v3(vertexCos[b], co); else copy_v3_v3(vertexCos[b], co); } } /* release cage derivedmesh */ MEM_freeN(dco); MEM_freeN(cagecos); cagedm->release(cagedm); }
static DerivedMesh *applyModifier( ModifierData *md, Object *ob, DerivedMesh *dm, ModifierApplyFlag UNUSED(flag)) { DerivedMesh *result; const SolidifyModifierData *smd = (SolidifyModifierData *) md; MVert *mv, *mvert, *orig_mvert; MEdge *ed, *medge, *orig_medge; MLoop *ml, *mloop, *orig_mloop; MPoly *mp, *mpoly, *orig_mpoly; const unsigned int numVerts = (unsigned int)dm->getNumVerts(dm); const unsigned int numEdges = (unsigned int)dm->getNumEdges(dm); const unsigned int numFaces = (unsigned int)dm->getNumPolys(dm); const unsigned int numLoops = (unsigned int)dm->getNumLoops(dm); unsigned int newLoops = 0, newFaces = 0, newEdges = 0, newVerts = 0, rimVerts = 0; /* only use material offsets if we have 2 or more materials */ const short mat_nr_max = ob->totcol > 1 ? ob->totcol - 1 : 0; const short mat_ofs = mat_nr_max ? smd->mat_ofs : 0; const short mat_ofs_rim = mat_nr_max ? smd->mat_ofs_rim : 0; /* use for edges */ /* over-alloc new_vert_arr, old_vert_arr */ unsigned int *new_vert_arr = NULL; STACK_DECLARE(new_vert_arr); unsigned int *new_edge_arr = NULL; STACK_DECLARE(new_edge_arr); unsigned int *old_vert_arr = MEM_callocN(sizeof(*old_vert_arr) * (size_t)numVerts, "old_vert_arr in solidify"); unsigned int *edge_users = NULL; char *edge_order = NULL; float (*vert_nors)[3] = NULL; float (*face_nors)[3] = NULL; const bool need_face_normals = (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) || (smd->flag & MOD_SOLIDIFY_EVEN); const float ofs_orig = -(((-smd->offset_fac + 1.0f) * 0.5f) * smd->offset); const float ofs_new = smd->offset + ofs_orig; const float offset_fac_vg = smd->offset_fac_vg; const float offset_fac_vg_inv = 1.0f - smd->offset_fac_vg; const bool do_flip = (smd->flag & MOD_SOLIDIFY_FLIP) != 0; const bool do_clamp = (smd->offset_clamp != 0.0f); const bool do_shell = ((smd->flag & MOD_SOLIDIFY_RIM) && (smd->flag & MOD_SOLIDIFY_NOSHELL)) == 0; /* weights */ MDeformVert *dvert; const bool defgrp_invert = (smd->flag & MOD_SOLIDIFY_VGROUP_INV) != 0; int defgrp_index; /* array size is doubled in case of using a shell */ const unsigned int stride = do_shell ? 2 : 1; modifier_get_vgroup(ob, dm, smd->defgrp_name, &dvert, &defgrp_index); orig_mvert = dm->getVertArray(dm); orig_medge = dm->getEdgeArray(dm); orig_mloop = dm->getLoopArray(dm); orig_mpoly = dm->getPolyArray(dm); if (need_face_normals) { /* calculate only face normals */ face_nors = MEM_mallocN(sizeof(*face_nors) * (size_t)numFaces, __func__); BKE_mesh_calc_normals_poly( orig_mvert, NULL, (int)numVerts, orig_mloop, orig_mpoly, (int)numLoops, (int)numFaces, face_nors, true); } STACK_INIT(new_vert_arr, numVerts * 2); STACK_INIT(new_edge_arr, numEdges * 2); if (smd->flag & MOD_SOLIDIFY_RIM) { BLI_bitmap *orig_mvert_tag = BLI_BITMAP_NEW(numVerts, __func__); unsigned int eidx; unsigned int i; #define INVALID_UNUSED ((unsigned int)-1) #define INVALID_PAIR ((unsigned int)-2) new_vert_arr = MEM_mallocN(sizeof(*new_vert_arr) * (size_t)(numVerts * 2), __func__); new_edge_arr = MEM_mallocN(sizeof(*new_edge_arr) * (size_t)((numEdges * 2) + numVerts), __func__); edge_users = MEM_mallocN(sizeof(*edge_users) * (size_t)numEdges, "solid_mod edges"); edge_order = MEM_mallocN(sizeof(*edge_order) * (size_t)numEdges, "solid_mod eorder"); /* save doing 2 loops here... */ #if 0 copy_vn_i(edge_users, numEdges, INVALID_UNUSED); #endif for (eidx = 0, ed = orig_medge; eidx < numEdges; eidx++, ed++) { edge_users[eidx] = INVALID_UNUSED; } for (i = 0, mp = orig_mpoly; i < numFaces; i++, mp++) { MLoop *ml_prev; int j; ml = orig_mloop + mp->loopstart; ml_prev = ml + (mp->totloop - 1); for (j = 0; j < mp->totloop; j++, ml++) { /* add edge user */ eidx = ml_prev->e; if (edge_users[eidx] == INVALID_UNUSED) { ed = orig_medge + eidx; BLI_assert(ELEM(ml_prev->v, ed->v1, ed->v2) && ELEM(ml->v, ed->v1, ed->v2)); edge_users[eidx] = (ml_prev->v > ml->v) == (ed->v1 < ed->v2) ? i : (i + numFaces); edge_order[eidx] = j; } else { edge_users[eidx] = INVALID_PAIR; } ml_prev = ml; } } for (eidx = 0, ed = orig_medge; eidx < numEdges; eidx++, ed++) { if (!ELEM(edge_users[eidx], INVALID_UNUSED, INVALID_PAIR)) { BLI_BITMAP_ENABLE(orig_mvert_tag, ed->v1); BLI_BITMAP_ENABLE(orig_mvert_tag, ed->v2); STACK_PUSH(new_edge_arr, eidx); newFaces++; newLoops += 4; } } for (i = 0; i < numVerts; i++) { if (BLI_BITMAP_TEST(orig_mvert_tag, i)) { old_vert_arr[i] = STACK_SIZE(new_vert_arr); STACK_PUSH(new_vert_arr, i); rimVerts++; } else { old_vert_arr[i] = INVALID_UNUSED; } } MEM_freeN(orig_mvert_tag); } if (do_shell == false) { /* only add rim vertices */ newVerts = rimVerts; /* each extruded face needs an opposite edge */ newEdges = newFaces; } else { /* (stride == 2) in this case, so no need to add newVerts/newEdges */ BLI_assert(newVerts == 0); BLI_assert(newEdges == 0); } if (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) { vert_nors = MEM_callocN(sizeof(float) * (size_t)numVerts * 3, "mod_solid_vno_hq"); dm_calc_normal(dm, face_nors, vert_nors); } result = CDDM_from_template(dm, (int)((numVerts * stride) + newVerts), (int)((numEdges * stride) + newEdges + rimVerts), 0, (int)((numLoops * stride) + newLoops), (int)((numFaces * stride) + newFaces)); mpoly = CDDM_get_polys(result); mloop = CDDM_get_loops(result); medge = CDDM_get_edges(result); mvert = CDDM_get_verts(result); if (do_shell) { DM_copy_vert_data(dm, result, 0, 0, (int)numVerts); DM_copy_vert_data(dm, result, 0, (int)numVerts, (int)numVerts); DM_copy_edge_data(dm, result, 0, 0, (int)numEdges); DM_copy_edge_data(dm, result, 0, (int)numEdges, (int)numEdges); DM_copy_loop_data(dm, result, 0, 0, (int)numLoops); DM_copy_loop_data(dm, result, 0, (int)numLoops, (int)numLoops); DM_copy_poly_data(dm, result, 0, 0, (int)numFaces); DM_copy_poly_data(dm, result, 0, (int)numFaces, (int)numFaces); } else { int i, j; DM_copy_vert_data(dm, result, 0, 0, (int)numVerts); for (i = 0, j = (int)numVerts; i < numVerts; i++) { if (old_vert_arr[i] != INVALID_UNUSED) { DM_copy_vert_data(dm, result, i, j, 1); j++; } } DM_copy_edge_data(dm, result, 0, 0, (int)numEdges); for (i = 0, j = (int)numEdges; i < numEdges; i++) { if (!ELEM(edge_users[i], INVALID_UNUSED, INVALID_PAIR)) { MEdge *ed_src, *ed_dst; DM_copy_edge_data(dm, result, i, j, 1); ed_src = &medge[i]; ed_dst = &medge[j]; ed_dst->v1 = old_vert_arr[ed_src->v1] + numVerts; ed_dst->v2 = old_vert_arr[ed_src->v2] + numVerts; j++; } } /* will be created later */ DM_copy_loop_data(dm, result, 0, 0, (int)numLoops); DM_copy_poly_data(dm, result, 0, 0, (int)numFaces); } #undef INVALID_UNUSED #undef INVALID_PAIR /* initializes: (i_end, do_shell_align, mv) */ #define INIT_VERT_ARRAY_OFFSETS(test) \ if (((ofs_new >= ofs_orig) == do_flip) == test) { \ i_end = numVerts; \ do_shell_align = true; \ mv = mvert; \ } \ else { \ if (do_shell) { \ i_end = numVerts; \ do_shell_align = true; \ } \ else { \ i_end = newVerts ; \ do_shell_align = false; \ } \ mv = &mvert[numVerts]; \ } (void)0 /* flip normals */ if (do_shell) { unsigned int i; mp = mpoly + numFaces; for (i = 0; i < dm->numPolyData; i++, mp++) { MLoop *ml2; unsigned int e; int j; /* reverses the loop direction (MLoop.v as well as custom-data) * MLoop.e also needs to be corrected too, done in a separate loop below. */ ml2 = mloop + mp->loopstart + dm->numLoopData; for (j = 0; j < mp->totloop; j++) { CustomData_copy_data(&dm->loopData, &result->loopData, mp->loopstart + j, mp->loopstart + (mp->totloop - j - 1) + dm->numLoopData, 1); } if (mat_ofs) { mp->mat_nr += mat_ofs; CLAMP(mp->mat_nr, 0, mat_nr_max); } 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 += dm->numLoopData; for (j = 0; j < mp->totloop; j++) { ml2[j].e += numEdges; ml2[j].v += numVerts; } } for (i = 0, ed = medge + numEdges; i < numEdges; i++, ed++) { ed->v1 += numVerts; ed->v2 += numVerts; } } /* note, copied vertex layers don't have flipped normals yet. do this after applying offset */ if ((smd->flag & MOD_SOLIDIFY_EVEN) == 0) { /* no even thickness, very simple */ float scalar_short; float scalar_short_vgroup; /* for clamping */ float *vert_lens = NULL; const float offset = fabsf(smd->offset) * smd->offset_clamp; const float offset_sq = offset * offset; if (do_clamp) { unsigned int i; vert_lens = MEM_mallocN(sizeof(float) * numVerts, "vert_lens"); copy_vn_fl(vert_lens, (int)numVerts, FLT_MAX); for (i = 0; i < numEdges; i++) { const float ed_len_sq = len_squared_v3v3(mvert[medge[i].v1].co, mvert[medge[i].v2].co); vert_lens[medge[i].v1] = min_ff(vert_lens[medge[i].v1], ed_len_sq); vert_lens[medge[i].v2] = min_ff(vert_lens[medge[i].v2], ed_len_sq); } } if (ofs_new != 0.0f) { unsigned int i_orig, i_end; bool do_shell_align; scalar_short = scalar_short_vgroup = ofs_new / 32767.0f; INIT_VERT_ARRAY_OFFSETS(false); for (i_orig = 0; i_orig < i_end; i_orig++, mv++) { const unsigned int i = do_shell_align ? i_orig : new_vert_arr[i_orig]; if (dvert) { MDeformVert *dv = &dvert[i]; if (defgrp_invert) scalar_short_vgroup = 1.0f - defvert_find_weight(dv, defgrp_index); else scalar_short_vgroup = defvert_find_weight(dv, defgrp_index); scalar_short_vgroup = (offset_fac_vg + (scalar_short_vgroup * offset_fac_vg_inv)) * scalar_short; } if (do_clamp) { /* always reset becaise we may have set before */ if (dvert == NULL) { scalar_short_vgroup = scalar_short; } if (vert_lens[i] < offset_sq) { float scalar = sqrtf(vert_lens[i]) / offset; scalar_short_vgroup *= scalar; } } madd_v3v3short_fl(mv->co, mv->no, scalar_short_vgroup); } } if (ofs_orig != 0.0f) { unsigned int i_orig, i_end; bool do_shell_align; scalar_short = scalar_short_vgroup = ofs_orig / 32767.0f; /* as above but swapped */ INIT_VERT_ARRAY_OFFSETS(true); for (i_orig = 0; i_orig < i_end; i_orig++, mv++) { const unsigned int i = do_shell_align ? i_orig : new_vert_arr[i_orig]; if (dvert) { MDeformVert *dv = &dvert[i]; if (defgrp_invert) scalar_short_vgroup = 1.0f - defvert_find_weight(dv, defgrp_index); else scalar_short_vgroup = defvert_find_weight(dv, defgrp_index); scalar_short_vgroup = (offset_fac_vg + (scalar_short_vgroup * offset_fac_vg_inv)) * scalar_short; } if (do_clamp) { /* always reset becaise we may have set before */ if (dvert == NULL) { scalar_short_vgroup = scalar_short; } if (vert_lens[i] < offset_sq) { float scalar = sqrtf(vert_lens[i]) / offset; scalar_short_vgroup *= scalar; } } madd_v3v3short_fl(mv->co, mv->no, scalar_short_vgroup); } } if (do_clamp) { MEM_freeN(vert_lens); } } else { #ifdef USE_NONMANIFOLD_WORKAROUND const bool check_non_manifold = (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) != 0; #endif /* same as EM_solidify() in editmesh_lib.c */ float *vert_angles = MEM_callocN(sizeof(float) * numVerts * 2, "mod_solid_pair"); /* 2 in 1 */ float *vert_accum = vert_angles + numVerts; unsigned int vidx; unsigned int i; if (vert_nors == NULL) { vert_nors = MEM_mallocN(sizeof(float) * numVerts * 3, "mod_solid_vno"); for (i = 0, mv = mvert; i < numVerts; i++, mv++) { normal_short_to_float_v3(vert_nors[i], mv->no); } } for (i = 0, mp = mpoly; i < numFaces; i++, mp++) { /* #BKE_mesh_calc_poly_angles logic is inlined here */ float nor_prev[3]; float nor_next[3]; int i_curr = mp->totloop - 1; int i_next = 0; ml = &mloop[mp->loopstart]; sub_v3_v3v3(nor_prev, mvert[ml[i_curr - 1].v].co, mvert[ml[i_curr].v].co); normalize_v3(nor_prev); while (i_next < mp->totloop) { float angle; sub_v3_v3v3(nor_next, mvert[ml[i_curr].v].co, mvert[ml[i_next].v].co); normalize_v3(nor_next); angle = angle_normalized_v3v3(nor_prev, nor_next); /* --- not related to angle calc --- */ if (angle < FLT_EPSILON) { angle = FLT_EPSILON; } vidx = ml[i_curr].v; vert_accum[vidx] += angle; #ifdef USE_NONMANIFOLD_WORKAROUND /* skip 3+ face user edges */ if ((check_non_manifold == false) || LIKELY(((orig_medge[ml[i_curr].e].flag & ME_EDGE_TMP_TAG) == 0) && ((orig_medge[ml[i_next].e].flag & ME_EDGE_TMP_TAG) == 0))) { vert_angles[vidx] += shell_v3v3_normalized_to_dist(vert_nors[vidx], face_nors[i]) * angle; } else { vert_angles[vidx] += angle; } #else vert_angles[vidx] += shell_v3v3_normalized_to_dist(vert_nors[vidx], face_nors[i]) * angle; #endif /* --- end non-angle-calc section --- */ /* step */ copy_v3_v3(nor_prev, nor_next); i_curr = i_next; i_next++; } } /* vertex group support */ if (dvert) { MDeformVert *dv = dvert; float scalar; if (defgrp_invert) { for (i = 0; i < numVerts; i++, dv++) { scalar = 1.0f - defvert_find_weight(dv, defgrp_index); scalar = offset_fac_vg + (scalar * offset_fac_vg_inv); vert_angles[i] *= scalar; } } else { for (i = 0; i < numVerts; i++, dv++) { scalar = defvert_find_weight(dv, defgrp_index); scalar = offset_fac_vg + (scalar * offset_fac_vg_inv); vert_angles[i] *= scalar; } } } if (do_clamp) { float *vert_lens_sq = MEM_mallocN(sizeof(float) * numVerts, "vert_lens"); const float offset = fabsf(smd->offset) * smd->offset_clamp; const float offset_sq = offset * offset; copy_vn_fl(vert_lens_sq, (int)numVerts, FLT_MAX); for (i = 0; i < numEdges; i++) { const float ed_len = len_squared_v3v3(mvert[medge[i].v1].co, mvert[medge[i].v2].co); vert_lens_sq[medge[i].v1] = min_ff(vert_lens_sq[medge[i].v1], ed_len); vert_lens_sq[medge[i].v2] = min_ff(vert_lens_sq[medge[i].v2], ed_len); } for (i = 0; i < numVerts; i++) { if (vert_lens_sq[i] < offset_sq) { float scalar = sqrtf(vert_lens_sq[i]) / offset; vert_angles[i] *= scalar; } } MEM_freeN(vert_lens_sq); } if (ofs_new != 0.0f) { unsigned int i_orig, i_end; bool do_shell_align; INIT_VERT_ARRAY_OFFSETS(false); for (i_orig = 0; i_orig < i_end; i_orig++, mv++) { const unsigned int i_other = do_shell_align ? i_orig : new_vert_arr[i_orig]; if (vert_accum[i_other]) { /* zero if unselected */ madd_v3_v3fl(mv->co, vert_nors[i_other], ofs_new * (vert_angles[i_other] / vert_accum[i_other])); } } } if (ofs_orig != 0.0f) { unsigned int i_orig, i_end; bool do_shell_align; /* same as above but swapped, intentional use of 'ofs_new' */ INIT_VERT_ARRAY_OFFSETS(true); for (i_orig = 0; i_orig < i_end; i_orig++, mv++) { const unsigned int i_other = do_shell_align ? i_orig : new_vert_arr[i_orig]; if (vert_accum[i_other]) { /* zero if unselected */ madd_v3_v3fl(mv->co, vert_nors[i_other], ofs_orig * (vert_angles[i_other] / vert_accum[i_other])); } } } MEM_freeN(vert_angles); } if (vert_nors) MEM_freeN(vert_nors); /* must recalculate normals with vgroups since they can displace unevenly [#26888] */ if ((dm->dirty & DM_DIRTY_NORMALS) || (smd->flag & MOD_SOLIDIFY_RIM) || dvert) { result->dirty |= DM_DIRTY_NORMALS; } else if (do_shell) { unsigned int i; /* flip vertex normals for copied verts */ mv = mvert + numVerts; for (i = 0; i < numVerts; i++, mv++) { negate_v3_short(mv->no); } } if (smd->flag & MOD_SOLIDIFY_RIM) { unsigned int i; /* bugger, need to re-calculate the normals for the new edge faces. * This could be done in many ways, but probably the quickest way * is to calculate the average normals for side faces only. * Then blend them with the normals of the edge verts. * * at the moment its easiest to allocate an entire array for every vertex, * even though we only need edge verts - campbell */ #define SOLIDIFY_SIDE_NORMALS #ifdef SOLIDIFY_SIDE_NORMALS const bool do_side_normals = !(result->dirty & DM_DIRTY_NORMALS); /* annoying to allocate these since we only need the edge verts, */ float (*edge_vert_nos)[3] = do_side_normals ? MEM_callocN(sizeof(float) * numVerts * 3, __func__) : NULL; float nor[3]; #endif const unsigned char crease_rim = smd->crease_rim * 255.0f; const unsigned char crease_outer = smd->crease_outer * 255.0f; const unsigned char crease_inner = smd->crease_inner * 255.0f; int *origindex_edge; int *orig_ed; unsigned int j; if (crease_rim || crease_outer || crease_inner) { result->cd_flag |= ME_CDFLAG_EDGE_CREASE; } /* add faces & edges */ origindex_edge = result->getEdgeDataArray(result, CD_ORIGINDEX); ed = &medge[(numEdges * stride) + newEdges]; /* start after copied edges */ orig_ed = &origindex_edge[(numEdges * stride) + newEdges]; for (i = 0; i < rimVerts; i++, ed++, orig_ed++) { ed->v1 = new_vert_arr[i]; ed->v2 = (do_shell ? new_vert_arr[i] : i) + numVerts; ed->flag |= ME_EDGEDRAW; *orig_ed = ORIGINDEX_NONE; if (crease_rim) { ed->crease = crease_rim; } } /* faces */ mp = mpoly + (numFaces * stride); ml = mloop + (numLoops * stride); j = 0; for (i = 0; i < newFaces; i++, mp++) { unsigned int eidx = new_edge_arr[i]; unsigned int fidx = edge_users[eidx]; int k1, k2; bool flip; if (fidx >= numFaces) { fidx -= numFaces; flip = true; } else { flip = false; } ed = medge + eidx; /* copy most of the face settings */ DM_copy_poly_data(dm, result, (int)fidx, (int)((numFaces * stride) + i), 1); mp->loopstart = (int)(j + (numLoops * stride)); mp->flag = mpoly[fidx].flag; /* notice we use 'mp->totloop' which is later overwritten, * we could lookup the original face but theres no point since this is a copy * and will have the same value, just take care when changing order of assignment */ k1 = mpoly[fidx].loopstart + (((edge_order[eidx] - 1) + mp->totloop) % mp->totloop); /* prev loop */ k2 = mpoly[fidx].loopstart + (edge_order[eidx]); mp->totloop = 4; CustomData_copy_data(&dm->loopData, &result->loopData, k2, (int)((numLoops * stride) + j + 0), 1); CustomData_copy_data(&dm->loopData, &result->loopData, k1, (int)((numLoops * stride) + j + 1), 1); CustomData_copy_data(&dm->loopData, &result->loopData, k1, (int)((numLoops * stride) + j + 2), 1); CustomData_copy_data(&dm->loopData, &result->loopData, k2, (int)((numLoops * stride) + j + 3), 1); if (flip == false) { ml[j].v = ed->v1; ml[j++].e = eidx; ml[j].v = ed->v2; ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v2] + newEdges; ml[j].v = (do_shell ? ed->v2 : old_vert_arr[ed->v2]) + numVerts; ml[j++].e = (do_shell ? eidx : i) + numEdges; ml[j].v = (do_shell ? ed->v1 : old_vert_arr[ed->v1]) + numVerts; ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v1] + newEdges; } else { ml[j].v = ed->v2; ml[j++].e = eidx; ml[j].v = ed->v1; ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v1] + newEdges; ml[j].v = (do_shell ? ed->v1 : old_vert_arr[ed->v1]) + numVerts; ml[j++].e = (do_shell ? eidx : i) + numEdges; ml[j].v = (do_shell ? ed->v2 : old_vert_arr[ed->v2]) + numVerts; ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v2] + newEdges; } origindex_edge[ml[j - 3].e] = ORIGINDEX_NONE; origindex_edge[ml[j - 1].e] = ORIGINDEX_NONE; /* use the next material index if option enabled */ if (mat_ofs_rim) { mp->mat_nr += mat_ofs_rim; CLAMP(mp->mat_nr, 0, mat_nr_max); } if (crease_outer) { /* crease += crease_outer; without wrapping */ char *cr = &(ed->crease); int tcr = *cr + crease_outer; *cr = tcr > 255 ? 255 : tcr; } if (crease_inner) { /* crease += crease_inner; without wrapping */ char *cr = &(medge[numEdges + (do_shell ? eidx : i)].crease); int tcr = *cr + crease_inner; *cr = tcr > 255 ? 255 : tcr; } #ifdef SOLIDIFY_SIDE_NORMALS if (do_side_normals) { normal_quad_v3(nor, mvert[ml[j - 4].v].co, mvert[ml[j - 3].v].co, mvert[ml[j - 2].v].co, mvert[ml[j - 1].v].co); add_v3_v3(edge_vert_nos[ed->v1], nor); add_v3_v3(edge_vert_nos[ed->v2], nor); } #endif } #ifdef SOLIDIFY_SIDE_NORMALS if (do_side_normals) { ed = medge + (numEdges * stride); for (i = 0; i < rimVerts; i++, ed++) { float nor_cpy[3]; short *nor_short; int k; /* note, only the first vertex (lower half of the index) is calculated */ normalize_v3_v3(nor_cpy, edge_vert_nos[ed->v1]); for (k = 0; k < 2; k++) { /* loop over both verts of the edge */ nor_short = mvert[*(&ed->v1 + k)].no; normal_short_to_float_v3(nor, nor_short); add_v3_v3(nor, nor_cpy); normalize_v3(nor); normal_float_to_short_v3(nor_short, nor); } } MEM_freeN(edge_vert_nos); } #endif MEM_freeN(new_vert_arr); MEM_freeN(new_edge_arr); MEM_freeN(edge_users); MEM_freeN(edge_order); } if (old_vert_arr) MEM_freeN(old_vert_arr); if (face_nors) MEM_freeN(face_nors); if (numFaces == 0 && numEdges != 0) { modifier_setError(md, "Faces needed for useful output"); } return result; }
static void deformVerts_do(HookModifierData *hmd, Object *ob, DerivedMesh *dm, float (*vertexCos)[3], int numVerts) { bPoseChannel *pchan = BKE_pose_channel_find_name(hmd->object->pose, hmd->subtarget); float dmat[4][4]; int i, *index_pt; struct HookData_cb hd; if (hmd->curfalloff == NULL) { /* should never happen, but bad lib linking could cause it */ hmd->curfalloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); } if (hmd->curfalloff) { curvemapping_initialize(hmd->curfalloff); } /* Generic data needed for applying per-vertex calculations (initialize all members) */ hd.vertexCos = vertexCos; modifier_get_vgroup(ob, dm, hmd->name, &hd.dvert, &hd.defgrp_index); hd.curfalloff = hmd->curfalloff; hd.falloff_type = hmd->falloff_type; hd.falloff = (hmd->falloff_type == eHook_Falloff_None) ? 0.0f : hmd->falloff; hd.falloff_sq = SQUARE(hd.falloff); hd.fac_orig = hmd->force; hd.use_falloff = (hd.falloff_sq != 0.0f); hd.use_uniform = (hmd->flag & MOD_HOOK_UNIFORM_SPACE) != 0; if (hd.use_uniform) { copy_m3_m4(hd.mat_uniform, hmd->parentinv); mul_v3_m3v3(hd.cent, hd.mat_uniform, hmd->cent); } else { unit_m3(hd.mat_uniform); /* unused */ copy_v3_v3(hd.cent, hmd->cent); } /* get world-space matrix of target, corrected for the space the verts are in */ if (hmd->subtarget[0] && pchan) { /* bone target if there's a matching pose-channel */ mul_m4_m4m4(dmat, hmd->object->obmat, pchan->pose_mat); } else { /* just object target */ copy_m4_m4(dmat, hmd->object->obmat); } invert_m4_m4(ob->imat, ob->obmat); mul_m4_series(hd.mat, ob->imat, dmat, hmd->parentinv); /* --- done with 'hd' init --- */ /* Regarding index range checking below. * * This should always be true and I don't generally like * "paranoid" style code like this, but old files can have * indices that are out of range because old blender did * not correct them on exit editmode. - zr */ if (hmd->force == 0.0f) { /* do nothing, avoid annoying checks in the loop */ } else if (hmd->indexar) { /* vertex indices? */ const int *origindex_ar; /* if DerivedMesh is present and has original index data, use it */ if (dm && (origindex_ar = dm->getVertDataArray(dm, CD_ORIGINDEX))) { for (i = 0, index_pt = hmd->indexar; i < hmd->totindex; i++, index_pt++) { if (*index_pt < numVerts) { int j; for (j = 0; j < numVerts; j++) { if (origindex_ar[j] == *index_pt) { hook_co_apply(&hd, j); } } } } } else { /* missing dm or ORIGINDEX */ for (i = 0, index_pt = hmd->indexar; i < hmd->totindex; i++, index_pt++) { if (*index_pt < numVerts) { hook_co_apply(&hd, *index_pt); } } } } else if (hd.dvert) { /* vertex group hook */ for (i = 0; i < numVerts; i++) { hook_co_apply(&hd, i); } } }
static void sphere_do( CastModifierData *cmd, Object *ob, DerivedMesh *dm, float (*vertexCos)[3], int numVerts) { MDeformVert *dvert = NULL; Object *ctrl_ob = NULL; int i, defgrp_index; int has_radius = 0; short flag, type; float fac, facm, len = 0.0f; float vec[3], center[3] = {0.0f, 0.0f, 0.0f}; float mat[4][4], imat[4][4]; fac = cmd->fac; facm = 1.0f - fac; flag = cmd->flag; type = cmd->type; /* projection type: sphere or cylinder */ if (type == MOD_CAST_TYPE_CYLINDER) flag &= ~MOD_CAST_Z; ctrl_ob = cmd->object; /* spherify's center is {0, 0, 0} (the ob's own center in its local * space), by default, but if the user defined a control object, * we use its location, transformed to ob's local space */ if (ctrl_ob) { if(flag & MOD_CAST_USE_OB_TRANSFORM) { invert_m4_m4(ctrl_ob->imat, ctrl_ob->obmat); mul_m4_m4m4(mat, ob->obmat, ctrl_ob->imat); invert_m4_m4(imat, mat); } invert_m4_m4(ob->imat, ob->obmat); mul_v3_m4v3(center, ob->imat, ctrl_ob->obmat[3]); } /* now we check which options the user wants */ /* 1) (flag was checked in the "if (ctrl_ob)" block above) */ /* 2) cmd->radius > 0.0f: only the vertices within this radius from * the center of the effect should be deformed */ if (cmd->radius > FLT_EPSILON) has_radius = 1; /* 3) if we were given a vertex group name, * only those vertices should be affected */ modifier_get_vgroup(ob, dm, cmd->defgrp_name, &dvert, &defgrp_index); if(flag & MOD_CAST_SIZE_FROM_RADIUS) { len = cmd->radius; } else { len = cmd->size; } if(len <= 0) { for (i = 0; i < numVerts; i++) { len += len_v3v3(center, vertexCos[i]); } len /= numVerts; if (len == 0.0f) len = 10.0f; } /* ready to apply the effect, one vertex at a time; * tiny optimization: the code is separated (with parts repeated) * in two possible cases: * with or w/o a vgroup. With lots of if's in the code below, * further optimizations are possible, if needed */ if (dvert) { /* with a vgroup */ float fac_orig = fac; for (i = 0; i < numVerts; i++) { MDeformWeight *dw = NULL; int j; float tmp_co[3]; copy_v3_v3(tmp_co, vertexCos[i]); if(ctrl_ob) { if(flag & MOD_CAST_USE_OB_TRANSFORM) { mul_m4_v3(mat, tmp_co); } else { sub_v3_v3(tmp_co, center); } } copy_v3_v3(vec, tmp_co); if (type == MOD_CAST_TYPE_CYLINDER) vec[2] = 0.0f; if (has_radius) { if (len_v3(vec) > cmd->radius) continue; } for (j = 0; j < dvert[i].totweight; ++j) { if(dvert[i].dw[j].def_nr == defgrp_index) { dw = &dvert[i].dw[j]; break; } } if (!dw) continue; fac = fac_orig * dw->weight; facm = 1.0f - fac; normalize_v3(vec); if (flag & MOD_CAST_X) tmp_co[0] = fac*vec[0]*len + facm*tmp_co[0]; if (flag & MOD_CAST_Y) tmp_co[1] = fac*vec[1]*len + facm*tmp_co[1]; if (flag & MOD_CAST_Z) tmp_co[2] = fac*vec[2]*len + facm*tmp_co[2]; if(ctrl_ob) { if(flag & MOD_CAST_USE_OB_TRANSFORM) { mul_m4_v3(imat, tmp_co); } else { add_v3_v3(tmp_co, center); } } copy_v3_v3(vertexCos[i], tmp_co); } return; } /* no vgroup */ for (i = 0; i < numVerts; i++) { float tmp_co[3]; copy_v3_v3(tmp_co, vertexCos[i]); if(ctrl_ob) { if(flag & MOD_CAST_USE_OB_TRANSFORM) { mul_m4_v3(mat, tmp_co); } else { sub_v3_v3(tmp_co, center); } } copy_v3_v3(vec, tmp_co); if (type == MOD_CAST_TYPE_CYLINDER) vec[2] = 0.0f; if (has_radius) { if (len_v3(vec) > cmd->radius) continue; } normalize_v3(vec); if (flag & MOD_CAST_X) tmp_co[0] = fac*vec[0]*len + facm*tmp_co[0]; if (flag & MOD_CAST_Y) tmp_co[1] = fac*vec[1]*len + facm*tmp_co[1]; if (flag & MOD_CAST_Z) tmp_co[2] = fac*vec[2]*len + facm*tmp_co[2]; if(ctrl_ob) { if(flag & MOD_CAST_USE_OB_TRANSFORM) { mul_m4_v3(imat, tmp_co); } else { add_v3_v3(tmp_co, center); } } copy_v3_v3(vertexCos[i], tmp_co); } }
static void deformVerts_do(HookModifierData *hmd, Object *ob, DerivedMesh *dm, float (*vertexCos)[3], int numVerts) { bPoseChannel *pchan = BKE_pose_channel_find_name(hmd->object->pose, hmd->subtarget); float vec[3], mat[4][4], dmat[4][4]; int i, *index_pt; const float falloff_squared = hmd->falloff * hmd->falloff; /* for faster comparisons */ MDeformVert *dvert; int defgrp_index, max_dvert; /* get world-space matrix of target, corrected for the space the verts are in */ if (hmd->subtarget[0] && pchan) { /* bone target if there's a matching pose-channel */ mul_m4_m4m4(dmat, hmd->object->obmat, pchan->pose_mat); } else { /* just object target */ copy_m4_m4(dmat, hmd->object->obmat); } invert_m4_m4(ob->imat, ob->obmat); mul_serie_m4(mat, ob->imat, dmat, hmd->parentinv, NULL, NULL, NULL, NULL, NULL); modifier_get_vgroup(ob, dm, hmd->name, &dvert, &defgrp_index); max_dvert = (dvert) ? numVerts : 0; /* Regarding index range checking below. * * This should always be true and I don't generally like * "paranoid" style code like this, but old files can have * indices that are out of range because old blender did * not correct them on exit editmode. - zr */ if (hmd->force == 0.0f) { /* do nothing, avoid annoying checks in the loop */ } else if (hmd->indexar) { /* vertex indices? */ const float fac_orig = hmd->force; float fac; const int *origindex_ar; /* if DerivedMesh is present and has original index data, use it */ if (dm && (origindex_ar = dm->getVertDataArray(dm, CD_ORIGINDEX))) { for (i = 0, index_pt = hmd->indexar; i < hmd->totindex; i++, index_pt++) { if (*index_pt < numVerts) { int j; for (j = 0; j < numVerts; j++) { if (origindex_ar[j] == *index_pt) { float *co = vertexCos[j]; if ((fac = hook_falloff(hmd->cent, co, falloff_squared, fac_orig))) { if (dvert) fac *= defvert_find_weight(dvert + j, defgrp_index); if (fac) { mul_v3_m4v3(vec, mat, co); interp_v3_v3v3(co, co, vec, fac); } } } } } } } else { /* missing dm or ORIGINDEX */ for (i = 0, index_pt = hmd->indexar; i < hmd->totindex; i++, index_pt++) { if (*index_pt < numVerts) { float *co = vertexCos[*index_pt]; if ((fac = hook_falloff(hmd->cent, co, falloff_squared, fac_orig))) { if (dvert) fac *= defvert_find_weight(dvert + (*index_pt), defgrp_index); if (fac) { mul_v3_m4v3(vec, mat, co); interp_v3_v3v3(co, co, vec, fac); } } } } } } else if (dvert) { /* vertex group hook */ const float fac_orig = hmd->force; for (i = 0; i < max_dvert; i++, dvert++) { float fac; float *co = vertexCos[i]; if ((fac = hook_falloff(hmd->cent, co, falloff_squared, fac_orig))) { fac *= defvert_find_weight(dvert, defgrp_index); if (fac) { mul_v3_m4v3(vec, mat, co); interp_v3_v3v3(co, co, vec, fac); } } } } }
static void smoothModifier_do( SmoothModifierData *smd, Object *ob, DerivedMesh *dm, float (*vertexCos)[3], int numVerts) { MDeformVert *dvert = NULL; MEdge *medges = NULL; int i, j, numDMEdges, defgrp_index; unsigned char *uctmp; float *ftmp, fac, facm; ftmp = (float *)MEM_callocN(3 * sizeof(float) * numVerts, "smoothmodifier_f"); if (!ftmp) return; uctmp = (unsigned char *)MEM_callocN(sizeof(unsigned char) * numVerts, "smoothmodifier_uc"); if (!uctmp) { if (ftmp) MEM_freeN(ftmp); return; } fac = smd->fac; facm = 1 - fac; if (dm->getNumVerts(dm) == numVerts) { medges = dm->getEdgeArray(dm); numDMEdges = dm->getNumEdges(dm); } else { medges = NULL; numDMEdges = 0; } modifier_get_vgroup(ob, dm, smd->defgrp_name, &dvert, &defgrp_index); /* NOTICE: this can be optimized a little bit by moving the * if (dvert) out of the loop, if needed */ for (j = 0; j < smd->repeat; j++) { for (i = 0; i < numDMEdges; i++) { float fvec[3]; float *v1, *v2; unsigned int idx1, idx2; idx1 = medges[i].v1; idx2 = medges[i].v2; v1 = vertexCos[idx1]; v2 = vertexCos[idx2]; mid_v3_v3v3(fvec, v1, v2); v1 = &ftmp[idx1 * 3]; v2 = &ftmp[idx2 * 3]; if (uctmp[idx1] < 255) { uctmp[idx1]++; add_v3_v3(v1, fvec); } if (uctmp[idx2] < 255) { uctmp[idx2]++; add_v3_v3(v2, fvec); } } if (dvert) { MDeformVert *dv = dvert; for (i = 0; i < numVerts; i++, dv++) { float f, fm, facw, *fp, *v; short flag = smd->flag; v = vertexCos[i]; fp = &ftmp[i * 3]; f = defvert_find_weight(dv, defgrp_index); if (f <= 0.0f) continue; f *= fac; fm = 1.0f - f; /* fp is the sum of uctmp[i] verts, so must be averaged */ facw = 0.0f; if (uctmp[i]) facw = f / (float)uctmp[i]; if (flag & MOD_SMOOTH_X) v[0] = fm * v[0] + facw * fp[0]; if (flag & MOD_SMOOTH_Y) v[1] = fm * v[1] + facw * fp[1]; if (flag & MOD_SMOOTH_Z) v[2] = fm * v[2] + facw * fp[2]; } } else { /* no vertex group */ for (i = 0; i < numVerts; i++) { float facw, *fp, *v; short flag = smd->flag; v = vertexCos[i]; fp = &ftmp[i * 3]; /* fp is the sum of uctmp[i] verts, so must be averaged */ facw = 0.0f; if (uctmp[i]) facw = fac / (float)uctmp[i]; if (flag & MOD_SMOOTH_X) v[0] = facm * v[0] + facw * fp[0]; if (flag & MOD_SMOOTH_Y) v[1] = facm * v[1] + facw * fp[1]; if (flag & MOD_SMOOTH_Z) v[2] = facm * v[2] + facw * fp[2]; } } memset(ftmp, 0, 3 * sizeof(float) * numVerts); memset(uctmp, 0, sizeof(unsigned char) * numVerts); } MEM_freeN(ftmp); MEM_freeN(uctmp); }
/* simple deform modifier */ static void SimpleDeformModifier_do( SimpleDeformModifierData *smd, struct Object *ob, struct DerivedMesh *dm, float (*vertexCos)[3], int numVerts) { const float base_limit[2] = {0.0f, 0.0f}; int i; float smd_limit[2], smd_factor; SpaceTransform *transf = NULL, tmp_transf; void (*simpleDeform_callback)(const float factor, const int axis, const float dcut[3], float co[3]) = NULL; /* Mode callback */ int vgroup; MDeformVert *dvert; /* This is historically the lock axis, _not_ the deform axis as the name would imply */ const int deform_axis = smd->deform_axis; int lock_axis = smd->axis; if (smd->mode == MOD_SIMPLEDEFORM_MODE_BEND) { /* Bend mode shouldn't have any lock axis */ lock_axis = 0; } else { /* Don't lock axis if it is the chosen deform axis, as this flattens * the geometry */ if (deform_axis == 0) { lock_axis &= ~MOD_SIMPLEDEFORM_LOCK_AXIS_X; } if (deform_axis == 1) { lock_axis &= ~MOD_SIMPLEDEFORM_LOCK_AXIS_Y; } if (deform_axis == 2) { lock_axis &= ~MOD_SIMPLEDEFORM_LOCK_AXIS_Z; } } /* Safe-check */ if (smd->origin == ob) smd->origin = NULL; /* No self references */ if (smd->limit[0] < 0.0f) smd->limit[0] = 0.0f; if (smd->limit[0] > 1.0f) smd->limit[0] = 1.0f; smd->limit[0] = min_ff(smd->limit[0], smd->limit[1]); /* Upper limit >= than lower limit */ /* Calculate matrixs do convert between coordinate spaces */ if (smd->origin) { transf = &tmp_transf; BLI_SPACE_TRANSFORM_SETUP(transf, ob, smd->origin); } /* Update limits if needed */ int limit_axis = deform_axis; if (smd->mode == MOD_SIMPLEDEFORM_MODE_BEND) { /* Bend is a special case. */ switch (deform_axis) { case 0: ATTR_FALLTHROUGH; case 1: limit_axis = 2; break; default: limit_axis = 0; } } { float lower = FLT_MAX; float upper = -FLT_MAX; for (i = 0; i < numVerts; i++) { float tmp[3]; copy_v3_v3(tmp, vertexCos[i]); if (transf) { BLI_space_transform_apply(transf, tmp); } lower = min_ff(lower, tmp[limit_axis]); upper = max_ff(upper, tmp[limit_axis]); } /* SMD values are normalized to the BV, calculate the absolute values */ smd_limit[1] = lower + (upper - lower) * smd->limit[1]; smd_limit[0] = lower + (upper - lower) * smd->limit[0]; smd_factor = smd->factor / max_ff(FLT_EPSILON, smd_limit[1] - smd_limit[0]); } switch (smd->mode) { case MOD_SIMPLEDEFORM_MODE_TWIST: simpleDeform_callback = simpleDeform_twist; break; case MOD_SIMPLEDEFORM_MODE_BEND: simpleDeform_callback = simpleDeform_bend; break; case MOD_SIMPLEDEFORM_MODE_TAPER: simpleDeform_callback = simpleDeform_taper; break; case MOD_SIMPLEDEFORM_MODE_STRETCH: simpleDeform_callback = simpleDeform_stretch; break; default: return; /* No simpledeform mode? */ } if (smd->mode == MOD_SIMPLEDEFORM_MODE_BEND) { if (fabsf(smd_factor) < BEND_EPS) { return; } } modifier_get_vgroup(ob, dm, smd->vgroup_name, &dvert, &vgroup); const bool invert_vgroup = (smd->flag & MOD_SIMPLEDEFORM_FLAG_INVERT_VGROUP) != 0; const uint *axis_map = axis_map_table[(smd->mode != MOD_SIMPLEDEFORM_MODE_BEND) ? deform_axis : 2]; for (i = 0; i < numVerts; i++) { float weight = defvert_array_find_weight_safe(dvert, i, vgroup); if (invert_vgroup) { weight = 1.0f - weight; } if (weight != 0.0f) { float co[3], dcut[3] = {0.0f, 0.0f, 0.0f}; if (transf) { BLI_space_transform_apply(transf, vertexCos[i]); } copy_v3_v3(co, vertexCos[i]); /* Apply axis limits, and axis mappings */ if (lock_axis & MOD_SIMPLEDEFORM_LOCK_AXIS_X) { axis_limit(0, base_limit, co, dcut); } if (lock_axis & MOD_SIMPLEDEFORM_LOCK_AXIS_Y) { axis_limit(1, base_limit, co, dcut); } if (lock_axis & MOD_SIMPLEDEFORM_LOCK_AXIS_Z) { axis_limit(2, base_limit, co, dcut); } axis_limit(limit_axis, smd_limit, co, dcut); /* apply the deform to a mapped copy of the vertex, and then re-map it back. */ float co_remap[3]; float dcut_remap[3]; copy_v3_v3_map(co_remap, co, axis_map); copy_v3_v3_map(dcut_remap, dcut, axis_map); simpleDeform_callback(smd_factor, deform_axis, dcut_remap, co_remap); /* apply deform */ copy_v3_v3_unmap(co, co_remap, axis_map); interp_v3_v3v3(vertexCos[i], vertexCos[i], co, weight); /* Use vertex weight has coef of linear interpolation */ if (transf) { BLI_space_transform_invert(transf, vertexCos[i]); } } } }
static void laplaciansmoothModifier_do( LaplacianSmoothModifierData *smd, Object *ob, DerivedMesh *dm, float (*vertexCos)[3], int numVerts) { LaplacianSystem *sys; MDeformVert *dvert = NULL; MDeformVert *dv = NULL; float w, wpaint; int i, iter; int defgrp_index; DM_ensure_tessface(dm); sys = init_laplacian_system(dm->getNumEdges(dm), dm->getNumTessFaces(dm), numVerts); if (!sys) { return; } sys->mfaces = dm->getTessFaceArray(dm); sys->medges = dm->getEdgeArray(dm); sys->vertexCos = vertexCos; sys->min_area = 0.00001f; modifier_get_vgroup(ob, dm, smd->defgrp_name, &dvert, &defgrp_index); sys->vert_centroid[0] = 0.0f; sys->vert_centroid[1] = 0.0f; sys->vert_centroid[2] = 0.0f; memset_laplacian_system(sys, 0); #ifdef OPENNL_THREADING_HACK modifier_opennl_lock(); #endif nlNewContext(); sys->context = nlGetCurrent(); nlSolverParameteri(NL_NB_VARIABLES, numVerts); nlSolverParameteri(NL_LEAST_SQUARES, NL_TRUE); nlSolverParameteri(NL_NB_ROWS, numVerts); nlSolverParameteri(NL_NB_RIGHT_HAND_SIDES, 3); init_laplacian_matrix(sys); for (iter = 0; iter < smd->repeat; iter++) { nlBegin(NL_SYSTEM); for (i = 0; i < numVerts; i++) { nlSetVariable(0, i, vertexCos[i][0]); nlSetVariable(1, i, vertexCos[i][1]); nlSetVariable(2, i, vertexCos[i][2]); if (iter == 0) { add_v3_v3(sys->vert_centroid, vertexCos[i]); } } if (iter == 0 && numVerts > 0) { mul_v3_fl(sys->vert_centroid, 1.0f / (float)numVerts); } nlBegin(NL_MATRIX); dv = dvert; for (i = 0; i < numVerts; i++) { nlRightHandSideSet(0, i, vertexCos[i][0]); nlRightHandSideSet(1, i, vertexCos[i][1]); nlRightHandSideSet(2, i, vertexCos[i][2]); if (iter == 0) { if (dv) { wpaint = defvert_find_weight(dv, defgrp_index); dv++; } else { wpaint = 1.0f; } if (sys->zerola[i] == 0) { if (smd->flag & MOD_LAPLACIANSMOOTH_NORMALIZED) { w = sys->vweights[i]; sys->vweights[i] = (w == 0.0f) ? 0.0f : -fabsf(smd->lambda) * wpaint / w; w = sys->vlengths[i]; sys->vlengths[i] = (w == 0.0f) ? 0.0f : -fabsf(smd->lambda_border) * wpaint * 2.0f / w; if (sys->numNeEd[i] == sys->numNeFa[i]) { nlMatrixAdd(i, i, 1.0f + fabsf(smd->lambda) * wpaint); } else { nlMatrixAdd(i, i, 1.0f + fabsf(smd->lambda_border) * wpaint * 2.0f); } } else { w = sys->vweights[i] * sys->ring_areas[i]; sys->vweights[i] = (w == 0.0f) ? 0.0f : -fabsf(smd->lambda) * wpaint / (4.0f * w); w = sys->vlengths[i]; sys->vlengths[i] = (w == 0.0f) ? 0.0f : -fabsf(smd->lambda_border) * wpaint * 2.0f / w; if (sys->numNeEd[i] == sys->numNeFa[i]) { nlMatrixAdd(i, i, 1.0f + fabsf(smd->lambda) * wpaint / (4.0f * sys->ring_areas[i])); } else { nlMatrixAdd(i, i, 1.0f + fabsf(smd->lambda_border) * wpaint * 2.0f); } } } else { nlMatrixAdd(i, i, 1.0f); } } } if (iter == 0) { fill_laplacian_matrix(sys); } nlEnd(NL_MATRIX); nlEnd(NL_SYSTEM); if (nlSolveAdvanced(NULL, NL_TRUE)) { validate_solution(sys, smd->flag, smd->lambda, smd->lambda_border); } } nlDeleteContext(sys->context); sys->context = NULL; #ifdef OPENNL_THREADING_HACK modifier_opennl_unlock(); #endif delete_laplacian_system(sys); }
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *dm, ModifierApplyFlag UNUSED(flag)) { UVWarpModifierData *umd = (UVWarpModifierData *) md; int i, numPolys, numLoops; MPoly *mpoly; MLoop *mloop; MLoopUV *mloopuv; MDeformVert *dvert; int defgrp_index; char uvname[MAX_CUSTOMDATA_LAYER_NAME]; float mat_src[4][4]; float mat_dst[4][4]; float imat_dst[4][4]; float warp_mat[4][4]; const int axis_u = umd->axis_u; const int axis_v = umd->axis_v; /* make sure there are UV Maps available */ if (!CustomData_has_layer(&dm->loopData, CD_MLOOPUV)) { return dm; } else if (ELEM(NULL, umd->object_src, umd->object_dst)) { modifier_setError(md, "From/To objects must be set"); return dm; } /* make sure anything moving UVs is available */ matrix_from_obj_pchan(mat_src, umd->object_src, umd->bone_src); matrix_from_obj_pchan(mat_dst, umd->object_dst, umd->bone_dst); invert_m4_m4(imat_dst, mat_dst); mul_m4_m4m4(warp_mat, imat_dst, mat_src); /* apply warp */ if (!is_zero_v2(umd->center)) { float mat_cent[4][4]; float imat_cent[4][4]; unit_m4(mat_cent); mat_cent[3][axis_u] = umd->center[0]; mat_cent[3][axis_v] = umd->center[1]; invert_m4_m4(imat_cent, mat_cent); mul_m4_m4m4(warp_mat, warp_mat, imat_cent); mul_m4_m4m4(warp_mat, mat_cent, warp_mat); } /* make sure we're using an existing layer */ CustomData_validate_layer_name(&dm->loopData, CD_MLOOPUV, umd->uvlayer_name, uvname); numPolys = dm->getNumPolys(dm); numLoops = dm->getNumLoops(dm); mpoly = dm->getPolyArray(dm); mloop = dm->getLoopArray(dm); /* make sure we are not modifying the original UV map */ mloopuv = CustomData_duplicate_referenced_layer_named(&dm->loopData, CD_MLOOPUV, uvname, numLoops); modifier_get_vgroup(ob, dm, umd->vgroup_name, &dvert, &defgrp_index); if (dvert) { #pragma omp parallel for if (numPolys > OMP_LIMIT) for (i = 0; i < numPolys; i++) { float uv[2]; MPoly *mp = &mpoly[i]; MLoop *ml = &mloop[mp->loopstart]; MLoopUV *mluv = &mloopuv[mp->loopstart]; int l; for (l = 0; l < mp->totloop; l++, ml++, mluv++) { const float weight = defvert_find_weight(&dvert[ml->v], defgrp_index); uv_warp_from_mat4_pair(uv, mluv->uv, warp_mat, axis_u, axis_v); interp_v2_v2v2(mluv->uv, mluv->uv, uv, weight); } } } else { #pragma omp parallel for if (numPolys > OMP_LIMIT) for (i = 0; i < numPolys; i++) { MPoly *mp = &mpoly[i]; // MLoop *ml = &mloop[mp->loopstart]; MLoopUV *mluv = &mloopuv[mp->loopstart]; int l; for (l = 0; l < mp->totloop; l++, /* ml++, */ mluv++) { uv_warp_from_mat4_pair(mluv->uv, mluv->uv, warp_mat, axis_u, axis_v); } } } dm->dirty |= DM_DIRTY_TESS_CDLAYERS; return dm; }
/* dm must be a CDDerivedMesh */ static void displaceModifier_do( DisplaceModifierData *dmd, Object *ob, DerivedMesh *dm, float (*vertexCos)[3], int numVerts) { int i; MVert *mvert; MDeformVert *dvert; int direction = dmd->direction; int defgrp_index; float (*tex_co)[3]; float weight = 1.0f; /* init value unused but some compilers may complain */ const float delta_fixed = 1.0f - dmd->midlevel; /* when no texture is used, we fallback to white */ float (*vert_clnors)[3] = NULL; if (!dmd->texture && dmd->direction == MOD_DISP_DIR_RGB_XYZ) return; if (dmd->strength == 0.0f) return; mvert = CDDM_get_verts(dm); modifier_get_vgroup(ob, dm, dmd->defgrp_name, &dvert, &defgrp_index); if (dmd->texture) { tex_co = MEM_callocN(sizeof(*tex_co) * numVerts, "displaceModifier_do tex_co"); get_texture_coords((MappingInfoModifierData *)dmd, ob, dm, vertexCos, tex_co, numVerts); modifier_init_texture(dmd->modifier.scene, dmd->texture); } else { tex_co = NULL; } if (direction == MOD_DISP_DIR_CLNOR) { CustomData *ldata = dm->getLoopDataLayout(dm); if (CustomData_has_layer(ldata, CD_CUSTOMLOOPNORMAL)) { float (*clnors)[3] = NULL; if ((dm->dirty & DM_DIRTY_NORMALS) || !CustomData_has_layer(ldata, CD_NORMAL)) { dm->calcLoopNormals(dm, true, (float)M_PI); } clnors = CustomData_get_layer(ldata, CD_NORMAL); vert_clnors = MEM_mallocN(sizeof(*vert_clnors) * (size_t)numVerts, __func__); BKE_mesh_normals_loop_to_vertex(numVerts, dm->getLoopArray(dm), dm->getNumLoops(dm), (const float (*)[3])clnors, vert_clnors); } else { direction = MOD_DISP_DIR_NOR; } } for (i = 0; i < numVerts; i++) { TexResult texres; float strength = dmd->strength; float delta; if (dvert) { weight = defvert_find_weight(dvert + i, defgrp_index); if (weight == 0.0f) continue; } if (dmd->texture) { texres.nor = NULL; BKE_texture_get_value(dmd->modifier.scene, dmd->texture, tex_co[i], &texres, false); delta = texres.tin - dmd->midlevel; } else { delta = delta_fixed; /* (1.0f - dmd->midlevel) */ /* never changes */ } if (dvert) strength *= weight; delta *= strength; CLAMP(delta, -10000, 10000); switch (direction) { case MOD_DISP_DIR_X: vertexCos[i][0] += delta; break; case MOD_DISP_DIR_Y: vertexCos[i][1] += delta; break; case MOD_DISP_DIR_Z: vertexCos[i][2] += delta; break; case MOD_DISP_DIR_RGB_XYZ: vertexCos[i][0] += (texres.tr - dmd->midlevel) * strength; vertexCos[i][1] += (texres.tg - dmd->midlevel) * strength; vertexCos[i][2] += (texres.tb - dmd->midlevel) * strength; break; case MOD_DISP_DIR_NOR: vertexCos[i][0] += delta * (mvert[i].no[0] / 32767.0f); vertexCos[i][1] += delta * (mvert[i].no[1] / 32767.0f); vertexCos[i][2] += delta * (mvert[i].no[2] / 32767.0f); break; case MOD_DISP_DIR_CLNOR: madd_v3_v3fl(vertexCos[i], vert_clnors[i], delta); break; } } if (tex_co) { MEM_freeN(tex_co); } if (vert_clnors) { MEM_freeN(vert_clnors); } }
static void warpModifier_do(WarpModifierData *wmd, Object *ob, DerivedMesh *dm, float (*vertexCos)[3], int numVerts) { 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]; 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; modifier_get_vgroup(ob, dm, wmd->defgrp_name, &dvert, &defgrp_index); 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; if (wmd->texture) { tex_co = MEM_mallocN(sizeof(*tex_co) * numVerts, "warpModifier_do tex_co"); get_texture_coords((MappingInfoModifierData *)wmd, ob, dm, vertexCos, tex_co, numVerts); modifier_init_texture(wmd->modifier.scene, wmd->texture); } for (i = 0; i < numVerts; i++) { float *co = vertexCos[i]; if (wmd->falloff_type == eWarp_Falloff_None || ((fac = len_v3v3(co, mat_from[3])) < wmd->falloff_radius && (fac = (wmd->falloff_radius - fac) / wmd->falloff_radius))) { /* skip if no vert group found */ if (dvert && defgrp_index != -1) { dv = &dvert[i]; if (dv) { weight = defvert_find_weight(dv, defgrp_index) * strength; if (weight <= 0.0f) /* Should never occure... */ 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 = (float)sqrt(fac); break; case eWarp_Falloff_Linear: /* pass */ break; case eWarp_Falloff_Const: fac = 1.0f; break; case eWarp_Falloff_Sphere: fac = (float)sqrt(2 * fac - fac * fac); break; } fac *= weight; if (tex_co) { TexResult texres; texres.nor = NULL; get_texture_value(wmd->modifier.scene, wmd->texture, tex_co[i], &texres, false); fac *= texres.tin; } /* into the 'from' objects space */ mul_m4_v3(mat_from_inv, co); if (fac >= 1.0f) { mul_m4_v3(mat_final, co); } else if (fac > 0.0f) { 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); }
/* simple deform modifier */ static void SimpleDeformModifier_do(SimpleDeformModifierData *smd, struct Object *ob, struct DerivedMesh *dm, float (*vertexCos)[3], int numVerts) { static const float lock_axis[2] = {0.0f, 0.0f}; int i; int limit_axis = 0; float smd_limit[2], smd_factor; SpaceTransform *transf = NULL, tmp_transf; void (*simpleDeform_callback)(const float factor, const float dcut[3], float co[3]) = NULL; /* Mode callback */ int vgroup; MDeformVert *dvert; /* Safe-check */ if (smd->origin == ob) smd->origin = NULL; /* No self references */ if (smd->limit[0] < 0.0f) smd->limit[0] = 0.0f; if (smd->limit[0] > 1.0f) smd->limit[0] = 1.0f; smd->limit[0] = min_ff(smd->limit[0], smd->limit[1]); /* Upper limit >= than lower limit */ /* Calculate matrixs do convert between coordinate spaces */ if (smd->origin) { transf = &tmp_transf; if (smd->originOpts & MOD_SIMPLEDEFORM_ORIGIN_LOCAL) { space_transform_from_matrixs(transf, ob->obmat, smd->origin->obmat); } else { copy_m4_m4(transf->local2target, smd->origin->obmat); invert_m4_m4(transf->target2local, transf->local2target); } } /* Setup vars, * Bend limits on X.. all other modes limit on Z */ limit_axis = (smd->mode == MOD_SIMPLEDEFORM_MODE_BEND) ? 0 : 2; /* Update limits if needed */ { float lower = FLT_MAX; float upper = -FLT_MAX; for (i = 0; i < numVerts; i++) { float tmp[3]; copy_v3_v3(tmp, vertexCos[i]); if (transf) space_transform_apply(transf, tmp); lower = min_ff(lower, tmp[limit_axis]); upper = max_ff(upper, tmp[limit_axis]); } /* SMD values are normalized to the BV, calculate the absolut values */ smd_limit[1] = lower + (upper - lower) * smd->limit[1]; smd_limit[0] = lower + (upper - lower) * smd->limit[0]; smd_factor = smd->factor / max_ff(FLT_EPSILON, smd_limit[1] - smd_limit[0]); } modifier_get_vgroup(ob, dm, smd->vgroup_name, &dvert, &vgroup); switch (smd->mode) { case MOD_SIMPLEDEFORM_MODE_TWIST: simpleDeform_callback = simpleDeform_twist; break; case MOD_SIMPLEDEFORM_MODE_BEND: simpleDeform_callback = simpleDeform_bend; break; case MOD_SIMPLEDEFORM_MODE_TAPER: simpleDeform_callback = simpleDeform_taper; break; case MOD_SIMPLEDEFORM_MODE_STRETCH: simpleDeform_callback = simpleDeform_stretch; break; default: return; /* No simpledeform mode? */ } for (i = 0; i < numVerts; i++) { float weight = defvert_array_find_weight_safe(dvert, i, vgroup); if (weight != 0.0f) { float co[3], dcut[3] = {0.0f, 0.0f, 0.0f}; if (transf) { space_transform_apply(transf, vertexCos[i]); } copy_v3_v3(co, vertexCos[i]); /* Apply axis limits */ if (smd->mode != MOD_SIMPLEDEFORM_MODE_BEND) { /* Bend mode shoulnt have any lock axis */ if (smd->axis & MOD_SIMPLEDEFORM_LOCK_AXIS_X) axis_limit(0, lock_axis, co, dcut); if (smd->axis & MOD_SIMPLEDEFORM_LOCK_AXIS_Y) axis_limit(1, lock_axis, co, dcut); } axis_limit(limit_axis, smd_limit, co, dcut); simpleDeform_callback(smd_factor, dcut, co); /* apply deform */ interp_v3_v3v3(vertexCos[i], vertexCos[i], co, weight); /* Use vertex weight has coef of linear interpolation */ if (transf) { space_transform_invert(transf, vertexCos[i]); } } } }
static void laplaciansmoothModifier_do( LaplacianSmoothModifierData *smd, Object *ob, DerivedMesh *dm, float (*vertexCos)[3], int numVerts) { LaplacianSystem *sys; MDeformVert *dvert = NULL; MDeformVert *dv = NULL; float w, wpaint; int i, iter; int defgrp_index; sys = init_laplacian_system(dm->getNumEdges(dm), dm->getNumPolys(dm), dm->getNumLoops(dm), numVerts); if (!sys) { return; } sys->mpoly = dm->getPolyArray(dm); sys->mloop = dm->getLoopArray(dm); sys->medges = dm->getEdgeArray(dm); sys->vertexCos = vertexCos; sys->min_area = 0.00001f; modifier_get_vgroup(ob, dm, smd->defgrp_name, &dvert, &defgrp_index); sys->vert_centroid[0] = 0.0f; sys->vert_centroid[1] = 0.0f; sys->vert_centroid[2] = 0.0f; memset_laplacian_system(sys, 0); sys->context = EIG_linear_least_squares_solver_new(numVerts, numVerts, 3); init_laplacian_matrix(sys); for (iter = 0; iter < smd->repeat; iter++) { for (i = 0; i < numVerts; i++) { EIG_linear_solver_variable_set(sys->context, 0, i, vertexCos[i][0]); EIG_linear_solver_variable_set(sys->context, 1, i, vertexCos[i][1]); EIG_linear_solver_variable_set(sys->context, 2, i, vertexCos[i][2]); if (iter == 0) { add_v3_v3(sys->vert_centroid, vertexCos[i]); } } if (iter == 0 && numVerts > 0) { mul_v3_fl(sys->vert_centroid, 1.0f / (float)numVerts); } dv = dvert; for (i = 0; i < numVerts; i++) { EIG_linear_solver_right_hand_side_add(sys->context, 0, i, vertexCos[i][0]); EIG_linear_solver_right_hand_side_add(sys->context, 1, i, vertexCos[i][1]); EIG_linear_solver_right_hand_side_add(sys->context, 2, i, vertexCos[i][2]); if (iter == 0) { if (dv) { wpaint = defvert_find_weight(dv, defgrp_index); dv++; } else { wpaint = 1.0f; } if (sys->zerola[i] == 0) { if (smd->flag & MOD_LAPLACIANSMOOTH_NORMALIZED) { w = sys->vweights[i]; sys->vweights[i] = (w == 0.0f) ? 0.0f : -fabsf(smd->lambda) * wpaint / w; w = sys->vlengths[i]; sys->vlengths[i] = (w == 0.0f) ? 0.0f : -fabsf(smd->lambda_border) * wpaint * 2.0f / w; if (sys->numNeEd[i] == sys->numNeFa[i]) { EIG_linear_solver_matrix_add(sys->context, i, i, 1.0f + fabsf(smd->lambda) * wpaint); } else { EIG_linear_solver_matrix_add(sys->context, i, i, 1.0f + fabsf(smd->lambda_border) * wpaint * 2.0f); } } else { w = sys->vweights[i] * sys->ring_areas[i]; sys->vweights[i] = (w == 0.0f) ? 0.0f : -fabsf(smd->lambda) * wpaint / (4.0f * w); w = sys->vlengths[i]; sys->vlengths[i] = (w == 0.0f) ? 0.0f : -fabsf(smd->lambda_border) * wpaint * 2.0f / w; if (sys->numNeEd[i] == sys->numNeFa[i]) { EIG_linear_solver_matrix_add(sys->context, i, i, 1.0f + fabsf(smd->lambda) * wpaint / (4.0f * sys->ring_areas[i])); } else { EIG_linear_solver_matrix_add(sys->context, i, i, 1.0f + fabsf(smd->lambda_border) * wpaint * 2.0f); } } } else { EIG_linear_solver_matrix_add(sys->context, i, i, 1.0f); } } } if (iter == 0) { fill_laplacian_matrix(sys); } if (EIG_linear_solver_solve(sys->context)) { validate_solution(sys, smd->flag, smd->lambda, smd->lambda_border); } } EIG_linear_solver_delete(sys->context); sys->context = NULL; delete_laplacian_system(sys); }