/* returns standard diameter */ static float new_primitive_matrix(bContext *C, float *loc, float *rot, float primmat[][4]) { Object *obedit = CTX_data_edit_object(C); View3D *v3d = CTX_wm_view3d(C); float mat[3][3], rmat[3][3], cmat[3][3], imat[3][3]; unit_m4(primmat); eul_to_mat3(rmat, rot); invert_m3(rmat); /* inverse transform for initial rotation and object */ copy_m3_m4(mat, obedit->obmat); mul_m3_m3m3(cmat, rmat, mat); invert_m3_m3(imat, cmat); copy_m4_m3(primmat, imat); /* center */ copy_v3_v3(primmat[3], loc); sub_v3_v3(primmat[3], obedit->obmat[3]); invert_m3_m3(imat, mat); mul_m3_v3(imat, primmat[3]); return v3d ? v3d->grid : 1.0f; }
void getConstraintMatrix(TransInfo *t) { float mat[3][3]; invert_m3_m3(t->con.imtx, t->con.mtx); unit_m3(t->con.pmtx); if (!(t->con.mode & CON_AXIS0)) { t->con.pmtx[0][0] = t->con.pmtx[0][1] = t->con.pmtx[0][2] = 0.0f; } if (!(t->con.mode & CON_AXIS1)) { t->con.pmtx[1][0] = t->con.pmtx[1][1] = t->con.pmtx[1][2] = 0.0f; } if (!(t->con.mode & CON_AXIS2)) { t->con.pmtx[2][0] = t->con.pmtx[2][1] = t->con.pmtx[2][2] = 0.0f; } mul_m3_m3m3(mat, t->con.pmtx, t->con.imtx); mul_m3_m3m3(t->con.pmtx, t->con.mtx, mat); }
/* v3d and rv3d are allowed to be NULL */ void add_primitive_bone(Scene *scene, View3D *v3d, RegionView3D *rv3d) { Object *obedit = scene->obedit; // XXX get from context bArmature *arm = obedit->data; float obmat[3][3], curs[3], viewmat[3][3], totmat[3][3], imat[3][3]; EditBone *bone; /* Get inverse point for head and orientation for tail */ invert_m4_m4(obedit->imat, obedit->obmat); mul_v3_m4v3(curs, obedit->imat, give_cursor(scene, v3d)); if (rv3d && (U.flag & USER_ADD_VIEWALIGNED)) copy_m3_m4(obmat, rv3d->viewmat); else unit_m3(obmat); copy_m3_m4(viewmat, obedit->obmat); mul_m3_m3m3(totmat, obmat, viewmat); invert_m3_m3(imat, totmat); ED_armature_deselect_all(obedit, 0); /* Create a bone */ bone = ED_armature_edit_bone_add(arm, "Bone"); arm->act_edbone = bone; copy_v3_v3(bone->head, curs); if (rv3d && (U.flag & USER_ADD_VIEWALIGNED)) add_v3_v3v3(bone->tail, bone->head, imat[1]); // bone with unit length 1 else add_v3_v3v3(bone->tail, bone->head, imat[2]); // bone with unit length 1, pointing up Z }
static void applyObjectConstraintSize(TransInfo *t, TransData *td, float smat[3][3]) { if (td && t->con.mode & CON_APPLY) { float tmat[3][3]; float imat[3][3]; invert_m3_m3(imat, td->axismtx); if (!(t->con.mode & CON_AXIS0)) { smat[0][0] = 1.0f; } if (!(t->con.mode & CON_AXIS1)) { smat[1][1] = 1.0f; } if (!(t->con.mode & CON_AXIS2)) { smat[2][2] = 1.0f; } mul_m3_m3m3(tmat, smat, imat); if (t->flag & T_EDIT) { mul_m3_m3m3(smat, t->obedit_mat, smat); } mul_m3_m3m3(smat, td->axismtx, tmat); } }
void env_rotate_scene(Render *re, float mat[4][4], int do_rotate) { GroupObject *go; ObjectRen *obr; ObjectInstanceRen *obi; LampRen *lar = NULL; HaloRen *har = NULL; float imat[3][3], mat_inverse[4][4], smat[4][4], tmat[4][4], cmat[3][3], tmpmat[4][4]; int a; if (do_rotate == 0) { invert_m4_m4(tmat, mat); copy_m3_m4(imat, tmat); copy_m4_m4(mat_inverse, mat); } else { copy_m4_m4(tmat, mat); copy_m3_m4(imat, mat); invert_m4_m4(mat_inverse, tmat); } for (obi = re->instancetable.first; obi; obi = obi->next) { /* append or set matrix depending on dupli */ if (obi->flag & R_DUPLI_TRANSFORMED) { copy_m4_m4(tmpmat, obi->mat); mul_m4_m4m4(obi->mat, tmat, tmpmat); } else if (do_rotate == 1) copy_m4_m4(obi->mat, tmat); else unit_m4(obi->mat); copy_m3_m4(cmat, obi->mat); invert_m3_m3(obi->nmat, cmat); transpose_m3(obi->nmat); /* indicate the renderer has to use transform matrices */ if (do_rotate == 0) obi->flag &= ~R_ENV_TRANSFORMED; else { obi->flag |= R_ENV_TRANSFORMED; copy_m4_m4(obi->imat, mat_inverse); } } for (obr = re->objecttable.first; obr; obr = obr->next) { for (a = 0; a < obr->tothalo; a++) { if ((a & 255) == 0) har = obr->bloha[a >> 8]; else har++; mul_m4_v3(tmat, har->co); } /* imat_ren is needed for correct texture coordinates */ mul_m4_m4m4(obr->ob->imat_ren, re->viewmat, obr->ob->obmat); invert_m4(obr->ob->imat_ren); }
static int object_hook_recenter_exec(bContext *C, wmOperator *op) { PointerRNA ptr= CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier); int num= RNA_enum_get(op->ptr, "modifier"); Object *ob=NULL; HookModifierData *hmd=NULL; Scene *scene = CTX_data_scene(C); float bmat[3][3], imat[3][3]; if (ptr.data) { /* if modifier context is available, use that */ ob = ptr.id.data; hmd= ptr.data; } else { /* use the provided property */ ob = CTX_data_edit_object(C); hmd = (HookModifierData *)BLI_findlink(&ob->modifiers, num); } if (!ob || !hmd) { BKE_report(op->reports, RPT_ERROR, "Couldn't find hook modifier"); return OPERATOR_CANCELLED; } /* recenter functionality */ copy_m3_m4(bmat, ob->obmat); invert_m3_m3(imat, bmat); sub_v3_v3v3(hmd->cent, scene->cursor, ob->obmat[3]); mul_m3_v3(imat, hmd->cent); DAG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob); return OPERATOR_FINISHED; }
static void flush_pixel(const MResolvePixelData *data, const int x, const int y) { float st[2] = {(x + 0.5f) / data->w, (y + 0.5f) / data->h}; float *st0, *st1, *st2; float *tang0, *tang1, *tang2; float no0[3], no1[3], no2[3]; float fUV[2], from_tang[3][3], to_tang[3][3]; float u, v, w, sign; int r; const int i0 = data->i0; const int i1 = data->i1; const int i2 = data->i2; st0 = data->mtface[data->face_index].uv[i0]; st1 = data->mtface[data->face_index].uv[i1]; st2 = data->mtface[data->face_index].uv[i2]; multiresbake_get_normal(data, no0, data->face_index, i0); /* can optimize these 3 into one call */ multiresbake_get_normal(data, no1, data->face_index, i1); multiresbake_get_normal(data, no2, data->face_index, i2); resolve_tri_uv(fUV, st, st0, st1, st2); u = fUV[0]; v = fUV[1]; w = 1 - u - v; if (data->pvtangent) { tang0 = data->pvtangent + data->face_index * 16 + i0 * 4; tang1 = data->pvtangent + data->face_index * 16 + i1 * 4; tang2 = data->pvtangent + data->face_index * 16 + i2 * 4; /* the sign is the same at all face vertices for any non degenerate face. * Just in case we clamp the interpolated value though. */ sign = (tang0[3] * u + tang1[3] * v + tang2[3] * w) < 0 ? (-1.0f) : 1.0f; /* this sequence of math is designed specifically as is with great care * to be compatible with our shader. Please don't change without good reason. */ for (r = 0; r < 3; r++) { from_tang[0][r] = tang0[r] * u + tang1[r] * v + tang2[r] * w; from_tang[2][r] = no0[r] * u + no1[r] * v + no2[r] * w; } cross_v3_v3v3(from_tang[1], from_tang[2], from_tang[0]); /* B = sign * cross(N, T) */ mul_v3_fl(from_tang[1], sign); invert_m3_m3(to_tang, from_tang); } else { zero_m3(to_tang); } data->pass_data(data->lores_dm, data->hires_dm, data->bake_data, data->ibuf, data->face_index, data->lvl, st, to_tang, x, y); }
static void multires_reshape_vertex_from_final_data(MultiresReshapeContext *ctx, const int ptex_face_index, const float corner_u, const float corner_v, const int coarse_poly_index, const int coarse_corner, const float final_P[3], const float final_mask) { Subdiv *subdiv = ctx->subdiv; const int grid_size = ctx->top_grid_size; const Mesh *coarse_mesh = ctx->coarse_mesh; const MPoly *coarse_mpoly = coarse_mesh->mpoly; const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index]; const int loop_index = coarse_poly->loopstart + coarse_corner; /* Evaluate limit surface. */ float P[3], dPdu[3], dPdv[3]; multires_reshape_sample_surface( subdiv, coarse_poly, coarse_corner, corner_u, corner_v, ptex_face_index, P, dPdu, dPdv); /* Construct tangent matrix which matches orientation of the current * displacement grid. */ float tangent_matrix[3][3], inv_tangent_matrix[3][3]; multires_reshape_tangent_matrix_for_corner( coarse_poly, coarse_corner, dPdu, dPdv, tangent_matrix); invert_m3_m3(inv_tangent_matrix, tangent_matrix); /* Convert object coordinate to a tangent space of displacement grid. */ float D[3]; sub_v3_v3v3(D, final_P, P); float tangent_D[3]; mul_v3_m3v3(tangent_D, inv_tangent_matrix, D); /* Calculate index of element within the grid. */ float grid_u, grid_v; BKE_subdiv_ptex_face_uv_to_grid_uv(corner_u, corner_v, &grid_u, &grid_v); const int grid_x = (grid_u * (grid_size - 1) + 0.5f); const int grid_y = (grid_v * (grid_size - 1) + 0.5f); const int index = grid_y * grid_size + grid_x; /* Write tangent displacement. */ MDisps *displacement_grid = &ctx->mdisps[loop_index]; copy_v3_v3(displacement_grid->disps[index], tangent_D); /* Write mask grid. */ if (ctx->grid_paint_mask != NULL) { GridPaintMask *grid_paint_mask = &ctx->grid_paint_mask[loop_index]; BLI_assert(grid_paint_mask->level == displacement_grid->level); grid_paint_mask->data[index] = final_mask; } }
static void imapaint_tri_weights(Object *ob, const float v1[3], const float v2[3], const float v3[3], const float co[2], float w[3]) { float pv1[4], pv2[4], pv3[4], h[3], divw; float model[4][4], proj[4][4], wmat[3][3], invwmat[3][3]; GLint view[4]; /* compute barycentric coordinates */ /* get the needed opengl matrices */ glGetIntegerv(GL_VIEWPORT, view); glGetFloatv(GL_MODELVIEW_MATRIX, (float *)model); glGetFloatv(GL_PROJECTION_MATRIX, (float *)proj); view[0] = view[1] = 0; /* project the verts */ imapaint_project(ob, model, proj, v1, pv1); imapaint_project(ob, model, proj, v2, pv2); imapaint_project(ob, model, proj, v3, pv3); /* do inverse view mapping, see gluProject man page */ h[0] = (co[0] - view[0]) * 2.0f / view[2] - 1; h[1] = (co[1] - view[1]) * 2.0f / view[3] - 1; h[2] = 1.0f; /* solve for (w1,w2,w3)/perspdiv in: * h * perspdiv = Project * Model * (w1 * v1 + w2 * v2 + w3 * v3) */ wmat[0][0] = pv1[0]; wmat[1][0] = pv2[0]; wmat[2][0] = pv3[0]; wmat[0][1] = pv1[1]; wmat[1][1] = pv2[1]; wmat[2][1] = pv3[1]; wmat[0][2] = pv1[3]; wmat[1][2] = pv2[3]; wmat[2][2] = pv3[3]; invert_m3_m3(invwmat, wmat); mul_m3_v3(invwmat, h); copy_v3_v3(w, h); /* w is still divided by perspdiv, make it sum to one */ divw = w[0] + w[1] + w[2]; if (divw != 0.0f) { mul_v3_fl(w, 1.0f / divw); } }
/** * This calculates #CorrectiveSmoothModifierData.delta_cache * It's not run on every update (during animation for example). */ static void calc_deltas(CorrectiveSmoothModifierData *csmd, Mesh *mesh, MDeformVert *dvert, const int defgrp_index, const float (*rest_coords)[3], unsigned int numVerts) { float(*smooth_vertex_coords)[3] = MEM_dupallocN(rest_coords); float(*tangent_spaces)[3][3]; unsigned int i; tangent_spaces = MEM_calloc_arrayN(numVerts, sizeof(float[3][3]), __func__); if (csmd->delta_cache_num != numVerts) { MEM_SAFE_FREE(csmd->delta_cache); } /* allocate deltas if they have not yet been allocated, otheriwse we will just write over them */ if (!csmd->delta_cache) { csmd->delta_cache_num = numVerts; csmd->delta_cache = MEM_malloc_arrayN(numVerts, sizeof(float[3]), __func__); } smooth_verts(csmd, mesh, dvert, defgrp_index, smooth_vertex_coords, numVerts); calc_tangent_spaces(mesh, smooth_vertex_coords, tangent_spaces); for (i = 0; i < numVerts; i++) { float imat[3][3], delta[3]; #ifdef USE_TANGENT_CALC_INLINE calc_tangent_ortho(tangent_spaces[i]); #endif sub_v3_v3v3(delta, rest_coords[i], smooth_vertex_coords[i]); if (UNLIKELY(!invert_m3_m3(imat, tangent_spaces[i]))) { transpose_m3_m3(imat, tangent_spaces[i]); } mul_v3_m3v3(csmd->delta_cache[i], imat, delta); } MEM_freeN(tangent_spaces); MEM_freeN(smooth_vertex_coords); }
/* also sets restposition in armature (arm_mat) */ static void fix_bonelist_roll(ListBase *bonelist, ListBase *editbonelist) { Bone *curBone; EditBone *ebone; float premat[3][3]; float postmat[3][3]; float difmat[3][3]; float imat[3][3]; for (curBone = bonelist->first; curBone; curBone = curBone->next) { /* sets local matrix and arm_mat (restpos) */ BKE_armature_where_is_bone(curBone, curBone->parent); /* Find the associated editbone */ for (ebone = editbonelist->first; ebone; ebone = ebone->next) if (ebone->temp.bone == curBone) break; if (ebone) { /* Get the ebone premat */ ED_armature_ebone_to_mat3(ebone, premat); /* Get the bone postmat */ copy_m3_m4(postmat, curBone->arm_mat); invert_m3_m3(imat, premat); mul_m3_m3m3(difmat, imat, postmat); #if 0 printf("Bone %s\n", curBone->name); print_m4("premat", premat); print_m4("postmat", postmat); print_m4("difmat", difmat); printf("Roll = %f\n", RAD2DEGF(-atan2(difmat[2][0], difmat[2][2]))); #endif curBone->roll = -atan2f(difmat[2][0], difmat[2][2]); /* and set restposition again */ BKE_armature_where_is_bone(curBone, curBone->parent); } fix_bonelist_roll(&curBone->childbase, editbonelist); } }
static int armature_bone_primitive_add_exec(bContext *C, wmOperator *op) { RegionView3D *rv3d = CTX_wm_region_view3d(C); Object *obedit = CTX_data_edit_object(C); EditBone *bone; float obmat[3][3], curs[3], viewmat[3][3], totmat[3][3], imat[3][3]; char name[MAXBONENAME]; RNA_string_get(op->ptr, "name", name); copy_v3_v3(curs, ED_view3d_cursor3d_get(CTX_data_scene(C), CTX_wm_view3d(C))); /* Get inverse point for head and orientation for tail */ invert_m4_m4(obedit->imat, obedit->obmat); mul_m4_v3(obedit->imat, curs); if (rv3d && (U.flag & USER_ADD_VIEWALIGNED)) copy_m3_m4(obmat, rv3d->viewmat); else unit_m3(obmat); copy_m3_m4(viewmat, obedit->obmat); mul_m3_m3m3(totmat, obmat, viewmat); invert_m3_m3(imat, totmat); ED_armature_deselect_all(obedit); /* Create a bone */ bone = ED_armature_edit_bone_add(obedit->data, name); copy_v3_v3(bone->head, curs); if (rv3d && (U.flag & USER_ADD_VIEWALIGNED)) add_v3_v3v3(bone->tail, bone->head, imat[1]); // bone with unit length 1 else add_v3_v3v3(bone->tail, bone->head, imat[2]); // bone with unit length 1, pointing up Z /* note, notifier might evolve */ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); return OPERATOR_FINISHED; }
static void imapaint_tri_weights(float matrix[4][4], GLint view[4], const float v1[3], const float v2[3], const float v3[3], const float co[2], float w[3]) { float pv1[4], pv2[4], pv3[4], h[3], divw; float wmat[3][3], invwmat[3][3]; /* compute barycentric coordinates */ /* project the verts */ imapaint_project(matrix, v1, pv1); imapaint_project(matrix, v2, pv2); imapaint_project(matrix, v3, pv3); /* do inverse view mapping, see gluProject man page */ h[0] = (co[0] - view[0]) * 2.0f / view[2] - 1.0f; h[1] = (co[1] - view[1]) * 2.0f / view[3] - 1.0f; h[2] = 1.0f; /* solve for (w1,w2,w3)/perspdiv in: * h * perspdiv = Project * Model * (w1 * v1 + w2 * v2 + w3 * v3) */ wmat[0][0] = pv1[0]; wmat[1][0] = pv2[0]; wmat[2][0] = pv3[0]; wmat[0][1] = pv1[1]; wmat[1][1] = pv2[1]; wmat[2][1] = pv3[1]; wmat[0][2] = pv1[3]; wmat[1][2] = pv2[3]; wmat[2][2] = pv3[3]; invert_m3_m3(invwmat, wmat); mul_m3_v3(invwmat, h); copy_v3_v3(w, h); /* w is still divided by perspdiv, make it sum to one */ divw = w[0] + w[1] + w[2]; if (divw != 0.0f) { mul_v3_fl(w, 1.0f / divw); } }
/* This function: * - sets local head/tail rest locations using parent bone's arm_mat. * - calls BKE_armature_where_is_bone() which uses parent's transform (arm_mat) to define this bone's transform. * - fixes (converts) EditBone roll into Bone roll. * - calls again BKE_armature_where_is_bone(), since roll fiddling may have changed things for our bone... * Note that order is crucial here, we can only handle child if all its parents in chain have already been handled * (this is ensured by recursive process). */ static void armature_finalize_restpose(ListBase *bonelist, ListBase *editbonelist) { Bone *curBone; EditBone *ebone; for (curBone = bonelist->first; curBone; curBone = curBone->next) { /* Set bone's local head/tail. * Note that it's important to use final parent's restpose (arm_mat) here, instead of setting those values * from editbone's matrix (see T46010). */ if (curBone->parent) { float parmat_inv[4][4]; invert_m4_m4(parmat_inv, curBone->parent->arm_mat); /* Get the new head and tail */ sub_v3_v3v3(curBone->head, curBone->arm_head, curBone->parent->arm_tail); sub_v3_v3v3(curBone->tail, curBone->arm_tail, curBone->parent->arm_tail); mul_mat3_m4_v3(parmat_inv, curBone->head); mul_mat3_m4_v3(parmat_inv, curBone->tail); } else { copy_v3_v3(curBone->head, curBone->arm_head); copy_v3_v3(curBone->tail, curBone->arm_tail); } /* Set local matrix and arm_mat (restpose). * Do not recurse into children here, armature_finalize_restpose() is already recursive. */ BKE_armature_where_is_bone(curBone, curBone->parent, false); /* Find the associated editbone */ for (ebone = editbonelist->first; ebone; ebone = ebone->next) { if (ebone->temp.bone == curBone) { float premat[3][3]; float postmat[3][3]; float difmat[3][3]; float imat[3][3]; /* Get the ebone premat and its inverse. */ ED_armature_ebone_to_mat3(ebone, premat); invert_m3_m3(imat, premat); /* Get the bone postmat. */ copy_m3_m4(postmat, curBone->arm_mat); mul_m3_m3m3(difmat, imat, postmat); #if 0 printf("Bone %s\n", curBone->name); print_m4("premat", premat); print_m4("postmat", postmat); print_m4("difmat", difmat); printf("Roll = %f\n", RAD2DEGF(-atan2(difmat[2][0], difmat[2][2]))); #endif curBone->roll = -atan2f(difmat[2][0], difmat[2][2]); /* and set restposition again */ BKE_armature_where_is_bone(curBone, curBone->parent, false); break; } } /* Recurse into children... */ armature_finalize_restpose(&curBone->childbase, editbonelist); } }
static int snap_selected_to_location(bContext *C, const float snap_target_global[3], const bool use_offset) { Scene *scene = CTX_data_scene(C); Object *obedit = CTX_data_edit_object(C); Object *obact = CTX_data_active_object(C); View3D *v3d = CTX_wm_view3d(C); TransVertStore tvs = {NULL}; TransVert *tv; float imat[3][3], bmat[3][3]; float center_global[3]; float offset_global[3]; int a; if (use_offset) { if ((v3d && v3d->around == V3D_AROUND_ACTIVE) && snap_calc_active_center(C, true, center_global)) { /* pass */ } else { snap_curs_to_sel_ex(C, center_global); } sub_v3_v3v3(offset_global, snap_target_global, center_global); } if (obedit) { float snap_target_local[3]; if (ED_transverts_check_obedit(obedit)) ED_transverts_create_from_obedit(&tvs, obedit, 0); if (tvs.transverts_tot == 0) return OPERATOR_CANCELLED; copy_m3_m4(bmat, obedit->obmat); invert_m3_m3(imat, bmat); /* get the cursor in object space */ sub_v3_v3v3(snap_target_local, snap_target_global, obedit->obmat[3]); mul_m3_v3(imat, snap_target_local); if (use_offset) { float offset_local[3]; mul_v3_m3v3(offset_local, imat, offset_global); tv = tvs.transverts; for (a = 0; a < tvs.transverts_tot; a++, tv++) { add_v3_v3(tv->loc, offset_local); } } else { tv = tvs.transverts; for (a = 0; a < tvs.transverts_tot; a++, tv++) { copy_v3_v3(tv->loc, snap_target_local); } } ED_transverts_update_obedit(&tvs, obedit); ED_transverts_free(&tvs); } else if (obact && (obact->mode & OB_MODE_POSE)) { struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID); bPoseChannel *pchan; bArmature *arm = obact->data; float snap_target_local[3]; invert_m4_m4(obact->imat, obact->obmat); mul_v3_m4v3(snap_target_local, obact->imat, snap_target_global); for (pchan = obact->pose->chanbase.first; pchan; pchan = pchan->next) { if ((pchan->bone->flag & BONE_SELECTED) && (PBONE_VISIBLE(arm, pchan->bone)) && /* if the bone has a parent and is connected to the parent, * don't do anything - will break chain unless we do auto-ik. */ (pchan->bone->flag & BONE_CONNECTED) == 0) { pchan->bone->flag |= BONE_TRANSFORM; } else { pchan->bone->flag &= ~BONE_TRANSFORM; } } for (pchan = obact->pose->chanbase.first; pchan; pchan = pchan->next) { if ((pchan->bone->flag & BONE_TRANSFORM) && /* check that our parents not transformed (if we have one) */ ((pchan->bone->parent && BKE_armature_bone_flag_test_recursive(pchan->bone->parent, BONE_TRANSFORM)) == 0)) { /* Get position in pchan (pose) space. */ float cursor_pose[3]; if (use_offset) { mul_v3_m4v3(cursor_pose, obact->obmat, pchan->pose_mat[3]); add_v3_v3(cursor_pose, offset_global); mul_m4_v3(obact->imat, cursor_pose); BKE_armature_loc_pose_to_bone(pchan, cursor_pose, cursor_pose); } else { BKE_armature_loc_pose_to_bone(pchan, snap_target_local, cursor_pose); } /* copy new position */ if ((pchan->protectflag & OB_LOCK_LOCX) == 0) pchan->loc[0] = cursor_pose[0]; if ((pchan->protectflag & OB_LOCK_LOCY) == 0) pchan->loc[1] = cursor_pose[1]; if ((pchan->protectflag & OB_LOCK_LOCZ) == 0) pchan->loc[2] = cursor_pose[2]; /* auto-keyframing */ ED_autokeyframe_pchan(C, scene, obact, pchan, ks); } } for (pchan = obact->pose->chanbase.first; pchan; pchan = pchan->next) { pchan->bone->flag &= ~BONE_TRANSFORM; } obact->pose->flag |= (POSE_LOCKED | POSE_DO_UNLOCK); DAG_id_tag_update(&obact->id, OB_RECALC_DATA); } else { struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID); Main *bmain = CTX_data_main(C); ListBase ctx_data_list; CollectionPointerLink *ctx_ob; Object *ob; CTX_data_selected_editable_objects(C, &ctx_data_list); /* reset flags */ for (ob = bmain->object.first; ob; ob = ob->id.next) { ob->flag &= ~OB_DONE; } /* tag objects we're transforming */ for (ctx_ob = ctx_data_list.first; ctx_ob; ctx_ob = ctx_ob->next) { ob = ctx_ob->ptr.data; ob->flag |= OB_DONE; } for (ctx_ob = ctx_data_list.first; ctx_ob; ctx_ob = ctx_ob->next) { ob = ctx_ob->ptr.data; if ((ob->parent && BKE_object_flag_test_recursive(ob->parent, OB_DONE)) == 0) { float cursor_parent[3]; /* parent-relative */ if (use_offset) { add_v3_v3v3(cursor_parent, ob->obmat[3], offset_global); } else { copy_v3_v3(cursor_parent, snap_target_global); } sub_v3_v3(cursor_parent, ob->obmat[3]); if (ob->parent) { float originmat[3][3]; BKE_object_where_is_calc_ex(scene, NULL, ob, originmat); invert_m3_m3(imat, originmat); mul_m3_v3(imat, cursor_parent); } if ((ob->protectflag & OB_LOCK_LOCX) == 0) ob->loc[0] += cursor_parent[0]; if ((ob->protectflag & OB_LOCK_LOCY) == 0) ob->loc[1] += cursor_parent[1]; if ((ob->protectflag & OB_LOCK_LOCZ) == 0) ob->loc[2] += cursor_parent[2]; /* auto-keyframing */ ED_autokeyframe_object(C, scene, ob, ks); DAG_id_tag_update(&ob->id, OB_RECALC_OB); } } BLI_freelistN(&ctx_data_list); } WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); return OPERATOR_FINISHED; }
static int snap_sel_to_grid_exec(bContext *C, wmOperator *UNUSED(op)) { Object *obedit = CTX_data_edit_object(C); Scene *scene = CTX_data_scene(C); RegionView3D *rv3d = CTX_wm_region_data(C); TransVertStore tvs = {NULL}; TransVert *tv; float gridf, imat[3][3], bmat[3][3], vec[3]; int a; gridf = rv3d->gridview; if (obedit) { if (ED_transverts_check_obedit(obedit)) ED_transverts_create_from_obedit(&tvs, obedit, 0); if (tvs.transverts_tot == 0) return OPERATOR_CANCELLED; copy_m3_m4(bmat, obedit->obmat); invert_m3_m3(imat, bmat); tv = tvs.transverts; for (a = 0; a < tvs.transverts_tot; a++, tv++) { copy_v3_v3(vec, tv->loc); mul_m3_v3(bmat, vec); add_v3_v3(vec, obedit->obmat[3]); vec[0] = gridf * floorf(0.5f + vec[0] / gridf); vec[1] = gridf * floorf(0.5f + vec[1] / gridf); vec[2] = gridf * floorf(0.5f + vec[2] / gridf); sub_v3_v3(vec, obedit->obmat[3]); mul_m3_v3(imat, vec); copy_v3_v3(tv->loc, vec); } ED_transverts_update_obedit(&tvs, obedit); ED_transverts_free(&tvs); } else { struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID); CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { if (ob->mode & OB_MODE_POSE) { bPoseChannel *pchan; bArmature *arm = ob->data; invert_m4_m4(ob->imat, ob->obmat); for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { if (pchan->bone->flag & BONE_SELECTED) { if (pchan->bone->layer & arm->layer) { if ((pchan->bone->flag & BONE_CONNECTED) == 0) { float nLoc[3]; /* get nearest grid point to snap to */ copy_v3_v3(nLoc, pchan->pose_mat[3]); /* We must operate in world space! */ mul_m4_v3(ob->obmat, nLoc); vec[0] = gridf * floorf(0.5f + nLoc[0] / gridf); vec[1] = gridf * floorf(0.5f + nLoc[1] / gridf); vec[2] = gridf * floorf(0.5f + nLoc[2] / gridf); /* Back in object space... */ mul_m4_v3(ob->imat, vec); /* Get location of grid point in pose space. */ BKE_armature_loc_pose_to_bone(pchan, vec, vec); /* adjust location */ if ((pchan->protectflag & OB_LOCK_LOCX) == 0) pchan->loc[0] = vec[0]; if ((pchan->protectflag & OB_LOCK_LOCY) == 0) pchan->loc[1] = vec[1]; if ((pchan->protectflag & OB_LOCK_LOCZ) == 0) pchan->loc[2] = vec[2]; /* auto-keyframing */ ED_autokeyframe_pchan(C, scene, ob, pchan, ks); } /* if the bone has a parent and is connected to the parent, * don't do anything - will break chain unless we do auto-ik. */ } } } ob->pose->flag |= (POSE_LOCKED | POSE_DO_UNLOCK); DAG_id_tag_update(&ob->id, OB_RECALC_DATA); } else { vec[0] = -ob->obmat[3][0] + gridf * floorf(0.5f + ob->obmat[3][0] / gridf); vec[1] = -ob->obmat[3][1] + gridf * floorf(0.5f + ob->obmat[3][1] / gridf); vec[2] = -ob->obmat[3][2] + gridf * floorf(0.5f + ob->obmat[3][2] / gridf); if (ob->parent) { float originmat[3][3]; BKE_object_where_is_calc_ex(scene, NULL, ob, originmat); invert_m3_m3(imat, originmat); mul_m3_v3(imat, vec); } if ((ob->protectflag & OB_LOCK_LOCX) == 0) ob->loc[0] += vec[0]; if ((ob->protectflag & OB_LOCK_LOCY) == 0) ob->loc[1] += vec[1]; if ((ob->protectflag & OB_LOCK_LOCZ) == 0) ob->loc[2] += vec[2]; /* auto-keyframing */ ED_autokeyframe_object(C, scene, ob, ks); DAG_id_tag_update(&ob->id, OB_RECALC_OB); } } CTX_DATA_END; } WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); return OPERATOR_FINISHED; }
/* set the current pose as the restpose */ static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); // must be active object, not edit-object bArmature *arm = BKE_armature_from_object(ob); bPose *pose; bPoseChannel *pchan; EditBone *curbone; /* don't check if editmode (should be done by caller) */ if (ob->type != OB_ARMATURE) return OPERATOR_CANCELLED; if (BKE_object_obdata_is_libdata(ob)) { BKE_report(op->reports, RPT_ERROR, "Cannot apply pose to lib-linked armature"); /* error_libdata(); */ return OPERATOR_CANCELLED; } /* helpful warnings... */ /* TODO: add warnings to be careful about actions, applying deforms first, etc. */ if (ob->adt && ob->adt->action) BKE_report(op->reports, RPT_WARNING, "Actions on this armature will be destroyed by this new rest pose as the " "transforms stored are relative to the old rest pose"); /* Get editbones of active armature to alter */ ED_armature_to_edit(arm); /* get pose of active object and move it out of posemode */ pose = ob->pose; for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) { curbone = ED_armature_bone_find_name(arm->edbo, pchan->name); /* simply copy the head/tail values from pchan over to curbone */ copy_v3_v3(curbone->head, pchan->pose_head); copy_v3_v3(curbone->tail, pchan->pose_tail); /* fix roll: * 1. find auto-calculated roll value for this bone now * 2. remove this from the 'visual' y-rotation */ { float premat[3][3], imat[3][3], pmat[3][3], tmat[3][3]; float delta[3], eul[3]; /* obtain new auto y-rotation */ sub_v3_v3v3(delta, curbone->tail, curbone->head); vec_roll_to_mat3(delta, 0.0f, premat); invert_m3_m3(imat, premat); /* get pchan 'visual' matrix */ copy_m3_m4(pmat, pchan->pose_mat); /* remove auto from visual and get euler rotation */ mul_m3_m3m3(tmat, imat, pmat); mat3_to_eul(eul, tmat); /* just use this euler-y as new roll value */ curbone->roll = eul[1]; } /* clear transform values for pchan */ zero_v3(pchan->loc); zero_v3(pchan->eul); unit_qt(pchan->quat); unit_axis_angle(pchan->rotAxis, &pchan->rotAngle); pchan->size[0] = pchan->size[1] = pchan->size[2] = 1.0f; /* set anim lock */ curbone->flag |= BONE_UNKEYED; } /* convert editbones back to bones, and then free the edit-data */ ED_armature_from_edit(arm); ED_armature_edit_free(arm); /* flush positions of posebones */ BKE_pose_where_is(scene, ob); /* fix parenting of objects which are bone-parented */ applyarmature_fix_boneparents(scene, ob); /* note, notifier might evolve */ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); return OPERATOR_FINISHED; }
/* put EditMode back in Object */ void ED_armature_from_edit(bArmature *arm) { EditBone *eBone, *neBone; Bone *newBone; Object *obt; /* armature bones */ BKE_armature_bonelist_free(&arm->bonebase); arm->act_bone = NULL; /* remove zero sized bones, this gives unstable restposes */ for (eBone = arm->edbo->first; eBone; eBone = neBone) { float len = len_v3v3(eBone->head, eBone->tail); neBone = eBone->next; if (len <= 0.000001f) { /* FLT_EPSILON is too large? */ EditBone *fBone; /* Find any bones that refer to this bone */ for (fBone = arm->edbo->first; fBone; fBone = fBone->next) { if (fBone->parent == eBone) fBone->parent = eBone->parent; } if (G.debug & G_DEBUG) printf("Warning: removed zero sized bone: %s\n", eBone->name); bone_free(arm, eBone); } } /* Copy the bones from the editData into the armature */ for (eBone = arm->edbo->first; eBone; eBone = eBone->next) { newBone = MEM_callocN(sizeof(Bone), "bone"); eBone->temp.bone = newBone; /* Associate the real Bones with the EditBones */ BLI_strncpy(newBone->name, eBone->name, sizeof(newBone->name)); copy_v3_v3(newBone->arm_head, eBone->head); copy_v3_v3(newBone->arm_tail, eBone->tail); newBone->arm_roll = eBone->roll; newBone->flag = eBone->flag; if (eBone == arm->act_edbone) { /* don't change active selection, this messes up separate which uses * editmode toggle and can separate active bone which is de-selected originally */ /* newBone->flag |= BONE_SELECTED; */ /* important, editbones can be active with only 1 point selected */ arm->act_bone = newBone; } newBone->roll = 0.0f; newBone->weight = eBone->weight; newBone->dist = eBone->dist; newBone->xwidth = eBone->xwidth; newBone->zwidth = eBone->zwidth; newBone->ease1 = eBone->ease1; newBone->ease2 = eBone->ease2; newBone->rad_head = eBone->rad_head; newBone->rad_tail = eBone->rad_tail; newBone->segments = eBone->segments; newBone->layer = eBone->layer; if (eBone->prop) newBone->prop = IDP_CopyProperty(eBone->prop); } /* Fix parenting in a separate pass to ensure ebone->bone connections * are valid at this point */ for (eBone = arm->edbo->first; eBone; eBone = eBone->next) { newBone = eBone->temp.bone; if (eBone->parent) { newBone->parent = eBone->parent->temp.bone; BLI_addtail(&newBone->parent->childbase, newBone); { float M_parentRest[3][3]; float iM_parentRest[3][3]; /* Get the parent's matrix (rotation only) */ ED_armature_ebone_to_mat3(eBone->parent, M_parentRest); /* Invert the parent matrix */ invert_m3_m3(iM_parentRest, M_parentRest); /* Get the new head and tail */ sub_v3_v3v3(newBone->head, eBone->head, eBone->parent->tail); sub_v3_v3v3(newBone->tail, eBone->tail, eBone->parent->tail); mul_m3_v3(iM_parentRest, newBone->head); mul_m3_v3(iM_parentRest, newBone->tail); } } /* ...otherwise add this bone to the armature's bonebase */ else { copy_v3_v3(newBone->head, eBone->head); copy_v3_v3(newBone->tail, eBone->tail); BLI_addtail(&arm->bonebase, newBone); } } /* Make a pass through the new armature to fix rolling */ /* also builds restposition again (like BKE_armature_where_is) */ fix_bonelist_roll(&arm->bonebase, arm->edbo); /* so all users of this armature should get rebuilt */ for (obt = G.main->object.first; obt; obt = obt->id.next) { if (obt->data == arm) BKE_pose_rebuild(obt, arm); } DAG_id_tag_update(&arm->id, 0); }
/* the ctrl-click method */ static int armature_click_extrude_exec(bContext *C, wmOperator *UNUSED(op)) { View3D *v3d; bArmature *arm; EditBone *ebone, *newbone, *flipbone; float mat[3][3], imat[3][3]; const float *curs; int a, to_root = 0; Object *obedit; Scene *scene; scene = CTX_data_scene(C); v3d = CTX_wm_view3d(C); obedit = CTX_data_edit_object(C); arm = obedit->data; /* find the active or selected bone */ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { if (EBONE_VISIBLE(arm, ebone)) { if (ebone->flag & BONE_TIPSEL || arm->act_edbone == ebone) break; } } if (ebone == NULL) { for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { if (EBONE_VISIBLE(arm, ebone)) { if (ebone->flag & BONE_ROOTSEL || arm->act_edbone == ebone) break; } } if (ebone == NULL) return OPERATOR_CANCELLED; to_root = 1; } ED_armature_deselect_all(obedit); /* we re-use code for mirror editing... */ flipbone = NULL; if (arm->flag & ARM_MIRROR_EDIT) flipbone = ED_armature_bone_get_mirrored(arm->edbo, ebone); for (a = 0; a < 2; a++) { if (a == 1) { if (flipbone == NULL) break; else { SWAP(EditBone *, flipbone, ebone); } } newbone = ED_armature_edit_bone_add(arm, ebone->name); arm->act_edbone = newbone; if (to_root) { copy_v3_v3(newbone->head, ebone->head); newbone->rad_head = ebone->rad_tail; newbone->parent = ebone->parent; } else { copy_v3_v3(newbone->head, ebone->tail); newbone->rad_head = ebone->rad_tail; newbone->parent = ebone; newbone->flag |= BONE_CONNECTED; } curs = ED_view3d_cursor3d_get(scene, v3d); copy_v3_v3(newbone->tail, curs); sub_v3_v3v3(newbone->tail, newbone->tail, obedit->obmat[3]); if (a == 1) newbone->tail[0] = -newbone->tail[0]; copy_m3_m4(mat, obedit->obmat); invert_m3_m3(imat, mat); mul_m3_v3(imat, newbone->tail); newbone->length = len_v3v3(newbone->head, newbone->tail); newbone->rad_tail = newbone->length * 0.05f; newbone->dist = newbone->length * 0.25f; } ED_armature_sync_selection(arm->edbo); WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); return OPERATOR_FINISHED; }
/* 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 int apply_objects_internal(bContext *C, ReportList *reports, int apply_loc, int apply_rot, int apply_scale) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); float rsmat[3][3], tmat[3][3], obmat[3][3], iobmat[3][3], mat[4][4], scale; int a, change = 1; /* first check if we can execute */ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { if (ob->type == OB_MESH) { if (ID_REAL_USERS(ob->data) > 1) { BKE_report(reports, RPT_ERROR, "Can't apply to a multi user mesh, doing nothing"); change = 0; } } else if (ob->type == OB_ARMATURE) { if (ID_REAL_USERS(ob->data) > 1) { BKE_report(reports, RPT_ERROR, "Can't apply to a multi user armature, doing nothing"); change = 0; } } else if (ob->type == OB_LATTICE) { if (ID_REAL_USERS(ob->data) > 1) { BKE_report(reports, RPT_ERROR, "Can't apply to a multi user lattice, doing nothing"); change = 0; } } else if (ELEM(ob->type, OB_CURVE, OB_SURF)) { Curve *cu; if (ID_REAL_USERS(ob->data) > 1) { BKE_report(reports, RPT_ERROR, "Can't apply to a multi user curve, doing nothing"); change = 0; } cu = ob->data; if (!(cu->flag & CU_3D) && (apply_rot || apply_loc)) { BKE_report(reports, RPT_ERROR, "Neither rotation nor location could be applied to a 2d curve, doing nothing"); change = 0; } if (cu->key) { BKE_report(reports, RPT_ERROR, "Can't apply to a curve with vertex keys, doing nothing"); change = 0; } } } CTX_DATA_END; if (!change) return OPERATOR_CANCELLED; change = 0; /* now execute */ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { /* calculate rotation/scale matrix */ if (apply_scale && apply_rot) BKE_object_to_mat3(ob, rsmat); else if (apply_scale) BKE_object_scale_to_mat3(ob, rsmat); else if (apply_rot) { float tmat[3][3], timat[3][3]; /* simple rotation matrix */ BKE_object_rot_to_mat3(ob, rsmat); /* correct for scale, note mul_m3_m3m3 has swapped args! */ BKE_object_scale_to_mat3(ob, tmat); invert_m3_m3(timat, tmat); mul_m3_m3m3(rsmat, timat, rsmat); mul_m3_m3m3(rsmat, rsmat, tmat); } else unit_m3(rsmat); copy_m4_m3(mat, rsmat); /* calculate translation */ if (apply_loc) { copy_v3_v3(mat[3], ob->loc); if (!(apply_scale && apply_rot)) { /* correct for scale and rotation that is still applied */ BKE_object_to_mat3(ob, obmat); invert_m3_m3(iobmat, obmat); mul_m3_m3m3(tmat, rsmat, iobmat); mul_m3_v3(tmat, mat[3]); } } /* apply to object data */ if (ob->type == OB_MESH) { Mesh *me = ob->data; MVert *mvert; multiresModifier_scale_disp(scene, ob); /* adjust data */ mvert = me->mvert; for (a = 0; a < me->totvert; a++, mvert++) mul_m4_v3(mat, mvert->co); if (me->key) { KeyBlock *kb; for (kb = me->key->block.first; kb; kb = kb->next) { float *fp = kb->data; for (a = 0; a < kb->totelem; a++, fp += 3) mul_m4_v3(mat, fp); } } /* update normals */ BKE_mesh_calc_normals_mapping(me->mvert, me->totvert, me->mloop, me->mpoly, me->totloop, me->totpoly, NULL, NULL, 0, NULL, NULL); } else if (ob->type == OB_ARMATURE) { ED_armature_apply_transform(ob, mat); } else if (ob->type == OB_LATTICE) { Lattice *lt = ob->data; BPoint *bp = lt->def; int a = lt->pntsu * lt->pntsv * lt->pntsw; while (a--) { mul_m4_v3(mat, bp->vec); bp++; } } else if (ELEM(ob->type, OB_CURVE, OB_SURF)) { Curve *cu = ob->data; Nurb *nu; BPoint *bp; BezTriple *bezt; scale = mat3_to_scale(rsmat); for (nu = cu->nurb.first; nu; nu = nu->next) { if (nu->type == CU_BEZIER) { a = nu->pntsu; for (bezt = nu->bezt; a--; bezt++) { mul_m4_v3(mat, bezt->vec[0]); mul_m4_v3(mat, bezt->vec[1]); mul_m4_v3(mat, bezt->vec[2]); bezt->radius *= scale; } BKE_nurb_handles_calc(nu); } else { a = nu->pntsu * nu->pntsv; for (bp = nu->bp; a--; bp++) mul_m4_v3(mat, bp->vec); } } } else continue; if (apply_loc) zero_v3(ob->loc); if (apply_scale) ob->size[0] = ob->size[1] = ob->size[2] = 1.0f; if (apply_rot) { zero_v3(ob->rot); unit_qt(ob->quat); unit_axis_angle(ob->rotAxis, &ob->rotAngle); } BKE_object_where_is_calc(scene, ob); if (ob->type == OB_ARMATURE) { BKE_pose_where_is(scene, ob); /* needed for bone parents */ } ignore_parent_tx(bmain, scene, ob); DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA); change = 1; } CTX_DATA_END; if (!change) return OPERATOR_CANCELLED; WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); return OPERATOR_FINISHED; }
static int apply_objects_internal(bContext *C, ReportList *reports, bool apply_loc, bool apply_rot, bool apply_scale) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); float rsmat[3][3], obmat[3][3], iobmat[3][3], mat[4][4], scale; bool changed = true; /* first check if we can execute */ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { if (ELEM(ob->type, OB_MESH, OB_ARMATURE, OB_LATTICE, OB_MBALL, OB_CURVE, OB_SURF, OB_FONT)) { ID *obdata = ob->data; if (ID_REAL_USERS(obdata) > 1) { BKE_reportf(reports, RPT_ERROR, "Cannot apply to a multi user: Object \"%s\", %s \"%s\", aborting", ob->id.name + 2, BKE_idcode_to_name(GS(obdata->name)), obdata->name + 2); changed = false; } if (obdata->lib) { BKE_reportf(reports, RPT_ERROR, "Cannot apply to library data: Object \"%s\", %s \"%s\", aborting", ob->id.name + 2, BKE_idcode_to_name(GS(obdata->name)), obdata->name + 2); changed = false; } } if (ELEM(ob->type, OB_CURVE, OB_SURF)) { ID *obdata = ob->data; Curve *cu; cu = ob->data; if (((ob->type == OB_CURVE) && !(cu->flag & CU_3D)) && (apply_rot || apply_loc)) { BKE_reportf(reports, RPT_ERROR, "Rotation/Location can't apply to a 2D curve: Object \"%s\", %s \"%s\", aborting", ob->id.name + 2, BKE_idcode_to_name(GS(obdata->name)), obdata->name + 2); changed = false; } if (cu->key) { BKE_reportf(reports, RPT_ERROR, "Can't apply to a curve with shape-keys: Object \"%s\", %s \"%s\", aborting", ob->id.name + 2, BKE_idcode_to_name(GS(obdata->name)), obdata->name + 2); changed = false; } } if (ob->type == OB_FONT) { if (apply_rot || apply_loc) { BKE_reportf(reports, RPT_ERROR, "Font's can only have scale applied: \"%s\"", ob->id.name + 2); changed = false; } } } CTX_DATA_END; if (!changed) return OPERATOR_CANCELLED; changed = false; /* now execute */ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { /* calculate rotation/scale matrix */ if (apply_scale && apply_rot) BKE_object_to_mat3(ob, rsmat); else if (apply_scale) BKE_object_scale_to_mat3(ob, rsmat); else if (apply_rot) { float tmat[3][3], timat[3][3]; /* simple rotation matrix */ BKE_object_rot_to_mat3(ob, rsmat, true); /* correct for scale, note mul_m3_m3m3 has swapped args! */ BKE_object_scale_to_mat3(ob, tmat); invert_m3_m3(timat, tmat); mul_m3_m3m3(rsmat, timat, rsmat); mul_m3_m3m3(rsmat, rsmat, tmat); } else unit_m3(rsmat); copy_m4_m3(mat, rsmat); /* calculate translation */ if (apply_loc) { copy_v3_v3(mat[3], ob->loc); if (!(apply_scale && apply_rot)) { float tmat[3][3]; /* correct for scale and rotation that is still applied */ BKE_object_to_mat3(ob, obmat); invert_m3_m3(iobmat, obmat); mul_m3_m3m3(tmat, rsmat, iobmat); mul_m3_v3(tmat, mat[3]); } } /* apply to object data */ if (ob->type == OB_MESH) { Mesh *me = ob->data; if (apply_scale) multiresModifier_scale_disp(scene, ob); /* adjust data */ BKE_mesh_transform(me, mat, true); /* update normals */ BKE_mesh_calc_normals(me); } else if (ob->type == OB_ARMATURE) { ED_armature_apply_transform(ob, mat); } else if (ob->type == OB_LATTICE) { Lattice *lt = ob->data; BKE_lattice_transform(lt, mat, true); } else if (ob->type == OB_MBALL) { MetaBall *mb = ob->data; BKE_mball_transform(mb, mat); } else if (ELEM(ob->type, OB_CURVE, OB_SURF)) { Curve *cu = ob->data; scale = mat3_to_scale(rsmat); BKE_curve_transform_ex(cu, mat, true, scale); } else if (ob->type == OB_FONT) { Curve *cu = ob->data; int i; scale = mat3_to_scale(rsmat); for (i = 0; i < cu->totbox; i++) { TextBox *tb = &cu->tb[i]; tb->x *= scale; tb->y *= scale; tb->w *= scale; tb->h *= scale; } cu->fsize *= scale; } else if (ob->type == OB_CAMERA) { MovieClip *clip = BKE_object_movieclip_get(scene, ob, false); /* applying scale on camera actually scales clip's reconstruction. * of there's clip assigned to camera nothing to do actually. */ if (!clip) continue; if (apply_scale) BKE_tracking_reconstruction_scale(&clip->tracking, ob->size); } else if (ob->type == OB_EMPTY) { /* It's possible for empties too, even though they don't * really have obdata, since we can simply apply the maximum * scaling to the empty's drawsize. * * Core Assumptions: * 1) Most scaled empties have uniform scaling * (i.e. for visibility reasons), AND/OR * 2) Preserving non-uniform scaling is not that important, * and is something that many users would be willing to * sacrifice for having an easy way to do this. */ if ((apply_loc == false) && (apply_rot == false) && (apply_scale == true)) { float max_scale = max_fff(fabsf(ob->size[0]), fabsf(ob->size[1]), fabsf(ob->size[2])); ob->empty_drawsize *= max_scale; } } else { continue; } if (apply_loc) zero_v3(ob->loc); if (apply_scale) ob->size[0] = ob->size[1] = ob->size[2] = 1.0f; if (apply_rot) { zero_v3(ob->rot); unit_qt(ob->quat); unit_axis_angle(ob->rotAxis, &ob->rotAngle); } BKE_object_where_is_calc(scene, ob); if (ob->type == OB_ARMATURE) { BKE_pose_where_is(scene, ob); /* needed for bone parents */ } ignore_parent_tx(bmain, scene, ob); DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA); changed = true; } CTX_DATA_END; if (!changed) { BKE_report(reports, RPT_WARNING, "Objects have no data to transform"); return OPERATOR_CANCELLED; } WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); return OPERATOR_FINISHED; }
static void bake_shade(void *handle, Object *ob, ShadeInput *shi, int UNUSED(quad), int x, int y, float UNUSED(u), float UNUSED(v), float *tvn, float *ttang) { BakeShade *bs = handle; ShadeSample *ssamp = &bs->ssamp; ShadeResult shr; VlakRen *vlr = shi->vlr; shade_input_init_material(shi); if (bs->type == RE_BAKE_AO) { ambient_occlusion(shi); if (R.r.bake_flag & R_BAKE_NORMALIZE) { copy_v3_v3(shr.combined, shi->ao); } else { zero_v3(shr.combined); environment_lighting_apply(shi, &shr); } } else { if (bs->type == RE_BAKE_SHADOW) /* Why do shadows set the color anyhow?, ignore material color for baking */ shi->r = shi->g = shi->b = 1.0f; shade_input_set_shade_texco(shi); /* only do AO for a full bake (and obviously AO bakes) * AO for light bakes is a leftover and might not be needed */ if (ELEM3(bs->type, RE_BAKE_ALL, RE_BAKE_AO, RE_BAKE_LIGHT)) shade_samples_do_AO(ssamp); if (shi->mat->nodetree && shi->mat->use_nodes) { ntreeShaderExecTree(shi->mat->nodetree, shi, &shr); shi->mat = vlr->mat; /* shi->mat is being set in nodetree */ } else shade_material_loop(shi, &shr); if (bs->type == RE_BAKE_NORMALS) { float nor[3]; copy_v3_v3(nor, shi->vn); if (R.r.bake_normal_space == R_BAKE_SPACE_CAMERA) { /* pass */ } else if (R.r.bake_normal_space == R_BAKE_SPACE_TANGENT) { float mat[3][3], imat[3][3]; /* bitangent */ if (tvn && ttang) { copy_v3_v3(mat[0], ttang); cross_v3_v3v3(mat[1], tvn, ttang); mul_v3_fl(mat[1], ttang[3]); copy_v3_v3(mat[2], tvn); } else { copy_v3_v3(mat[0], shi->nmaptang); cross_v3_v3v3(mat[1], shi->nmapnorm, shi->nmaptang); mul_v3_fl(mat[1], shi->nmaptang[3]); copy_v3_v3(mat[2], shi->nmapnorm); } invert_m3_m3(imat, mat); mul_m3_v3(imat, nor); } else if (R.r.bake_normal_space == R_BAKE_SPACE_OBJECT) mul_mat3_m4_v3(ob->imat_ren, nor); /* ob->imat_ren includes viewinv! */ else if (R.r.bake_normal_space == R_BAKE_SPACE_WORLD) mul_mat3_m4_v3(R.viewinv, nor); normalize_v3(nor); /* in case object has scaling */ /* The invert of the red channel is to make * the normal map compliant with the outside world. * It needs to be done because in Blender * the normal used in the renderer points inward. It is generated * this way in calc_vertexnormals(). Should this ever change * this negate must be removed. */ shr.combined[0] = (-nor[0]) / 2.0f + 0.5f; shr.combined[1] = nor[1] / 2.0f + 0.5f; shr.combined[2] = nor[2] / 2.0f + 0.5f; } else if (bs->type == RE_BAKE_TEXTURE) { copy_v3_v3(shr.combined, &shi->r); shr.alpha = shi->alpha; } else if (bs->type == RE_BAKE_SHADOW) { copy_v3_v3(shr.combined, shr.shad); shr.alpha = shi->alpha; } else if (bs->type == RE_BAKE_SPEC_COLOR) { copy_v3_v3(shr.combined, &shi->specr); shr.alpha = 1.0f; } else if (bs->type == RE_BAKE_SPEC_INTENSITY) { copy_v3_fl(shr.combined, shi->spec); shr.alpha = 1.0f; } else if (bs->type == RE_BAKE_MIRROR_COLOR) { copy_v3_v3(shr.combined, &shi->mirr); shr.alpha = 1.0f; } else if (bs->type == RE_BAKE_MIRROR_INTENSITY) { copy_v3_fl(shr.combined, shi->ray_mirror); shr.alpha = 1.0f; } else if (bs->type == RE_BAKE_ALPHA) { copy_v3_fl(shr.combined, shi->alpha); shr.alpha = 1.0f; } else if (bs->type == RE_BAKE_EMIT) { copy_v3_fl(shr.combined, shi->emit); shr.alpha = 1.0f; } else if (bs->type == RE_BAKE_VERTEX_COLORS) { copy_v3_v3(shr.combined, shi->vcol); shr.alpha = shi->vcol[3]; } } if (bs->rect_float && !bs->vcol) { float *col = bs->rect_float + 4 * (bs->rectx * y + x); copy_v3_v3(col, shr.combined); if (bs->type == RE_BAKE_ALL || bs->type == RE_BAKE_TEXTURE || bs->type == RE_BAKE_VERTEX_COLORS) { col[3] = shr.alpha; } else { col[3] = 1.0; } } else { /* Target is char (LDR). */ unsigned char col[4]; if (ELEM(bs->type, RE_BAKE_ALL, RE_BAKE_TEXTURE)) { float rgb[3]; copy_v3_v3(rgb, shr.combined); if (R.scene_color_manage) { /* Vertex colors have no way to specify color space, so they * default to sRGB. */ if (!bs->vcol) IMB_colormanagement_scene_linear_to_colorspace_v3(rgb, bs->rect_colorspace); else linearrgb_to_srgb_v3_v3(rgb, rgb); } rgb_float_to_uchar(col, rgb); } else { rgb_float_to_uchar(col, shr.combined); } if (ELEM3(bs->type, RE_BAKE_ALL, RE_BAKE_TEXTURE, RE_BAKE_VERTEX_COLORS)) { col[3] = FTOCHAR(shr.alpha); } else { col[3] = 255; } if (bs->vcol) { /* Vertex color baking. Vcol has no useful alpha channel (it exists * but is used only for vertex painting). */ bs->vcol->r = col[0]; bs->vcol->g = col[1]; bs->vcol->b = col[2]; } else { unsigned char *imcol = (unsigned char *)(bs->rect + bs->rectx * y + x); copy_v4_v4_char((char *)imcol, (char *)col); } } if (bs->rect_mask) { bs->rect_mask[bs->rectx * y + x] = FILTER_MASK_USED; } if (bs->do_update) { *bs->do_update = true; } }
/** * This function converts an object space normal map to a tangent space normal map for a given low poly mesh */ void RE_bake_normal_world_to_tangent( const BakePixel pixel_array[], const size_t num_pixels, const int depth, float result[], Mesh *me, const BakeNormalSwizzle normal_swizzle[3], float mat[4][4]) { size_t i; TriTessFace *triangles; DerivedMesh *dm = CDDM_from_mesh(me); triangles = MEM_mallocN(sizeof(TriTessFace) * (me->totface * 2), "MVerts Mesh"); mesh_calc_tri_tessface(triangles, me, true, dm); BLI_assert(num_pixels >= 3); for (i = 0; i < num_pixels; i++) { TriTessFace *triangle; float tangents[3][3]; float normals[3][3]; float signs[3]; int j; float tangent[3]; float normal[3]; float binormal[3]; float sign; float u, v, w; float tsm[3][3]; /* tangent space matrix */ float itsm[3][3]; size_t offset; float nor[3]; /* texture normal */ bool is_smooth; int primitive_id = pixel_array[i].primitive_id; offset = i * depth; if (primitive_id == -1) { copy_v3_fl3(&result[offset], 0.5f, 0.5f, 1.0f); continue; } triangle = &triangles[primitive_id]; is_smooth = triangle->is_smooth; for (j = 0; j < 3; j++) { const TSpace *ts; if (is_smooth) normal_short_to_float_v3(normals[j], triangle->mverts[j]->no); else normal[j] = triangle->normal[j]; ts = triangle->tspace[j]; copy_v3_v3(tangents[j], ts->tangent); signs[j] = ts->sign; } u = pixel_array[i].uv[0]; v = pixel_array[i].uv[1]; w = 1.0f - u - v; /* normal */ if (is_smooth) interp_barycentric_tri_v3(normals, u, v, normal); /* tangent */ interp_barycentric_tri_v3(tangents, u, v, tangent); /* sign */ /* The sign is the same at all face vertices for any non degenerate face. * Just in case we clamp the interpolated value though. */ sign = (signs[0] * u + signs[1] * v + signs[2] * w) < 0 ? (-1.0f) : 1.0f; /* binormal */ /* B = sign * cross(N, T) */ cross_v3_v3v3(binormal, normal, tangent); mul_v3_fl(binormal, sign); /* populate tangent space matrix */ copy_v3_v3(tsm[0], tangent); copy_v3_v3(tsm[1], binormal); copy_v3_v3(tsm[2], normal); /* texture values */ normal_uncompress(nor, &result[offset]); /* converts from world space to local space */ mul_transposed_mat3_m4_v3(mat, nor); invert_m3_m3(itsm, tsm); mul_m3_v3(itsm, nor); normalize_v3(nor); /* save back the values */ normal_compress(&result[offset], nor, normal_swizzle); } /* garbage collection */ MEM_freeN(triangles); if (dm) dm->release(dm); }
static int apply_objects_internal(bContext *C, ReportList *reports, int apply_loc, int apply_rot, int apply_scale) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); float rsmat[3][3], obmat[3][3], iobmat[3][3], mat[4][4], scale; bool changed = true; /* first check if we can execute */ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { if (ELEM6(ob->type, OB_MESH, OB_ARMATURE, OB_LATTICE, OB_MBALL, OB_CURVE, OB_SURF)) { ID *obdata = ob->data; if (ID_REAL_USERS(obdata) > 1) { BKE_reportf(reports, RPT_ERROR, "Cannot apply to a multi user: Object \"%s\", %s \"%s\", aborting", ob->id.name + 2, BKE_idcode_to_name(GS(obdata->name)), obdata->name + 2); changed = false; } if (obdata->lib) { BKE_reportf(reports, RPT_ERROR, "Cannot apply to library data: Object \"%s\", %s \"%s\", aborting", ob->id.name + 2, BKE_idcode_to_name(GS(obdata->name)), obdata->name + 2); changed = false; } } if (ELEM(ob->type, OB_CURVE, OB_SURF)) { ID *obdata = ob->data; Curve *cu; cu = ob->data; if (((ob->type == OB_CURVE) && !(cu->flag & CU_3D)) && (apply_rot || apply_loc)) { BKE_reportf(reports, RPT_ERROR, "Rotation/Location can't apply to a 2D curve: Object \"%s\", %s \"%s\", aborting", ob->id.name + 2, BKE_idcode_to_name(GS(obdata->name)), obdata->name + 2); changed = false; } if (cu->key) { BKE_reportf(reports, RPT_ERROR, "Can't apply to a curve with shape-keys: Object \"%s\", %s \"%s\", aborting", ob->id.name + 2, BKE_idcode_to_name(GS(obdata->name)), obdata->name + 2); changed = false; } } } CTX_DATA_END; if (!changed) return OPERATOR_CANCELLED; changed = false; /* now execute */ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { /* calculate rotation/scale matrix */ if (apply_scale && apply_rot) BKE_object_to_mat3(ob, rsmat); else if (apply_scale) BKE_object_scale_to_mat3(ob, rsmat); else if (apply_rot) { float tmat[3][3], timat[3][3]; /* simple rotation matrix */ BKE_object_rot_to_mat3(ob, rsmat, TRUE); /* correct for scale, note mul_m3_m3m3 has swapped args! */ BKE_object_scale_to_mat3(ob, tmat); invert_m3_m3(timat, tmat); mul_m3_m3m3(rsmat, timat, rsmat); mul_m3_m3m3(rsmat, rsmat, tmat); } else unit_m3(rsmat); copy_m4_m3(mat, rsmat); /* calculate translation */ if (apply_loc) { copy_v3_v3(mat[3], ob->loc); if (!(apply_scale && apply_rot)) { float tmat[3][3]; /* correct for scale and rotation that is still applied */ BKE_object_to_mat3(ob, obmat); invert_m3_m3(iobmat, obmat); mul_m3_m3m3(tmat, rsmat, iobmat); mul_m3_v3(tmat, mat[3]); } } /* apply to object data */ if (ob->type == OB_MESH) { Mesh *me = ob->data; MVert *mvert; int a; if (apply_scale) multiresModifier_scale_disp(scene, ob); /* adjust data */ mvert = me->mvert; for (a = 0; a < me->totvert; a++, mvert++) mul_m4_v3(mat, mvert->co); if (me->key) { KeyBlock *kb; for (kb = me->key->block.first; kb; kb = kb->next) { float *fp = kb->data; for (a = 0; a < kb->totelem; a++, fp += 3) mul_m4_v3(mat, fp); } } /* update normals */ BKE_mesh_calc_normals(me); } else if (ob->type == OB_ARMATURE) { ED_armature_apply_transform(ob, mat); } else if (ob->type == OB_LATTICE) { Lattice *lt = ob->data; BPoint *bp = lt->def; int a = lt->pntsu * lt->pntsv * lt->pntsw; while (a--) { mul_m4_v3(mat, bp->vec); bp++; } } else if (ob->type == OB_MBALL) { MetaBall *mb = ob->data; ED_mball_transform(mb, mat); } else if (ELEM(ob->type, OB_CURVE, OB_SURF)) { Curve *cu = ob->data; Nurb *nu; BPoint *bp; BezTriple *bezt; int a; scale = mat3_to_scale(rsmat); for (nu = cu->nurb.first; nu; nu = nu->next) { if (nu->type == CU_BEZIER) { a = nu->pntsu; for (bezt = nu->bezt; a--; bezt++) { mul_m4_v3(mat, bezt->vec[0]); mul_m4_v3(mat, bezt->vec[1]); mul_m4_v3(mat, bezt->vec[2]); bezt->radius *= scale; } BKE_nurb_handles_calc(nu); } else { a = nu->pntsu * nu->pntsv; for (bp = nu->bp; a--; bp++) mul_m4_v3(mat, bp->vec); } } } else if (ob->type == OB_CAMERA) { MovieClip *clip = BKE_object_movieclip_get(scene, ob, false); /* applying scale on camera actually scales clip's reconstruction. * of there's clip assigned to camera nothing to do actually. */ if (!clip) continue; if (apply_scale) BKE_tracking_reconstruction_scale(&clip->tracking, ob->size); } else if (ob->type == OB_EMPTY) { /* It's possible for empties too, even though they don't * really have obdata, since we can simply apply the maximum * scaling to the empty's drawsize. * * Core Assumptions: * 1) Most scaled empties have uniform scaling * (i.e. for visibility reasons), AND/OR * 2) Preserving non-uniform scaling is not that important, * and is something that many users would be willing to * sacrifice for having an easy way to do this. */ float max_scale = MAX3(ob->size[0], ob->size[1], ob->size[2]); ob->empty_drawsize *= max_scale; } else { continue; } if (apply_loc) zero_v3(ob->loc); if (apply_scale) ob->size[0] = ob->size[1] = ob->size[2] = 1.0f; if (apply_rot) { zero_v3(ob->rot); unit_qt(ob->quat); unit_axis_angle(ob->rotAxis, &ob->rotAngle); } BKE_object_where_is_calc(scene, ob); if (ob->type == OB_ARMATURE) { BKE_pose_where_is(scene, ob); /* needed for bone parents */ } ignore_parent_tx(bmain, scene, ob); DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA); changed = true; } CTX_DATA_END; if (!changed) { BKE_report(reports, RPT_WARNING, "Objects have no data to transform"); return OPERATOR_CANCELLED; } WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); return OPERATOR_FINISHED; }