static int return_editmesh_vgroup(Object *obedit, EditMesh *em, char *name, float *cent) { zero_v3(cent); if(obedit->actdef) { const int defgrp_index= obedit->actdef-1; int totvert=0; MDeformVert *dvert; EditVert *eve; /* find the vertices */ for(eve= em->verts.first; eve; eve= eve->next) { dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT); if(dvert) { if(defvert_find_weight(dvert, defgrp_index) > 0.0f) { add_v3_v3(cent, eve->co); totvert++; } } } if(totvert) { bDeformGroup *dg = BLI_findlink(&obedit->defbase, defgrp_index); BLI_strncpy(name, dg->name, sizeof(dg->name)); mul_v3_fl(cent, 1.0f/(float)totvert); return 1; } } return 0; }
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; } } }
/* take care with this the rationale is: * - if the object has no vertex group. act like vertex group isn't set and return 1.0, * - if the vertex group exists but the 'defgroup' isn't found on this vertex, _still_ return 0.0 * * This is a bit confusing, just saves some checks from the caller. */ float defvert_array_find_weight_safe(const struct MDeformVert *dvert, const int index, const int defgroup) { if (defgroup == -1 || dvert == NULL) return 1.0f; return defvert_find_weight(dvert + index, defgroup); }
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); } } }
float defvert_array_find_weight_safe(const struct MDeformVert *dvert, int index, int group_num) { if(group_num == -1 || dvert == NULL) return 1.0f; return defvert_find_weight(dvert+index, group_num); }
static void editvert_mirror_update(Object *ob, EditVert *eve, int def_nr, int index) { Mesh *me= ob->data; EditMesh *em = BKE_mesh_get_editmesh(me); EditVert *eve_mirr; eve_mirr= editmesh_get_x_mirror_vert(ob, em, eve, eve->co, index); if(eve_mirr && eve_mirr != eve) { MDeformVert *dvert_src= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT); MDeformVert *dvert_dst= CustomData_em_get(&em->vdata, eve_mirr->data, CD_MDEFORMVERT); if(dvert_dst) { if(def_nr == -1) { /* all vgroups, add groups where neded */ int *flip_map= defgroup_flip_map(ob, 1); defvert_sync_mapped(dvert_dst, dvert_src, flip_map, 1); MEM_freeN(flip_map); } else { /* single vgroup */ MDeformWeight *dw= defvert_verify_index(dvert_dst, defgroup_flip_index(ob, def_nr, 1)); if(dw) { dw->weight= defvert_find_weight(dvert_src, def_nr); } } } } }
static void uv_warp_compute(void *userdata, const int i) { const UVWarpData *data = userdata; const MPoly *mp = &data->mpoly[i]; const MLoop *ml = &data->mloop[mp->loopstart]; MLoopUV *mluv = &data->mloopuv[mp->loopstart]; const MDeformVert *dvert = data->dvert; const int defgrp_index = data->defgrp_index; float (*warp_mat)[4] = data->warp_mat; const int axis_u = data->axis_u; const int axis_v = data->axis_v; int l; if (dvert) { for (l = 0; l < mp->totloop; l++, ml++, mluv++) { float uv[2]; 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 { for (l = 0; l < mp->totloop; l++, ml++, mluv++) { uv_warp_from_mat4_pair(mluv->uv, mluv->uv, warp_mat, axis_u, axis_v); } } }
void lattice_deform_verts(Object *laOb, Object *target, DerivedMesh *dm, float (*vertexCos)[3], int numVerts, const char *vgroup, float fac) { LatticeDeformData *lattice_deform_data; int a; bool use_vgroups; if (laOb->type != OB_LATTICE) return; lattice_deform_data = init_latt_deform(laOb, target); /* check whether to use vertex groups (only possible if target is a Mesh) * we want either a Mesh with no derived data, or derived data with * deformverts */ if (target && target->type == OB_MESH) { /* if there's derived data without deformverts, don't use vgroups */ if (dm) { use_vgroups = (dm->getVertDataArray(dm, CD_MDEFORMVERT) != NULL); } else { Mesh *me = target->data; use_vgroups = (me->dvert != NULL); } } else { use_vgroups = false; } if (vgroup && vgroup[0] && use_vgroups) { Mesh *me = target->data; const int defgrp_index = defgroup_name_index(target, vgroup); float weight; if (defgrp_index >= 0 && (me->dvert || dm)) { MDeformVert *dvert = me->dvert; for (a = 0; a < numVerts; a++, dvert++) { if (dm) dvert = dm->getVertData(dm, a, CD_MDEFORMVERT); weight = defvert_find_weight(dvert, defgrp_index); if (weight > 0.0f) calc_latt_deform(lattice_deform_data, vertexCos[a], weight * fac); } } } else { for (a = 0; a < numVerts; a++) { calc_latt_deform(lattice_deform_data, vertexCos[a], fac); } } end_latt_deform(lattice_deform_data); }
/** * \return The first group index shared by both deform verts * or -1 if none are found. */ int defvert_find_shared(const MDeformVert *dvert_a, const MDeformVert *dvert_b) { if (dvert_a->totweight && dvert_b->totweight) { MDeformWeight *dw = dvert_a->dw; unsigned int i; for (i = dvert_a->totweight; i != 0; i--, dw++) { if (dw->weight > 0.0f && defvert_find_weight(dvert_b, dw->def_nr) > 0.0f) { return dw->def_nr; } } } return -1; }
void BKE_defvert_extract_vgroup_to_vertweights( MDeformVert *dvert, const int defgroup, const int num_verts, float *r_weights, const bool invert_vgroup) { if (dvert && defgroup != -1) { int i = num_verts; while (i--) { const float w = defvert_find_weight(&dvert[i], defgroup); r_weights[i] = invert_vgroup ? (1.0f - w) : w; } } else { copy_vn_fl(r_weights, num_verts, invert_vgroup ? 1.0f : 0.0f); } }
void lattice_deform_verts(Object *laOb, Object *target, DerivedMesh *dm, float (*vertexCos)[3], int numVerts, char *vgroup) { int a; int use_vgroups; if(laOb->type != OB_LATTICE) return; init_latt_deform(laOb, target); /* check whether to use vertex groups (only possible if target is a Mesh) * we want either a Mesh with no derived data, or derived data with * deformverts */ if(target && target->type==OB_MESH) { /* if there's derived data without deformverts, don't use vgroups */ if(dm && !dm->getVertData(dm, 0, CD_MDEFORMVERT)) use_vgroups = 0; else use_vgroups = 1; } else use_vgroups = 0; if(vgroup && vgroup[0] && use_vgroups) { Mesh *me = target->data; int index = defgroup_name_index(target, vgroup); float weight; if(index >= 0 && (me->dvert || dm)) { MDeformVert *dvert = me->dvert; for(a = 0; a < numVerts; a++, dvert++) { if(dm) dvert = dm->getVertData(dm, a, CD_MDEFORMVERT); weight= defvert_find_weight(dvert, index); if(weight > 0.0f) calc_latt_deform(laOb, vertexCos[a], weight); } } } else { for(a = 0; a < numVerts; a++) { calc_latt_deform(laOb, vertexCos[a], 1.0f); } } end_latt_deform(laOb); }
/* check individual weights for changes and cache values */ static void dm_get_weights( MDeformVert *dvert, const int defgrp_index, const unsigned int numVerts, const bool use_invert_vgroup, float *smooth_weights) { unsigned int i; for (i = 0; i < numVerts; i++, dvert++) { const float w = defvert_find_weight(dvert, defgrp_index); if (use_invert_vgroup == false) { smooth_weights[i] = w; } else { smooth_weights[i] = 1.0f - w; } } }
void RAS_MeshObject::CheckWeightCache(Object* obj) { KeyBlock *kb; int kbindex, defindex; MDeformVert *dv= NULL; int totvert, i; float *weights; if (!m_mesh->key) return; for (kbindex = 0, kb = (KeyBlock *)m_mesh->key->block.first; kb; kb = kb->next, kbindex++) { // first check the cases where the weight must be cleared if (kb->vgroup[0] == 0 || m_mesh->dvert == NULL || (defindex = get_def_index(obj, kb->vgroup)) == -1) { if (kb->weights) { MEM_freeN(kb->weights); kb->weights = NULL; } m_cacheWeightIndex[kbindex] = -1; } else if (m_cacheWeightIndex[kbindex] != defindex) { // a weight array is required but the cache is not matching if (kb->weights) { MEM_freeN(kb->weights); kb->weights = NULL; } dv= m_mesh->dvert; totvert= m_mesh->totvert; weights= (float*)MEM_mallocN(totvert*sizeof(float), "weights"); for (i=0; i < totvert; i++, dv++) { weights[i] = defvert_find_weight(dv, defindex); } kb->weights = weights; m_cacheWeightIndex[kbindex] = defindex; } } }
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 deformVerts(ModifierData *md, Object *ob, DerivedMesh *dm, float (*vertexCos)[3], int numVerts, int UNUSED(useRenderParams), int UNUSED(isFinalCalc)) { HookModifierData *hmd = (HookModifierData*) md; bPoseChannel *pchan= get_pose_channel(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 */ int max_dvert= 0; MDeformVert *dvert= NULL; int defgrp_index = -1; /* 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, pchan->pose_mat, hmd->object->obmat); } 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); if((defgrp_index= defgroup_name_index(ob, hmd->name)) != -1) { Mesh *me = ob->data; if(dm) { dvert= dm->getVertDataArray(dm, CD_MDEFORMVERT); if(dvert) { max_dvert = numVerts; } } else if(me->dvert) { dvert= me->dvert; if(dvert) { max_dvert = me->totvert; } } } /* 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 */ int i; 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); } } } } }
/* 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 DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData, ModifierApplyFlag UNUSED(flag)) { MaskModifierData *mmd = (MaskModifierData *)md; DerivedMesh *dm = derivedData, *result = NULL; GHash *vertHash = NULL, *edgeHash, *polyHash; GHashIterator *hashIter; MDeformVert *dvert = NULL, *dv; int numPolys = 0, numLoops = 0, numEdges = 0, numVerts = 0; int maxVerts, maxEdges, maxPolys; int i; MPoly *mpoly; MLoop *mloop; MPoly *mpoly_new; MLoop *mloop_new; MEdge *medge_new; MVert *mvert_new; int *loop_mapping; /* Overview of Method: * 1. Get the vertices that are in the vertexgroup of interest * 2. Filter out unwanted geometry (i.e. not in vertexgroup), by populating mappings with new vs old indices * 3. Make a new mesh containing only the mapping data */ /* get original number of verts, edges, and faces */ maxVerts = dm->getNumVerts(dm); maxEdges = dm->getNumEdges(dm); maxPolys = dm->getNumPolys(dm); /* check if we can just return the original mesh * - must have verts and therefore verts assigned to vgroups to do anything useful */ if (!(ELEM(mmd->mode, MOD_MASK_MODE_ARM, MOD_MASK_MODE_VGROUP)) || (maxVerts == 0) || (ob->defbase.first == NULL) ) { return derivedData; } /* if mode is to use selected armature bones, aggregate the bone groups */ if (mmd->mode == MOD_MASK_MODE_ARM) { /* --- using selected bones --- */ Object *oba = mmd->ob_arm; bPoseChannel *pchan; bDeformGroup *def; char *bone_select_array; int bone_select_tot = 0; const int defbase_tot = BLI_countlist(&ob->defbase); /* check that there is armature object with bones to use, otherwise return original mesh */ if (ELEM3(NULL, oba, oba->pose, ob->defbase.first)) return derivedData; /* determine whether each vertexgroup is associated with a selected bone or not * - each cell is a boolean saying whether bone corresponding to the ith group is selected * - groups that don't match a bone are treated as not existing (along with the corresponding ungrouped verts) */ bone_select_array = MEM_mallocN(defbase_tot * sizeof(char), "mask array"); for (i = 0, def = ob->defbase.first; def; def = def->next, i++) { pchan = BKE_pose_channel_find_name(oba->pose, def->name); if (pchan && pchan->bone && (pchan->bone->flag & BONE_SELECTED)) { bone_select_array[i] = TRUE; bone_select_tot++; } else { bone_select_array[i] = FALSE; } } /* if no dverts (i.e. no data for vertex groups exists), we've got an * inconsistent situation, so free hashes and return oirginal mesh */ dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); if (dvert == NULL) { MEM_freeN(bone_select_array); return derivedData; } /* verthash gives mapping from original vertex indices to the new indices (including selected matches only) * key = oldindex, value = newindex */ vertHash = BLI_ghash_int_new("mask vert gh"); /* add vertices which exist in vertexgroups into vertHash for filtering * - dv = for each vertex, what vertexgroups does it belong to * - dw = weight that vertex was assigned to a vertexgroup it belongs to */ for (i = 0, dv = dvert; i < maxVerts; i++, dv++) { MDeformWeight *dw = dv->dw; short found = 0; int j; /* check the groups that vertex is assigned to, and see if it was any use */ for (j = 0; j < dv->totweight; j++, dw++) { if (dw->def_nr < defbase_tot) { if (bone_select_array[dw->def_nr]) { if (dw->weight != 0.0f) { found = TRUE; break; } } } } /* check if include vert in vertHash */ if (mmd->flag & MOD_MASK_INV) { /* if this vert is in the vgroup, don't include it in vertHash */ if (found) continue; } else { /* if this vert isn't in the vgroup, don't include it in vertHash */ if (!found) continue; } /* add to ghash for verts (numVerts acts as counter for mapping) */ BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numVerts)); numVerts++; } /* free temp hashes */ MEM_freeN(bone_select_array); } else { /* --- Using Nominated VertexGroup only --- */ int defgrp_index = defgroup_name_index(ob, mmd->vgroup); /* get dverts */ if (defgrp_index != -1) dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); /* if no vgroup (i.e. dverts) found, return the initial mesh */ if ((defgrp_index == -1) || (dvert == NULL)) return dm; /* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */ vertHash = BLI_ghash_int_new("mask vert2 bh"); /* add vertices which exist in vertexgroup into ghash for filtering */ for (i = 0, dv = dvert; i < maxVerts; i++, dv++) { const int weight_set = defvert_find_weight(dv, defgrp_index) != 0.0f; /* check if include vert in vertHash */ if (mmd->flag & MOD_MASK_INV) { /* if this vert is in the vgroup, don't include it in vertHash */ if (weight_set) continue; } else { /* if this vert isn't in the vgroup, don't include it in vertHash */ if (!weight_set) continue; } /* add to ghash for verts (numVerts acts as counter for mapping) */ BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numVerts)); numVerts++; } } /* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */ edgeHash = BLI_ghash_int_new("mask ed2 gh"); polyHash = BLI_ghash_int_new("mask fa2 gh"); mpoly = dm->getPolyArray(dm); mloop = dm->getLoopArray(dm); loop_mapping = MEM_callocN(sizeof(int) * maxPolys, "mask loopmap"); /* overalloc, assume all polys are seen */ /* loop over edges and faces, and do the same thing to * ensure that they only reference existing verts */ for (i = 0; i < maxEdges; i++) { MEdge me; dm->getEdge(dm, i, &me); /* only add if both verts will be in new mesh */ if (BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me.v1)) && BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me.v2))) { BLI_ghash_insert(edgeHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numEdges)); numEdges++; } } for (i = 0; i < maxPolys; i++) { MPoly *mp = &mpoly[i]; MLoop *ml = mloop + mp->loopstart; int ok = TRUE; int j; for (j = 0; j < mp->totloop; j++, ml++) { if (!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(ml->v))) { ok = FALSE; break; } } /* all verts must be available */ if (ok) { BLI_ghash_insert(polyHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numPolys)); loop_mapping[numPolys] = numLoops; numPolys++; numLoops += mp->totloop; } } /* now we know the number of verts, edges and faces, * we can create the new (reduced) mesh */ result = CDDM_from_template(dm, numVerts, numEdges, 0, numLoops, numPolys); mpoly_new = CDDM_get_polys(result); mloop_new = CDDM_get_loops(result); medge_new = CDDM_get_edges(result); mvert_new = CDDM_get_verts(result); /* using ghash-iterators, map data into new mesh */ /* vertices */ for (hashIter = BLI_ghashIterator_new(vertHash); !BLI_ghashIterator_isDone(hashIter); BLI_ghashIterator_step(hashIter) ) { MVert source; MVert *dest; int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(hashIter)); int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter)); dm->getVert(dm, oldIndex, &source); dest = &mvert_new[newIndex]; DM_copy_vert_data(dm, result, oldIndex, newIndex, 1); *dest = source; } BLI_ghashIterator_free(hashIter); /* edges */ for (hashIter = BLI_ghashIterator_new(edgeHash); !BLI_ghashIterator_isDone(hashIter); BLI_ghashIterator_step(hashIter)) { MEdge source; MEdge *dest; int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(hashIter)); int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter)); dm->getEdge(dm, oldIndex, &source); dest = &medge_new[newIndex]; source.v1 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v1))); source.v2 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v2))); DM_copy_edge_data(dm, result, oldIndex, newIndex, 1); *dest = source; } BLI_ghashIterator_free(hashIter); /* faces */ for (hashIter = BLI_ghashIterator_new(polyHash); !BLI_ghashIterator_isDone(hashIter); BLI_ghashIterator_step(hashIter) ) { int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(hashIter)); int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter)); MPoly *source = &mpoly[oldIndex]; MPoly *dest = &mpoly_new[newIndex]; int oldLoopIndex = source->loopstart; int newLoopIndex = loop_mapping[newIndex]; MLoop *source_loop = &mloop[oldLoopIndex]; MLoop *dest_loop = &mloop_new[newLoopIndex]; DM_copy_poly_data(dm, result, oldIndex, newIndex, 1); DM_copy_loop_data(dm, result, oldLoopIndex, newLoopIndex, source->totloop); *dest = *source; dest->loopstart = newLoopIndex; for (i = 0; i < source->totloop; i++) { dest_loop[i].v = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source_loop[i].v))); dest_loop[i].e = GET_INT_FROM_POINTER(BLI_ghash_lookup(edgeHash, SET_INT_IN_POINTER(source_loop[i].e))); } } BLI_ghashIterator_free(hashIter); MEM_freeN(loop_mapping); /* why is this needed? - campbell */ /* recalculate normals */ CDDM_calc_normals(result); /* free hashes */ BLI_ghash_free(vertHash, NULL, NULL); BLI_ghash_free(edgeHash, NULL, NULL); BLI_ghash_free(polyHash, NULL, NULL); /* return the new mesh */ return result; }
void curve_deform_verts(Scene *scene, Object *cuOb, Object *target, DerivedMesh *dm, float (*vertexCos)[3], int numVerts, const char *vgroup, short defaxis) { Curve *cu; int a, flag; CurveDeform cd; int use_vgroups; const int is_neg_axis = (defaxis > 2); if (cuOb->type != OB_CURVE) return; cu = cuOb->data; flag = cu->flag; cu->flag |= (CU_PATH | CU_FOLLOW); // needed for path & bevlist init_curve_deform(cuOb, target, &cd); /* dummy bounds, keep if CU_DEFORM_BOUNDS_OFF is set */ if (is_neg_axis == FALSE) { cd.dmin[0] = cd.dmin[1] = cd.dmin[2] = 0.0f; cd.dmax[0] = cd.dmax[1] = cd.dmax[2] = 1.0f; } else { /* negative, these bounds give a good rest position */ cd.dmin[0] = cd.dmin[1] = cd.dmin[2] = -1.0f; cd.dmax[0] = cd.dmax[1] = cd.dmax[2] = 0.0f; } /* check whether to use vertex groups (only possible if target is a Mesh) * we want either a Mesh with no derived data, or derived data with * deformverts */ if (target && target->type == OB_MESH) { /* if there's derived data without deformverts, don't use vgroups */ if (dm) { use_vgroups = (dm->getVertData(dm, 0, CD_MDEFORMVERT) != NULL); } else { Mesh *me = target->data; use_vgroups = (me->dvert != NULL); } } else { use_vgroups = FALSE; } if (vgroup && vgroup[0] && use_vgroups) { Mesh *me = target->data; int index = defgroup_name_index(target, vgroup); if (index != -1 && (me->dvert || dm)) { MDeformVert *dvert = me->dvert; float vec[3]; float weight; if (cu->flag & CU_DEFORM_BOUNDS_OFF) { dvert = me->dvert; for (a = 0; a < numVerts; a++, dvert++) { if (dm) dvert = dm->getVertData(dm, a, CD_MDEFORMVERT); weight = defvert_find_weight(dvert, index); if (weight > 0.0f) { mul_m4_v3(cd.curvespace, vertexCos[a]); copy_v3_v3(vec, vertexCos[a]); calc_curve_deform(scene, cuOb, vec, defaxis, &cd, NULL); interp_v3_v3v3(vertexCos[a], vertexCos[a], vec, weight); mul_m4_v3(cd.objectspace, vertexCos[a]); } } } else { /* set mesh min/max bounds */ INIT_MINMAX(cd.dmin, cd.dmax); for (a = 0; a < numVerts; a++, dvert++) { if (dm) dvert = dm->getVertData(dm, a, CD_MDEFORMVERT); if (defvert_find_weight(dvert, index) > 0.0f) { mul_m4_v3(cd.curvespace, vertexCos[a]); minmax_v3v3_v3(cd.dmin, cd.dmax, vertexCos[a]); } } dvert = me->dvert; for (a = 0; a < numVerts; a++, dvert++) { if (dm) dvert = dm->getVertData(dm, a, CD_MDEFORMVERT); weight = defvert_find_weight(dvert, index); if (weight > 0.0f) { /* already in 'cd.curvespace', prev for loop */ copy_v3_v3(vec, vertexCos[a]); calc_curve_deform(scene, cuOb, vec, defaxis, &cd, NULL); interp_v3_v3v3(vertexCos[a], vertexCos[a], vec, weight); mul_m4_v3(cd.objectspace, vertexCos[a]); } } } } } else { if (cu->flag & CU_DEFORM_BOUNDS_OFF) { for (a = 0; a < numVerts; a++) { mul_m4_v3(cd.curvespace, vertexCos[a]); calc_curve_deform(scene, cuOb, vertexCos[a], defaxis, &cd, NULL); mul_m4_v3(cd.objectspace, vertexCos[a]); } } else { /* set mesh min max bounds */ INIT_MINMAX(cd.dmin, cd.dmax); for (a = 0; a < numVerts; a++) { mul_m4_v3(cd.curvespace, vertexCos[a]); minmax_v3v3_v3(cd.dmin, cd.dmax, vertexCos[a]); } for (a = 0; a < numVerts; a++) { /* already in 'cd.curvespace', prev for loop */ calc_curve_deform(scene, cuOb, vertexCos[a], defaxis, &cd, NULL); mul_m4_v3(cd.objectspace, vertexCos[a]); } } } cu->flag = flag; }
void calc_latt_deform(Object *ob, float co[3], float weight) { Lattice *lt = ob->data; float u, v, w, tu[4], tv[4], tw[4]; float vec[3]; int idx_w, idx_v, idx_u; int ui, vi, wi, uu, vv, ww; /* vgroup influence */ int defgroup_nr = -1; float co_prev[3], weight_blend = 0.0f; MDeformVert *dvert = BKE_lattice_deform_verts_get(ob); if (lt->editlatt) lt = lt->editlatt->latt; if (lt->latticedata == NULL) return; if (lt->vgroup[0] && dvert) { defgroup_nr = defgroup_name_index(ob, lt->vgroup); copy_v3_v3(co_prev, co); } /* co is in local coords, treat with latmat */ mul_v3_m4v3(vec, lt->latmat, co); /* u v w coords */ if (lt->pntsu > 1) { u = (vec[0] - lt->fu) / lt->du; ui = (int)floor(u); u -= ui; key_curve_position_weights(u, tu, lt->typeu); } else { tu[0] = tu[2] = tu[3] = 0.0; tu[1] = 1.0; ui = 0; } if (lt->pntsv > 1) { v = (vec[1] - lt->fv) / lt->dv; vi = (int)floor(v); v -= vi; key_curve_position_weights(v, tv, lt->typev); } else { tv[0] = tv[2] = tv[3] = 0.0; tv[1] = 1.0; vi = 0; } if (lt->pntsw > 1) { w = (vec[2] - lt->fw) / lt->dw; wi = (int)floor(w); w -= wi; key_curve_position_weights(w, tw, lt->typew); } else { tw[0] = tw[2] = tw[3] = 0.0; tw[1] = 1.0; wi = 0; } for (ww = wi - 1; ww <= wi + 2; ww++) { w = tw[ww - wi + 1]; if (w != 0.0f) { if (ww > 0) { if (ww < lt->pntsw) idx_w = ww * lt->pntsu * lt->pntsv; else idx_w = (lt->pntsw - 1) * lt->pntsu * lt->pntsv; } else idx_w = 0; for (vv = vi - 1; vv <= vi + 2; vv++) { v = w * tv[vv - vi + 1]; if (v != 0.0f) { if (vv > 0) { if (vv < lt->pntsv) idx_v = idx_w + vv * lt->pntsu; else idx_v = idx_w + (lt->pntsv - 1) * lt->pntsu; } else idx_v = idx_w; for (uu = ui - 1; uu <= ui + 2; uu++) { u = weight * v * tu[uu - ui + 1]; if (u != 0.0f) { if (uu > 0) { if (uu < lt->pntsu) idx_u = idx_v + uu; else idx_u = idx_v + (lt->pntsu - 1); } else idx_u = idx_v; madd_v3_v3fl(co, <->latticedata[idx_u * 3], u); if (defgroup_nr != -1) weight_blend += (u * defvert_find_weight(dvert + idx_u, defgroup_nr)); } } } } } } if (defgroup_nr != -1) interp_v3_v3v3(co, co_prev, co, weight_blend); }
void curve_deform_verts( Scene *scene, Object *cuOb, Object *target, DerivedMesh *dm, float (*vertexCos)[3], int numVerts, const char *vgroup, short defaxis) { Curve *cu; int a; CurveDeform cd; MDeformVert *dvert = NULL; int defgrp_index = -1; const bool is_neg_axis = (defaxis > 2); if (cuOb->type != OB_CURVE) return; cu = cuOb->data; init_curve_deform(cuOb, target, &cd); /* dummy bounds, keep if CU_DEFORM_BOUNDS_OFF is set */ if (is_neg_axis == false) { cd.dmin[0] = cd.dmin[1] = cd.dmin[2] = 0.0f; cd.dmax[0] = cd.dmax[1] = cd.dmax[2] = 1.0f; } else { /* negative, these bounds give a good rest position */ cd.dmin[0] = cd.dmin[1] = cd.dmin[2] = -1.0f; cd.dmax[0] = cd.dmax[1] = cd.dmax[2] = 0.0f; } /* Check whether to use vertex groups (only possible if target is a Mesh or Lattice). * We want either a Mesh/Lattice with no derived data, or derived data with deformverts. */ if (vgroup && vgroup[0] && ELEM(target->type, OB_MESH, OB_LATTICE)) { defgrp_index = defgroup_name_index(target, vgroup); if (defgrp_index != -1) { /* if there's derived data without deformverts, don't use vgroups */ if (dm) { dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); } else if (target->type == OB_LATTICE) { dvert = ((Lattice *)target->data)->dvert; } else { dvert = ((Mesh *)target->data)->dvert; } } } if (dvert) { MDeformVert *dvert_iter; float vec[3]; if (cu->flag & CU_DEFORM_BOUNDS_OFF) { for (a = 0, dvert_iter = dvert; a < numVerts; a++, dvert_iter++) { const float weight = defvert_find_weight(dvert_iter, defgrp_index); if (weight > 0.0f) { mul_m4_v3(cd.curvespace, vertexCos[a]); copy_v3_v3(vec, vertexCos[a]); calc_curve_deform(scene, cuOb, vec, defaxis, &cd, NULL); interp_v3_v3v3(vertexCos[a], vertexCos[a], vec, weight); mul_m4_v3(cd.objectspace, vertexCos[a]); } } } else { /* set mesh min/max bounds */ INIT_MINMAX(cd.dmin, cd.dmax); for (a = 0, dvert_iter = dvert; a < numVerts; a++, dvert_iter++) { if (defvert_find_weight(dvert_iter, defgrp_index) > 0.0f) { mul_m4_v3(cd.curvespace, vertexCos[a]); minmax_v3v3_v3(cd.dmin, cd.dmax, vertexCos[a]); } } for (a = 0, dvert_iter = dvert; a < numVerts; a++, dvert_iter++) { const float weight = defvert_find_weight(dvert_iter, defgrp_index); if (weight > 0.0f) { /* already in 'cd.curvespace', prev for loop */ copy_v3_v3(vec, vertexCos[a]); calc_curve_deform(scene, cuOb, vec, defaxis, &cd, NULL); interp_v3_v3v3(vertexCos[a], vertexCos[a], vec, weight); mul_m4_v3(cd.objectspace, vertexCos[a]); } } } } else { if (cu->flag & CU_DEFORM_BOUNDS_OFF) { for (a = 0; a < numVerts; a++) { mul_m4_v3(cd.curvespace, vertexCos[a]); calc_curve_deform(scene, cuOb, vertexCos[a], defaxis, &cd, NULL); mul_m4_v3(cd.objectspace, vertexCos[a]); } } else { /* set mesh min max bounds */ INIT_MINMAX(cd.dmin, cd.dmax); for (a = 0; a < numVerts; a++) { mul_m4_v3(cd.curvespace, vertexCos[a]); minmax_v3v3_v3(cd.dmin, cd.dmax, vertexCos[a]); } for (a = 0; a < numVerts; a++) { /* already in 'cd.curvespace', prev for loop */ calc_curve_deform(scene, cuOb, vertexCos[a], defaxis, &cd, NULL); mul_m4_v3(cd.objectspace, vertexCos[a]); } } } }
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); }
/* Applies new_w weights to org_w ones, using either a texture, vgroup or constant value as factor. * Return values are in org_w. * If indices is not NULL, it must be a table of same length as org_w and new_w, mapping to the real * vertex index (in case the weight tables do not cover the whole vertices...). * XXX The standard “factor” value is assumed in [0.0, 1.0] range. Else, weird results might appear. */ void weightvg_do_mask(int num, const int *indices, float *org_w, const float *new_w, Object *ob, DerivedMesh *dm, float fact, const char defgrp_name[32], Tex *texture, int tex_use_channel, int tex_mapping, Object *tex_map_object, const char *tex_uvlayer_name) { int ref_didx; int i; /* If influence factor is null, nothing to do! */ if (fact == 0.0f) return; /* If we want to mask vgroup weights from a texture. */ if (texture) { /* The texture coordinates. */ float (*tex_co)[3]; /* See mapping note below... */ MappingInfoModifierData t_map; float (*v_co)[3]; /* Use new generic get_texture_coords, but do not modify our DNA struct for it... * XXX Why use a ModifierData stuff here ? Why not a simple, generic struct for parameters ? * What e.g. if a modifier wants to use several textures ? * Why use only v_co, and not MVert (or both) ? */ t_map.texture = texture; t_map.map_object = tex_map_object; BLI_strncpy(t_map.uvlayer_name, tex_uvlayer_name, sizeof(t_map.uvlayer_name)); t_map.texmapping = tex_mapping; v_co = MEM_mallocN(sizeof(*v_co) * num, "WeightVG Modifier, TEX mode, v_co"); dm->getVertCos(dm, v_co); tex_co = MEM_callocN(sizeof(*tex_co) * num, "WeightVG Modifier, TEX mode, tex_co"); get_texture_coords(&t_map, ob, dm, v_co, tex_co, num); MEM_freeN(v_co); /* For each weight (vertex), make the mix between org and new weights. */ for(i = 0; i < num; ++i) { int idx = indices ? indices[i] : i; TexResult texres; float h, s, v; /* For HSV color space. */ texres.nor = NULL; get_texture_value(texture, tex_co[idx], &texres); /* Get the good channel value... */ switch(tex_use_channel) { case MOD_WVG_MASK_TEX_USE_INT: org_w[i] = (new_w[i] * texres.tin * fact) + (org_w[i] * (1.0f - (texres.tin*fact))); break; case MOD_WVG_MASK_TEX_USE_RED: org_w[i] = (new_w[i] * texres.tr * fact) + (org_w[i] * (1.0f - (texres.tr*fact))); break; case MOD_WVG_MASK_TEX_USE_GREEN: org_w[i] = (new_w[i] * texres.tg * fact) + (org_w[i] * (1.0f - (texres.tg*fact))); break; case MOD_WVG_MASK_TEX_USE_BLUE: org_w[i] = (new_w[i] * texres.tb * fact) + (org_w[i] * (1.0f - (texres.tb*fact))); break; case MOD_WVG_MASK_TEX_USE_HUE: rgb_to_hsv(texres.tr, texres.tg, texres.tb, &h, &s, &v); org_w[i] = (new_w[i] * h * fact) + (org_w[i] * (1.0f - (h*fact))); break; case MOD_WVG_MASK_TEX_USE_SAT: rgb_to_hsv(texres.tr, texres.tg, texres.tb, &h, &s, &v); org_w[i] = (new_w[i] * s * fact) + (org_w[i] * (1.0f - (s*fact))); break; case MOD_WVG_MASK_TEX_USE_VAL: rgb_to_hsv(texres.tr, texres.tg, texres.tb, &h, &s, &v); org_w[i] = (new_w[i] * v * fact) + (org_w[i] * (1.0f - (v*fact))); break; case MOD_WVG_MASK_TEX_USE_ALPHA: org_w[i] = (new_w[i] * texres.ta * fact) + (org_w[i] * (1.0f - (texres.ta*fact))); break; default: org_w[i] = (new_w[i] * texres.tin * fact) + (org_w[i] * (1.0f - (texres.tin*fact))); break; } } MEM_freeN(tex_co); } else if ((ref_didx = defgroup_name_index(ob, defgrp_name)) != -1) { MDeformVert *dvert = NULL; /* Check whether we want to set vgroup weights from a constant weight factor or a vertex * group. */ /* Get vgroup idx from its name. */ /* Proceed only if vgroup is valid, else use constant factor. */ /* Get actual dverts (ie vertex group data). */ dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); /* Proceed only if vgroup is valid, else assume factor = O. */ if (dvert == NULL) return; /* For each weight (vertex), make the mix between org and new weights. */ for (i = 0; i < num; i++) { int idx = indices ? indices[i] : i; const float f = defvert_find_weight(&dvert[idx], ref_didx) * fact; org_w[i] = (new_w[i] * f) + (org_w[i] * (1.0f-f)); /* If that vertex is not in ref vgroup, assume null factor, and hence do nothing! */ } } else { /* Default "influence" behavior. */ /* For each weight (vertex), make the mix between org and new weights. */ const float ifact = 1.0f - fact; for (i = 0; i < num; i++) { org_w[i] = (new_w[i] * fact) + (org_w[i] * ifact); } } }
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); }
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); } }
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 createFacepa(ExplodeModifierData *emd, ParticleSystemModifierData *psmd, DerivedMesh *dm) { ParticleSystem *psys = psmd->psys; MFace *fa = NULL, *mface = NULL; MVert *mvert = NULL; ParticleData *pa; KDTree *tree; RNG *rng; float center[3], co[3]; int *facepa = NULL, *vertpa = NULL, totvert = 0, totface = 0, totpart = 0; int i, p, v1, v2, v3, v4 = 0; mvert = dm->getVertArray(dm); mface = dm->getTessFaceArray(dm); totface = dm->getNumTessFaces(dm); totvert = dm->getNumVerts(dm); totpart = psmd->psys->totpart; rng = BLI_rng_new_srandom(psys->seed); if (emd->facepa) MEM_freeN(emd->facepa); facepa = emd->facepa = MEM_callocN(sizeof(int) * totface, "explode_facepa"); vertpa = MEM_callocN(sizeof(int) * totvert, "explode_vertpa"); /* initialize all faces & verts to no particle */ for (i = 0; i < totface; i++) facepa[i] = totpart; for (i = 0; i < totvert; i++) vertpa[i] = totpart; /* set protected verts */ if (emd->vgroup) { MDeformVert *dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); if (dvert) { const int defgrp_index = emd->vgroup - 1; for (i = 0; i < totvert; i++, dvert++) { float val = BLI_rng_get_float(rng); val = (1.0f - emd->protect) * val + emd->protect * 0.5f; if (val < defvert_find_weight(dvert, defgrp_index)) vertpa[i] = -1; } } } /* make tree of emitter locations */ tree = BLI_kdtree_new(totpart); for (p = 0, pa = psys->particles; p < totpart; p++, pa++) { psys_particle_on_emitter(psmd, psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, co, NULL, NULL, NULL, NULL, NULL); BLI_kdtree_insert(tree, p, co); } BLI_kdtree_balance(tree); /* set face-particle-indexes to nearest particle to face center */ for (i = 0, fa = mface; i < totface; i++, fa++) { add_v3_v3v3(center, mvert[fa->v1].co, mvert[fa->v2].co); add_v3_v3(center, mvert[fa->v3].co); if (fa->v4) { add_v3_v3(center, mvert[fa->v4].co); mul_v3_fl(center, 0.25); } else mul_v3_fl(center, 1.0f / 3.0f); p = BLI_kdtree_find_nearest(tree, center, NULL); v1 = vertpa[fa->v1]; v2 = vertpa[fa->v2]; v3 = vertpa[fa->v3]; if (fa->v4) v4 = vertpa[fa->v4]; if (v1 >= 0 && v2 >= 0 && v3 >= 0 && (fa->v4 == 0 || v4 >= 0)) facepa[i] = p; if (v1 >= 0) vertpa[fa->v1] = p; if (v2 >= 0) vertpa[fa->v2] = p; if (v3 >= 0) vertpa[fa->v3] = p; if (fa->v4 && v4 >= 0) vertpa[fa->v4] = p; } if (vertpa) MEM_freeN(vertpa); BLI_kdtree_free(tree); BLI_rng_free(rng); }
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 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); }
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); } }
/* 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); } }