/* applies individual td->axismtx constraints */ void setAxisMatrixConstraint(TransInfo *t, int mode, const char text[]) { if (t->total == 1) { float axismtx[3][3]; if (t->flag & T_EDIT) { mul_m3_m3m3(axismtx, t->obedit_mat, t->data->axismtx); } else { copy_m3_m3(axismtx, t->data->axismtx); } setConstraint(t, axismtx, mode, text); } else { BLI_strncpy(t->con.text + 1, text, sizeof(t->con.text) - 1); copy_m3_m3(t->con.mtx, t->data->axismtx); t->con.mode = mode; getConstraintMatrix(t); startConstraint(t); t->con.drawExtra = drawObjectConstraint; t->con.applyVec = applyObjectConstraintVec; t->con.applySize = applyObjectConstraintSize; t->con.applyRot = applyObjectConstraintRot; t->redraw = TREDRAW_HARD; } }
void setLocalConstraint(TransInfo *t, int mode, const char text[]) { if (t->flag & T_EDIT) { float obmat[3][3]; copy_m3_m4(obmat, t->scene->obedit->obmat); normalize_m3(obmat); setConstraint(t, obmat, mode, text); } else { if (t->total == 1) { setConstraint(t, t->data->axismtx, mode, text); } else { strncpy(t->con.text + 1, text, 48); copy_m3_m3(t->con.mtx, t->data->axismtx); t->con.mode = mode; getConstraintMatrix(t); startConstraint(t); t->con.drawExtra = drawObjectConstraint; t->con.applyVec = applyObjectConstraintVec; t->con.applySize = applyObjectConstraintSize; t->con.applyRot = applyObjectConstraintRot; t->redraw = 1; } } }
void crazyspace_build_sculpt(Scene *scene, Object *ob, float (**deformmats)[3][3], float (**deformcos)[3]) { int totleft= sculpt_get_first_deform_matrices(scene, ob, deformmats, deformcos); if(totleft) { /* there are deformation modifier which doesn't support deformation matricies calculation. Need additional crazyspace correction */ float (*deformedVerts)[3]= *deformcos; float (*origVerts)[3]= MEM_dupallocN(deformedVerts); float *quats= NULL; int i, deformed= 0; ModifierData *md= modifiers_getVirtualModifierList(ob); Mesh *me= (Mesh*)ob->data; for(; md; md= md->next) { ModifierTypeInfo *mti= modifierType_getInfo(md->type); if(!modifier_isEnabled(scene, md, eModifierMode_Realtime)) continue; if(mti->type==eModifierTypeType_OnlyDeform) { /* skip leading modifiers which have been already handled in sculpt_get_first_deform_matrices */ if(mti->deformMatrices && !deformed) continue; mti->deformVerts(md, ob, NULL, deformedVerts, me->totvert, 0, 0); deformed= 1; } } quats= MEM_mallocN(me->totvert*sizeof(float)*4, "crazy quats"); crazyspace_set_quats_mesh(me, (float*)origVerts, (float*)deformedVerts, quats); for(i=0; i<me->totvert; i++) { float qmat[3][3], tmat[3][3]; quat_to_mat3(qmat, &quats[i*4]); mul_m3_m3m3(tmat, qmat, (*deformmats)[i]); copy_m3_m3((*deformmats)[i], tmat); } MEM_freeN(origVerts); MEM_freeN(quats); } if(!*deformmats) { int a, numVerts; Mesh *me= (Mesh*)ob->data; *deformcos= mesh_getVertexCos(me, &numVerts); *deformmats= MEM_callocN(sizeof(*(*deformmats))*numVerts, "defmats"); for(a=0; a<numVerts; a++) unit_m3((*deformmats)[a]); } }
void initSelectConstraint(TransInfo *t, float mtx[3][3]) { copy_m3_m3(t->con.mtx, mtx); t->con.mode |= CON_APPLY; t->con.mode |= CON_SELECT; setNearestAxis(t); t->con.drawExtra = NULL; t->con.applyVec = applyAxisConstraintVec; t->con.applySize = applyAxisConstraintSize; t->con.applyRot = applyAxisConstraintRot; }
static void cloth_hair_update_bending_rest_targets(ClothModifierData *clmd) { Cloth *cloth = clmd->clothObject; LinkNode *search = NULL; float hair_frame[3][3], dir_old[3], dir_new[3]; int prev_mn; /* to find hair roots */ if (!clmd->hairdata) return; /* XXX Note: we need to propagate frames from the root up, * but structural hair springs are stored in reverse order. * The bending springs however are then inserted in the same * order as vertices again ... * This messy situation can be resolved when solver data is * generated directly from a dedicated hair system. */ prev_mn = -1; for (search = cloth->springs; search; search = search->next) { ClothSpring *spring = search->link; ClothHairData *hair_ij, *hair_kl; bool is_root = spring->kl != prev_mn; if (spring->type != CLOTH_SPRING_TYPE_BENDING_ANG) { continue; } hair_ij = &clmd->hairdata[spring->ij]; hair_kl = &clmd->hairdata[spring->kl]; if (is_root) { /* initial hair frame from root orientation */ copy_m3_m3(hair_frame, hair_ij->rot); /* surface normal is the initial direction, * parallel transport then keeps it aligned to the hair direction */ copy_v3_v3(dir_new, hair_frame[2]); } copy_v3_v3(dir_old, dir_new); sub_v3_v3v3(dir_new, cloth->verts[spring->mn].xrest, cloth->verts[spring->kl].xrest); normalize_v3(dir_new); /* dir expressed in the hair frame defines the rest target direction */ copy_v3_v3(hair_kl->rest_target, dir_new); mul_transposed_m3_v3(hair_frame, hair_kl->rest_target); /* move frame to next hair segment */ cloth_parallel_transport_hair_frame(hair_frame, dir_old, dir_new); prev_mn = spring->mn; } }
void mul_m3_m3m3(float R[9], float A[9], float B[9]) { int i, j, n; float sum, temp[9]; for(i=1; i<=3; i++) for(j=1; j<=3; j++) { sum = 0.0; for(n=1; n<=3; n++) sum += A[INDEX_M3(i,n)] * B[INDEX_M3(n,j)]; temp[INDEX_M3(i,j)] = sum; } copy_m3_m3(R, temp); }
void setConstraint(TransInfo *t, float space[3][3], int mode, const char text[]) { strncpy(t->con.text + 1, text, 48); copy_m3_m3(t->con.mtx, space); t->con.mode = mode; getConstraintMatrix(t); startConstraint(t); t->con.drawExtra = NULL; t->con.applyVec = applyAxisConstraintVec; t->con.applySize = applyAxisConstraintSize; t->con.applyRot = applyAxisConstraintRot; t->redraw = 1; }
static void cancel_slide_point(SlidePointData *data) { /* cancel sliding */ if (data->orig_spline) { slide_point_restore_spline(data); } else { if (data->action == SLIDE_ACTION_FEATHER) { if (data->uw) data->uw->w = data->weight; else data->point->bezt.weight = data->weight; } else { copy_m3_m3(data->point->bezt.vec, data->vec); } } }
static void deformMatricesEM(ModifierData *UNUSED(md), Object *ob, struct BMEditMesh *UNUSED(editData), DerivedMesh *UNUSED(derivedData), float (*vertexCos)[3], float (*defMats)[3][3], int numVerts) { Key *key = BKE_key_from_object(ob); KeyBlock *kb = BKE_keyblock_from_object(ob); float scale[3][3]; (void)vertexCos; /* unused */ if (kb && kb->totelem == numVerts && kb != key->refkey) { int a; scale_m3_fl(scale, kb->curval); for (a = 0; a < numVerts; a++) copy_m3_m3(defMats[a], scale); } }
static void deformMatrices(ModifierData *md, Object *ob, DerivedMesh *derivedData, float (*vertexCos)[3], float (*defMats)[3][3], int numVerts) { Key *key = BKE_key_from_object(ob); KeyBlock *kb = BKE_keyblock_from_object(ob); float scale[3][3]; (void)vertexCos; /* unused */ if (kb && kb->totelem == numVerts && kb != key->refkey) { int a; if (ob->shapeflag & OB_SHAPE_LOCK) scale_m3_fl(scale, 1); else scale_m3_fl(scale, kb->curval); for (a = 0; a < numVerts; a++) copy_m3_m3(defMats[a], scale); } deformVerts(md, ob, derivedData, vertexCos, numVerts, 0); }
static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent *event) { ScrArea *sa = CTX_wm_area(C); ARegion *ar = CTX_wm_region(C); Mask *mask = CTX_data_edit_mask(C); SlidePointData *customdata = NULL; MaskLayer *masklay, *cv_masklay, *feather_masklay; MaskSpline *spline, *cv_spline, *feather_spline; MaskSplinePoint *point, *cv_point, *feather_point; MaskSplinePointUW *uw = NULL; int width, height, action = SLIDE_ACTION_NONE; bool is_handle = false; const bool slide_feather = RNA_boolean_get(op->ptr, "slide_feather"); float co[2], cv_score, feather_score; const float threshold = 19; ED_mask_mouse_pos(sa, ar, event->mval, co); ED_mask_get_size(sa, &width, &height); cv_point = ED_mask_point_find_nearest(C, mask, co, threshold, &cv_masklay, &cv_spline, &is_handle, &cv_score); if (ED_mask_feather_find_nearest(C, mask, co, threshold, &feather_masklay, &feather_spline, &feather_point, &uw, &feather_score)) { if (slide_feather || !cv_point || feather_score < cv_score) { action = SLIDE_ACTION_FEATHER; masklay = feather_masklay; spline = feather_spline; point = feather_point; } } if (cv_point && action == SLIDE_ACTION_NONE) { if (is_handle) action = SLIDE_ACTION_HANDLE; else action = SLIDE_ACTION_POINT; masklay = cv_masklay; spline = cv_spline; point = cv_point; } if (action != SLIDE_ACTION_NONE) { customdata = MEM_callocN(sizeof(SlidePointData), "mask slide point data"); customdata->mask = mask; customdata->masklay = masklay; customdata->spline = spline; customdata->point = point; customdata->width = width; customdata->height = height; customdata->action = action; customdata->uw = uw; if (uw) { float co_uw[2]; float weight_scalar = BKE_mask_point_weight_scalar(spline, point, uw->u); customdata->weight = uw->w; customdata->weight_scalar = weight_scalar; BKE_mask_point_segment_co(spline, point, uw->u, co_uw); BKE_mask_point_normal(spline, point, uw->u, customdata->no); madd_v2_v2v2fl(customdata->feather, co_uw, customdata->no, uw->w * weight_scalar); } else { BezTriple *bezt = &point->bezt; customdata->weight = bezt->weight; customdata->weight_scalar = 1.0f; BKE_mask_point_normal(spline, point, 0.0f, customdata->no); madd_v2_v2v2fl(customdata->feather, bezt->vec[1], customdata->no, bezt->weight); } if (customdata->action == SLIDE_ACTION_FEATHER) customdata->initial_feather = slide_point_check_initial_feather(spline); copy_m3_m3(customdata->vec, point->bezt.vec); if (BKE_mask_point_has_handle(point)) BKE_mask_point_handle(point, customdata->handle); ED_mask_mouse_pos(sa, ar, event->mval, customdata->co); } return customdata; }
/* called from within the core BKE_pose_where_is loop, all animsystems and constraints * were executed & assigned. Now as last we do an IK pass */ static void execute_posetree(struct Scene *scene, Object *ob, PoseTree *tree) { float R_parmat[3][3], identity[3][3]; float iR_parmat[3][3]; float R_bonemat[3][3]; float goalrot[3][3], goalpos[3]; float rootmat[4][4], imat[4][4]; float goal[4][4], goalinv[4][4]; float irest_basis[3][3], full_basis[3][3]; float end_pose[4][4], world_pose[4][4]; float length, basis[3][3], rest_basis[3][3], start[3], *ikstretch = NULL; float resultinf = 0.0f; int a, flag, hasstretch = 0, resultblend = 0; bPoseChannel *pchan; IK_Segment *seg, *parent, **iktree, *iktarget; IK_Solver *solver; PoseTarget *target; bKinematicConstraint *data, *poleangledata = NULL; Bone *bone; if (tree->totchannel == 0) return; iktree = MEM_mallocN(sizeof(void *) * tree->totchannel, "ik tree"); for (a = 0; a < tree->totchannel; a++) { pchan = tree->pchan[a]; bone = pchan->bone; /* set DoF flag */ flag = 0; if (!(pchan->ikflag & BONE_IK_NO_XDOF) && !(pchan->ikflag & BONE_IK_NO_XDOF_TEMP)) flag |= IK_XDOF; if (!(pchan->ikflag & BONE_IK_NO_YDOF) && !(pchan->ikflag & BONE_IK_NO_YDOF_TEMP)) flag |= IK_YDOF; if (!(pchan->ikflag & BONE_IK_NO_ZDOF) && !(pchan->ikflag & BONE_IK_NO_ZDOF_TEMP)) flag |= IK_ZDOF; if (tree->stretch && (pchan->ikstretch > 0.0f)) { flag |= IK_TRANS_YDOF; hasstretch = 1; } seg = iktree[a] = IK_CreateSegment(flag); /* find parent */ if (a == 0) parent = NULL; else parent = iktree[tree->parent[a]]; IK_SetParent(seg, parent); /* get the matrix that transforms from prevbone into this bone */ copy_m3_m4(R_bonemat, pchan->pose_mat); /* gather transformations for this IK segment */ if (pchan->parent) copy_m3_m4(R_parmat, pchan->parent->pose_mat); else unit_m3(R_parmat); /* bone offset */ if (pchan->parent && (a > 0)) sub_v3_v3v3(start, pchan->pose_head, pchan->parent->pose_tail); else /* only root bone (a = 0) has no parent */ start[0] = start[1] = start[2] = 0.0f; /* change length based on bone size */ length = bone->length * len_v3(R_bonemat[1]); /* compute rest basis and its inverse */ copy_m3_m3(rest_basis, bone->bone_mat); copy_m3_m3(irest_basis, bone->bone_mat); transpose_m3(irest_basis); /* compute basis with rest_basis removed */ invert_m3_m3(iR_parmat, R_parmat); mul_m3_m3m3(full_basis, iR_parmat, R_bonemat); mul_m3_m3m3(basis, irest_basis, full_basis); /* basis must be pure rotation */ normalize_m3(basis); /* transform offset into local bone space */ normalize_m3(iR_parmat); mul_m3_v3(iR_parmat, start); IK_SetTransform(seg, start, rest_basis, basis, length); if (pchan->ikflag & BONE_IK_XLIMIT) IK_SetLimit(seg, IK_X, pchan->limitmin[0], pchan->limitmax[0]); if (pchan->ikflag & BONE_IK_YLIMIT) IK_SetLimit(seg, IK_Y, pchan->limitmin[1], pchan->limitmax[1]); if (pchan->ikflag & BONE_IK_ZLIMIT) IK_SetLimit(seg, IK_Z, pchan->limitmin[2], pchan->limitmax[2]); IK_SetStiffness(seg, IK_X, pchan->stiffness[0]); IK_SetStiffness(seg, IK_Y, pchan->stiffness[1]); IK_SetStiffness(seg, IK_Z, pchan->stiffness[2]); if (tree->stretch && (pchan->ikstretch > 0.0f)) { const float ikstretch = pchan->ikstretch * pchan->ikstretch; /* this function does its own clamping */ IK_SetStiffness(seg, IK_TRANS_Y, 1.0f - ikstretch); IK_SetLimit(seg, IK_TRANS_Y, IK_STRETCH_STIFF_MIN, IK_STRETCH_STIFF_MAX); } } solver = IK_CreateSolver(iktree[0]); /* set solver goals */ /* first set the goal inverse transform, assuming the root of tree was done ok! */ pchan = tree->pchan[0]; if (pchan->parent) { /* transform goal by parent mat, so this rotation is not part of the * segment's basis. otherwise rotation limits do not work on the * local transform of the segment itself. */ copy_m4_m4(rootmat, pchan->parent->pose_mat); /* However, we do not want to get (i.e. reverse) parent's scale, as it generates [#31008] * kind of nasty bugs... */ normalize_m4(rootmat); } else unit_m4(rootmat); copy_v3_v3(rootmat[3], pchan->pose_head); mul_m4_m4m4(imat, ob->obmat, rootmat); invert_m4_m4(goalinv, imat); for (target = tree->targets.first; target; target = target->next) { float polepos[3]; int poleconstrain = 0; data = (bKinematicConstraint *)target->con->data; /* 1.0=ctime, we pass on object for auto-ik (owner-type here is object, even though * strictly speaking, it is a posechannel) */ BKE_constraint_target_matrix_get(scene, target->con, 0, CONSTRAINT_OBTYPE_OBJECT, ob, rootmat, 1.0); /* and set and transform goal */ mul_m4_m4m4(goal, goalinv, rootmat); copy_v3_v3(goalpos, goal[3]); copy_m3_m4(goalrot, goal); normalize_m3(goalrot); /* same for pole vector target */ if (data->poletar) { BKE_constraint_target_matrix_get(scene, target->con, 1, CONSTRAINT_OBTYPE_OBJECT, ob, rootmat, 1.0); if (data->flag & CONSTRAINT_IK_SETANGLE) { /* don't solve IK when we are setting the pole angle */ break; } else { mul_m4_m4m4(goal, goalinv, rootmat); copy_v3_v3(polepos, goal[3]); poleconstrain = 1; /* for pole targets, we blend the result of the ik solver * instead of the target position, otherwise we can't get * a smooth transition */ resultblend = 1; resultinf = target->con->enforce; if (data->flag & CONSTRAINT_IK_GETANGLE) { poleangledata = data; data->flag &= ~CONSTRAINT_IK_GETANGLE; } } } /* do we need blending? */ if (!resultblend && target->con->enforce != 1.0f) { float q1[4], q2[4], q[4]; float fac = target->con->enforce; float mfac = 1.0f - fac; pchan = tree->pchan[target->tip]; /* end effector in world space */ copy_m4_m4(end_pose, pchan->pose_mat); copy_v3_v3(end_pose[3], pchan->pose_tail); mul_serie_m4(world_pose, goalinv, ob->obmat, end_pose, NULL, NULL, NULL, NULL, NULL); /* blend position */ goalpos[0] = fac * goalpos[0] + mfac * world_pose[3][0]; goalpos[1] = fac * goalpos[1] + mfac * world_pose[3][1]; goalpos[2] = fac * goalpos[2] + mfac * world_pose[3][2]; /* blend rotation */ mat3_to_quat(q1, goalrot); mat4_to_quat(q2, world_pose); interp_qt_qtqt(q, q1, q2, mfac); quat_to_mat3(goalrot, q); } iktarget = iktree[target->tip]; if ((data->flag & CONSTRAINT_IK_POS) && data->weight != 0.0f) { if (poleconstrain) IK_SolverSetPoleVectorConstraint(solver, iktarget, goalpos, polepos, data->poleangle, (poleangledata == data)); IK_SolverAddGoal(solver, iktarget, goalpos, data->weight); } if ((data->flag & CONSTRAINT_IK_ROT) && (data->orientweight != 0.0f)) if ((data->flag & CONSTRAINT_IK_AUTO) == 0) IK_SolverAddGoalOrientation(solver, iktarget, goalrot, data->orientweight); } /* solve */ IK_Solve(solver, 0.0f, tree->iterations); if (poleangledata) poleangledata->poleangle = IK_SolverGetPoleAngle(solver); IK_FreeSolver(solver); /* gather basis changes */ tree->basis_change = MEM_mallocN(sizeof(float[3][3]) * tree->totchannel, "ik basis change"); if (hasstretch) ikstretch = MEM_mallocN(sizeof(float) * tree->totchannel, "ik stretch"); for (a = 0; a < tree->totchannel; a++) { IK_GetBasisChange(iktree[a], tree->basis_change[a]); if (hasstretch) { /* have to compensate for scaling received from parent */ float parentstretch, stretch; pchan = tree->pchan[a]; parentstretch = (tree->parent[a] >= 0) ? ikstretch[tree->parent[a]] : 1.0f; if (tree->stretch && (pchan->ikstretch > 0.0f)) { float trans[3], length; IK_GetTranslationChange(iktree[a], trans); length = pchan->bone->length * len_v3(pchan->pose_mat[1]); ikstretch[a] = (length == 0.0f) ? 1.0f : (trans[1] + length) / length; } else ikstretch[a] = 1.0; stretch = (parentstretch == 0.0f) ? 1.0f : ikstretch[a] / parentstretch; mul_v3_fl(tree->basis_change[a][0], stretch); mul_v3_fl(tree->basis_change[a][1], stretch); mul_v3_fl(tree->basis_change[a][2], stretch); } if (resultblend && resultinf != 1.0f) { unit_m3(identity); blend_m3_m3m3(tree->basis_change[a], identity, tree->basis_change[a], resultinf); } IK_FreeSegment(iktree[a]); } MEM_freeN(iktree); if (ikstretch) MEM_freeN(ikstretch); }
static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], int level, int animated) { Object *ob, *ob_iter; Base *base = NULL; DupliObject *dob; DerivedMesh *dm; Mesh *me= par->data; MLoopUV *mloopuv; MPoly *mpoly, *mp; MLoop *mloop; MVert *mvert; float pmat[4][4], imat[3][3], (*orco)[3] = NULL, w; int lay, oblay, totface, a; Scene *sce = NULL; Group *group = NULL; GroupObject *go = NULL; BMEditMesh *em; float ob__obmat[4][4]; /* needed for groups where the object matrix needs to be modified */ /* simple preventing of too deep nested groups */ if (level>MAX_DUPLI_RECUR) return; copy_m4_m4(pmat, par->obmat); em = me->edit_btmesh; if (em) { dm= editbmesh_get_derived_cage(scene, par, em, CD_MASK_BAREMESH); } else { dm = mesh_get_derived_deform(scene, par, CD_MASK_BAREMESH); } totface= dm->getNumPolys(dm); mpoly= dm->getPolyArray(dm); mloop= dm->getLoopArray(dm); mvert= dm->getVertArray(dm); if (G.rendering) { orco= (float(*)[3])get_mesh_orco_verts(par); transform_mesh_orco_verts(me, orco, me->totvert, 0); mloopuv= me->mloopuv; } else { orco= NULL; mloopuv= NULL; } /* having to loop on scene OR group objects is NOT FUN */ if (GS(id->name) == ID_SCE) { sce = (Scene *)id; lay= sce->lay; base= sce->base.first; } else { group = (Group *)id; lay= group->layer; go = group->gobject.first; } /* Start looping on Scene OR Group objects */ while (base || go) { if (sce) { ob_iter= base->object; oblay = base->lay; } else { ob_iter= go->ob; oblay = ob_iter->lay; } if (lay & oblay && scene->obedit!=ob_iter) { ob=ob_iter->parent; while (ob) { if (ob==par) { ob = ob_iter; /* End Scene/Group object loop, below is generic */ /* par_space_mat - only used for groups so we can modify the space dupli's are in * when par_space_mat is NULL ob->obmat can be used instead of ob__obmat */ if (par_space_mat) mult_m4_m4m4(ob__obmat, par_space_mat, ob->obmat); else copy_m4_m4(ob__obmat, ob->obmat); copy_m3_m4(imat, ob->parentinv); /* mballs have a different dupli handling */ if (ob->type!=OB_MBALL) ob->flag |= OB_DONE; /* doesnt render */ for (a=0, mp= mpoly; a<totface; a++, mp++) { int mv1; int mv2; int mv3; /* int mv4; */ /* UNUSED */ float *v1; float *v2; float *v3; /* float *v4; */ /* UNUSED */ float cent[3], quat[4], mat[3][3], mat3[3][3], tmat[4][4], obmat[4][4]; MLoop *loopstart= mloop + mp->loopstart; if (mp->totloop < 3) { /* highly unlikely but to be safe */ continue; } else { v1= mvert[(mv1= loopstart[0].v)].co; v2= mvert[(mv2= loopstart[1].v)].co; v3= mvert[(mv3= loopstart[2].v)].co; #if 0 if (mp->totloop > 3) { v4= mvert[(mv4= loopstart[3].v)].co; } #endif } /* translation */ mesh_calc_poly_center(mp, loopstart, mvert, cent); mul_m4_v3(pmat, cent); sub_v3_v3v3(cent, cent, pmat[3]); add_v3_v3(cent, ob__obmat[3]); copy_m4_m4(obmat, ob__obmat); copy_v3_v3(obmat[3], cent); /* rotation */ tri_to_quat( quat,v1, v2, v3); quat_to_mat3( mat,quat); /* scale */ if (par->transflag & OB_DUPLIFACES_SCALE) { float size= mesh_calc_poly_area(mp, loopstart, mvert, NULL); size= sqrtf(size) * par->dupfacesca; mul_m3_fl(mat, size); } copy_m3_m3(mat3, mat); mul_m3_m3m3(mat, imat, mat3); copy_m4_m4(tmat, obmat); mul_m4_m4m3(obmat, tmat, mat); dob= new_dupli_object(lb, ob, obmat, par->lay, a, OB_DUPLIFACES, animated); if (G.rendering) { w= 1.0f / (float)mp->totloop; if (orco) { int j; for (j = 0; j < mpoly->totloop; j++) { madd_v3_v3fl(dob->orco, orco[loopstart[j].v], w); } } if (mloopuv) { int j; for (j = 0; j < mpoly->totloop; j++) { madd_v2_v2fl(dob->orco, mloopuv[loopstart[j].v].uv, w); } } } if (ob->transflag & OB_DUPLI) { float tmpmat[4][4]; copy_m4_m4(tmpmat, ob->obmat); copy_m4_m4(ob->obmat, obmat); /* pretend we are really this mat */ object_duplilist_recursive((ID *)id, scene, ob, lb, ob->obmat, level+1, animated); copy_m4_m4(ob->obmat, tmpmat); } } break; } ob= ob->parent; } } if (sce) base= base->next; /* scene loop */ else go= go->next; /* group loop */ } if (orco) MEM_freeN(orco); dm->release(dm); }
static void cloth_hair_update_bending_targets(ClothModifierData *clmd) { Cloth *cloth = clmd->clothObject; LinkNode *search = NULL; float hair_frame[3][3], dir_old[3], dir_new[3]; int prev_mn; /* to find hair chains */ if (!clmd->hairdata) return; /* XXX Note: we need to propagate frames from the root up, * but structural hair springs are stored in reverse order. * The bending springs however are then inserted in the same * order as vertices again ... * This messy situation can be resolved when solver data is * generated directly from a dedicated hair system. */ prev_mn = -1; for (search = cloth->springs; search; search = search->next) { ClothSpring *spring = search->link; ClothHairData *hair_ij, *hair_kl; bool is_root = spring->kl != prev_mn; if (spring->type != CLOTH_SPRING_TYPE_BENDING_ANG) { continue; } hair_ij = &clmd->hairdata[spring->ij]; hair_kl = &clmd->hairdata[spring->kl]; if (is_root) { /* initial hair frame from root orientation */ copy_m3_m3(hair_frame, hair_ij->rot); /* surface normal is the initial direction, * parallel transport then keeps it aligned to the hair direction */ copy_v3_v3(dir_new, hair_frame[2]); } copy_v3_v3(dir_old, dir_new); sub_v3_v3v3(dir_new, cloth->verts[spring->mn].x, cloth->verts[spring->kl].x); normalize_v3(dir_new); #if 0 if (clmd->debug_data && (spring->ij == 0 || spring->ij == 1)) { float a[3], b[3]; copy_v3_v3(a, cloth->verts[spring->kl].x); // BKE_sim_debug_data_add_dot(clmd->debug_data, cloth_vert ? cloth_vert->x : key->co, 1, 1, 0, "frames", 8246, p, k); mul_v3_v3fl(b, hair_frame[0], clmd->sim_parms->avg_spring_len); BKE_sim_debug_data_add_vector(clmd->debug_data, a, b, 1, 0, 0, "frames", 8247, spring->kl, spring->mn); mul_v3_v3fl(b, hair_frame[1], clmd->sim_parms->avg_spring_len); BKE_sim_debug_data_add_vector(clmd->debug_data, a, b, 0, 1, 0, "frames", 8248, spring->kl, spring->mn); mul_v3_v3fl(b, hair_frame[2], clmd->sim_parms->avg_spring_len); BKE_sim_debug_data_add_vector(clmd->debug_data, a, b, 0, 0, 1, "frames", 8249, spring->kl, spring->mn); } #endif /* get local targets for kl/mn vertices by putting rest targets into the current frame, * then multiply with the rest length to get the actual goals */ mul_v3_m3v3(spring->target, hair_frame, hair_kl->rest_target); mul_v3_fl(spring->target, spring->restlen); /* move frame to next hair segment */ cloth_parallel_transport_hair_frame(hair_frame, dir_old, dir_new); prev_mn = spring->mn; } }