static void obmat_to_viewmat(RegionView3D *rv3d, Object *ob) { float bmat[4][4]; float tmat[3][3]; rv3d->view = RV3D_VIEW_USER; /* don't show the grid */ copy_m4_m4(bmat, ob->obmat); normalize_m4(bmat); invert_m4_m4(rv3d->viewmat, bmat); /* view quat calculation, needed for add object */ copy_m3_m4(tmat, rv3d->viewmat); mat3_to_quat(rv3d->viewquat, tmat); }
/* 'rotmat' can be obedit->obmat when uv project is used. * 'winx' and 'winy' can be from scene->r.xsch/ysch */ UvCameraInfo *project_camera_info(Object *ob, float (*rotmat)[4], float winx, float winy) { UvCameraInfo uci; Camera *camera= ob->data; uci.do_pano = (camera->flag & CAM_PANORAMA); uci.do_persp = (camera->type==CAM_PERSP); uci.camangle= lens_to_angle(camera->lens) / 2.0f; uci.camsize= uci.do_persp ? tanf(uci.camangle) : camera->ortho_scale; /* account for scaled cameras */ copy_m4_m4(uci.caminv, ob->obmat); normalize_m4(uci.caminv); if (invert_m4(uci.caminv)) { UvCameraInfo *uci_pt; /* normal projection */ if(rotmat) { copy_m4_m4(uci.rotmat, rotmat); uci.do_rotmat= 1; } else { uci.do_rotmat= 0; } /* also make aspect ratio adjustment factors */ if (winx > winy) { uci.xasp= 1.0f; uci.yasp= winx / winy; } else { uci.xasp= winy / winx; uci.yasp= 1.0f; } /* include 0.5f here to move the UVs into the center */ uci.shiftx = 0.5f - (camera->shiftx * uci.xasp); uci.shifty = 0.5f - (camera->shifty * uci.yasp); uci_pt= MEM_mallocN(sizeof(UvCameraInfo), "UvCameraInfo"); *uci_pt= uci; return uci_pt; } return NULL; }
void BKE_camera_multiview_model_matrix(RenderData *rd, Object *camera, const char *viewname, float r_modelmat[4][4]) { const bool is_multiview = (rd && rd->scemode & R_MULTIVIEW) != 0; if (!is_multiview) { camera_model_matrix(camera, r_modelmat); } else if (rd->views_format == SCE_VIEWS_FORMAT_MULTIVIEW) { camera_model_matrix(camera, r_modelmat); } else { /* SCE_VIEWS_SETUP_BASIC */ const bool is_left = camera_is_left(viewname); camera_stereo3d_model_matrix(camera, is_left, r_modelmat); } normalize_m4(r_modelmat); }
/* get the camera's dof value, takes the dof object into account */ float object_camera_dof_distance(Object *ob) { Camera *cam = (Camera *)ob->data; if (ob->type != OB_CAMERA) return 0.0f; if (cam->dof_ob) { /* too simple, better to return the distance on the view axis only * return len_v3v3(ob->obmat[3], cam->dof_ob->obmat[3]); */ float mat[4][4], imat[4][4], obmat[4][4]; copy_m4_m4(obmat, ob->obmat); normalize_m4(obmat); invert_m4_m4(imat, obmat); mult_m4_m4m4(mat, imat, cam->dof_ob->obmat); return fabsf(mat[3][2]); } return cam->YF_dofdist; }
static void obmat_to_viewmat(View3D *v3d, RegionView3D *rv3d, Object *ob, short smooth) { float bmat[4][4]; float tmat[3][3]; rv3d->view = RV3D_VIEW_USER; /* don't show the grid */ copy_m4_m4(bmat, ob->obmat); normalize_m4(bmat); invert_m4_m4(rv3d->viewmat, bmat); /* view quat calculation, needed for add object */ copy_m3_m4(tmat, rv3d->viewmat); if (smooth) { float new_quat[4]; if (rv3d->persp == RV3D_CAMOB && v3d->camera) { /* were from a camera view */ float orig_ofs[3]; float orig_dist = rv3d->dist; float orig_lens = v3d->lens; copy_v3_v3(orig_ofs, rv3d->ofs); /* Switch from camera view */ mat3_to_quat(new_quat, tmat); rv3d->persp = RV3D_PERSP; rv3d->dist = 0.0; ED_view3d_from_object(v3d->camera, rv3d->ofs, NULL, NULL, &v3d->lens); view3d_smooth_view(NULL, NULL, NULL, NULL, NULL, orig_ofs, new_quat, &orig_dist, &orig_lens); /* XXX */ rv3d->persp = RV3D_CAMOB; /* just to be polite, not needed */ } else { mat3_to_quat(new_quat, tmat); view3d_smooth_view(NULL, NULL, NULL, NULL, NULL, NULL, new_quat, NULL, NULL); /* XXX */ } } else { mat3_to_quat(rv3d->viewquat, tmat); } }
/* 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); }