Ejemplo n.º 1
0
static PyObject *Quaternion_slerp(QuaternionObject *self, PyObject *args)
{
	PyObject *value;
	float tquat[QUAT_SIZE], quat[QUAT_SIZE], fac;

	if (!PyArg_ParseTuple(args, "Of:slerp", &value, &fac)) {
		PyErr_SetString(PyExc_TypeError,
		                "quat.slerp(): "
		                "expected Quaternion types and float");
		return NULL;
	}

	if (BaseMath_ReadCallback(self) == -1)
		return NULL;

	if (mathutils_array_parse(tquat, QUAT_SIZE, QUAT_SIZE, value,
	                          "Quaternion.slerp(other), invalid 'other' arg") == -1)
	{
		return NULL;
	}

	if (fac > 1.0f || fac < 0.0f) {
		PyErr_SetString(PyExc_ValueError,
		                "quat.slerp(): "
		                "interpolation factor must be between 0.0 and 1.0");
		return NULL;
	}

	interp_qt_qtqt(quat, self->quat, tquat, fac);

	return Quaternion_CreatePyObject(quat, Py_NEW, Py_TYPE(self));
}
/* Only allowed for Poses with identical channels */
static void game_blend_poses(bPose *dst, bPose *src, float srcweight, short mode)
{
	bPoseChannel *dchan;
	const bPoseChannel *schan;
	bConstraint *dcon, *scon;
	float dstweight;
	int i;

	if (mode == BL_Action::ACT_BLEND_BLEND)
	{
		dstweight = 1.0f - srcweight;
	} else if (mode == BL_Action::ACT_BLEND_ADD)
	{
		dstweight = 1.0f;
	} else {
		dstweight = 1.0f;
	}
	
	schan= (bPoseChannel *)src->chanbase.first;
	for (dchan = (bPoseChannel *)dst->chanbase.first; dchan; dchan=(bPoseChannel *)dchan->next, schan= (bPoseChannel *)schan->next) {
		// always blend on all channels since we don't know which one has been set
		/* quat interpolation done separate */
		if (schan->rotmode == ROT_MODE_QUAT) {
			float dquat[4], squat[4];
			
			copy_qt_qt(dquat, dchan->quat);
			copy_qt_qt(squat, schan->quat);
			if (mode==BL_Action::ACT_BLEND_BLEND)
				interp_qt_qtqt(dchan->quat, dquat, squat, srcweight);
			else {
				mul_fac_qt_fl(squat, srcweight);
				mul_qt_qtqt(dchan->quat, dquat, squat);
			}
			
			normalize_qt(dchan->quat);
		}

		for (i=0; i<3; i++) {
			/* blending for loc and scale are pretty self-explanatory... */
			dchan->loc[i] = (dchan->loc[i]*dstweight) + (schan->loc[i]*srcweight);
			dchan->size[i] = 1.0f + ((dchan->size[i]-1.0f)*dstweight) + ((schan->size[i]-1.0f)*srcweight);
			
			/* euler-rotation interpolation done here instead... */
			// FIXME: are these results decent?
			if (schan->rotmode)
				dchan->eul[i] = (dchan->eul[i]*dstweight) + (schan->eul[i]*srcweight);
		}
		for (dcon= (bConstraint *)dchan->constraints.first, scon= (bConstraint *)schan->constraints.first;
		     dcon && scon;
		     dcon = dcon->next, scon = scon->next)
		{
			/* no 'add' option for constraint blending */
			dcon->enforce= dcon->enforce*(1.0f-srcweight) + scon->enforce*srcweight;
		}
	}
	
	/* this pose is now in src time */
	dst->ctime= src->ctime;
}
Ejemplo n.º 3
0
static void rotateBevelPiece(Curve *cu, BevPoint *bevp, BevPoint *nbevp, DispList *dlb, float bev_blend, float widfac, float fac, float **r_data)
{
	float *fp, *data = *r_data;
	int b;

	fp = dlb->verts;
	for (b = 0; b < dlb->nr; b++, fp += 3, data += 3) {
		if (cu->flag & CU_3D) {
			float vec[3], quat[4];

			vec[0] = fp[1] + widfac;
			vec[1] = fp[2];
			vec[2] = 0.0;

			if (nbevp == NULL) {
				copy_v3_v3(data, bevp->vec);
				copy_qt_qt(quat, bevp->quat);
			}
			else {
				interp_v3_v3v3(data, bevp->vec, nbevp->vec, bev_blend);
				interp_qt_qtqt(quat, bevp->quat, nbevp->quat, bev_blend);
			}

			mul_qt_v3(quat, vec);

			data[0] += fac * vec[0];
			data[1] += fac * vec[1];
			data[2] += fac * vec[2];
		}
		else {
			float sina, cosa;

			if (nbevp == NULL) {
				copy_v3_v3(data, bevp->vec);
				sina = bevp->sina;
				cosa = bevp->cosa;
			}
			else {
				interp_v3_v3v3(data, bevp->vec, nbevp->vec, bev_blend);

				/* perhaps we need to interpolate angles instead. but the thing is
				 * cosa and sina are not actually sine and cosine
				 */
				sina = nbevp->sina * bev_blend + bevp->sina * (1.0f - bev_blend);
				cosa = nbevp->cosa * bev_blend + bevp->cosa * (1.0f - bev_blend);
			}

			data[0] += fac * (widfac + fp[1]) * sina;
			data[1] += fac * (widfac + fp[1]) * cosa;
			data[2] += fac * fp[2];
		}
	}

	*r_data = data;
}
Ejemplo n.º 4
0
/* 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);
}
Ejemplo n.º 5
0
/* only meant for timer usage */
static int view3d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
	View3D *v3d = CTX_wm_view3d(C);
	RegionView3D *rv3d = CTX_wm_region_view3d(C);
	struct SmoothView3DStore *sms = rv3d->sms;
	float step, step_inv;
	
	/* escape if not our timer */
	if (rv3d->smooth_timer == NULL || rv3d->smooth_timer != event->customdata)
		return OPERATOR_PASS_THROUGH;
	
	if (sms->time_allowed != 0.0)
		step = (float)((rv3d->smooth_timer->duration) / sms->time_allowed);
	else
		step = 1.0f;
	
	/* end timer */
	if (step >= 1.0f) {
		
		/* if we went to camera, store the original */
		if (sms->to_camera) {
			rv3d->persp = RV3D_CAMOB;
			view3d_smooth_view_state_restore(&sms->org, v3d, rv3d);
		}
		else {
			view3d_smooth_view_state_restore(&sms->dst, v3d, rv3d);

			ED_view3d_camera_lock_sync(v3d, rv3d);
			ED_view3d_camera_lock_autokey(v3d, rv3d, C, true, true);
		}
		
		if ((rv3d->viewlock & RV3D_LOCKED) == 0) {
			rv3d->view = sms->org_view;
		}

		MEM_freeN(rv3d->sms);
		rv3d->sms = NULL;
		
		WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), rv3d->smooth_timer);
		rv3d->smooth_timer = NULL;
		rv3d->rflag &= ~RV3D_NAVIGATING;
	}
	else {
		/* ease in/out */
		step = (3.0f * step * step - 2.0f * step * step * step);

		step_inv = 1.0f - step;

		interp_v3_v3v3(rv3d->ofs,      sms->src.ofs,  sms->dst.ofs,  step);
		interp_qt_qtqt(rv3d->viewquat, sms->src.quat, sms->dst.quat, step);
		
		rv3d->dist = sms->dst.dist * step + sms->src.dist * step_inv;
		v3d->lens  = sms->dst.lens * step + sms->src.lens * step_inv;

		ED_view3d_camera_lock_sync(v3d, rv3d);
		if (ED_screen_animation_playing(CTX_wm_manager(C))) {
			ED_view3d_camera_lock_autokey(v3d, rv3d, C, true, true);
		}

	}
	
	if (rv3d->viewlock & RV3D_BOXVIEW)
		view3d_boxview_copy(CTX_wm_area(C), CTX_wm_region(C));

	/* note: this doesn't work right because the v3d->lens is now used in ortho mode r51636,
	 * when switching camera in quad-view the other ortho views would zoom & reset.
	 *
	 * For now only redraw all regions when smoothview finishes.
	 */
	if (step >= 1.0f) {
		WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
	}
	else {
		ED_region_tag_redraw(CTX_wm_region(C));
	}
	
	return OPERATOR_FINISHED;
}
Ejemplo n.º 6
0
/* calculate the deformation implied by the curve path at a given parametric position,
 * and returns whether this operation succeeded.
 *
 * note: ctime is normalized range <0-1>
 *
 * returns OK: 1/0
 */
int where_on_path(Object *ob, float ctime, float vec[4], float dir[3], float quat[4], float *radius, float *weight)
{
	Curve *cu;
	Nurb *nu;
	BevList *bl;
	Path *path;
	PathPoint *pp, *p0, *p1, *p2, *p3;
	float fac;
	float data[4];
	int cycl=0, s0, s1, s2, s3;

	if (ob==NULL || ob->type != OB_CURVE) return 0;
	cu= ob->data;
	if (cu->path==NULL || cu->path->data==NULL) {
		printf("no path!\n");
		return 0;
	}
	path= cu->path;
	pp= path->data;
	
	/* test for cyclic */
	bl= cu->bev.first;
	if (!bl) return 0;
	if (!bl->nr) return 0;
	if (bl->poly> -1) cycl= 1;

	ctime *= (path->len-1);
	
	s1= (int)floor(ctime);
	fac= (float)(s1+1)-ctime;

	/* path->len is corected for cyclic */
	s0= interval_test(0, path->len-1-cycl, s1-1, cycl);
	s1= interval_test(0, path->len-1-cycl, s1, cycl);
	s2= interval_test(0, path->len-1-cycl, s1+1, cycl);
	s3= interval_test(0, path->len-1-cycl, s1+2, cycl);

	p0= pp + s0;
	p1= pp + s1;
	p2= pp + s2;
	p3= pp + s3;

	/* note, commented out for follow constraint */
	//if (cu->flag & CU_FOLLOW) {

		key_curve_tangent_weights(1.0f-fac, data, KEY_BSPLINE);

		interp_v3_v3v3v3v3(dir, p0->vec, p1->vec, p2->vec, p3->vec, data);

		/* make compatible with vectoquat */
		negate_v3(dir);
	//}
	
	nu= cu->nurb.first;

	/* make sure that first and last frame are included in the vectors here  */
	if (nu->type == CU_POLY) key_curve_position_weights(1.0f-fac, data, KEY_LINEAR);
	else if (nu->type == CU_BEZIER) key_curve_position_weights(1.0f-fac, data, KEY_LINEAR);
	else if (s0==s1 || p2==p3) key_curve_position_weights(1.0f-fac, data, KEY_CARDINAL);
	else key_curve_position_weights(1.0f-fac, data, KEY_BSPLINE);

	vec[0]= data[0]*p0->vec[0] + data[1]*p1->vec[0] + data[2]*p2->vec[0] + data[3]*p3->vec[0] ; /* X */
	vec[1]= data[0]*p0->vec[1] + data[1]*p1->vec[1] + data[2]*p2->vec[1] + data[3]*p3->vec[1] ; /* Y */
	vec[2]= data[0]*p0->vec[2] + data[1]*p1->vec[2] + data[2]*p2->vec[2] + data[3]*p3->vec[2] ; /* Z */
	vec[3]= data[0]*p0->vec[3] + data[1]*p1->vec[3] + data[2]*p2->vec[3] + data[3]*p3->vec[3] ; /* Tilt, should not be needed since we have quat still used */

	if (quat) {
		float totfac, q1[4], q2[4];

		totfac= data[0]+data[3];
		if (totfac>FLT_EPSILON)	interp_qt_qtqt(q1, p0->quat, p3->quat, data[3] / totfac);
		else					copy_qt_qt(q1, p1->quat);

		totfac= data[1]+data[2];
		if (totfac>FLT_EPSILON)	interp_qt_qtqt(q2, p1->quat, p2->quat, data[2] / totfac);
		else					copy_qt_qt(q2, p3->quat);

		totfac = data[0]+data[1]+data[2]+data[3];
		if (totfac>FLT_EPSILON)	interp_qt_qtqt(quat, q1, q2, (data[1]+data[2]) / totfac);
		else					copy_qt_qt(quat, q2);
	}

	if (radius)
		*radius= data[0]*p0->radius + data[1]*p1->radius + data[2]*p2->radius + data[3]*p3->radius;

	if (weight)
		*weight= data[0]*p0->weight + data[1]*p1->weight + data[2]*p2->weight + data[3]*p3->weight;

	return 1;
}
Ejemplo n.º 7
0
/* calculate a curve-deform path for a curve 
 * 	- only called from displist.c -> do_makeDispListCurveTypes
 */
void calc_curvepath(Object *ob)
{
	BevList *bl;
	BevPoint *bevp, *bevpn, *bevpfirst, *bevplast;
	PathPoint *pp;
	Curve *cu;
	Nurb *nu;
	Path *path;
	float *fp, *dist, *maxdist, xyz[3];
	float fac, d=0, fac1, fac2;
	int a, tot, cycl=0;
	ListBase *nurbs;
	
	/* in a path vertices are with equal differences: path->len = number of verts */
	/* NOW WITH BEVELCURVE!!! */
	
	if (ob==NULL || ob->type != OB_CURVE) return;
	cu= ob->data;

	nurbs= BKE_curve_nurbs(cu);
	nu= nurbs->first;

	if (cu->path) free_path(cu->path);
	cu->path= NULL;
	
	bl= cu->bev.first;
	if (bl==NULL || !bl->nr) return;

	cu->path=path= MEM_callocN(sizeof(Path), "calc_curvepath");
	
	/* if POLY: last vertice != first vertice */
	cycl= (bl->poly!= -1);
	
	if (cycl) tot= bl->nr;
	else tot= bl->nr-1;
	
	path->len= tot+1;
	/* exception: vector handle paths and polygon paths should be subdivided at least a factor resolu */
	if (path->len<nu->resolu*SEGMENTSU(nu)) path->len= nu->resolu*SEGMENTSU(nu);
	
	dist= (float *)MEM_mallocN((tot+1)*4, "calcpathdist");

		/* all lengths in *dist */
	bevp= bevpfirst= (BevPoint *)(bl+1);
	fp= dist;
	*fp= 0;
	for (a=0; a<tot; a++) {
		fp++;
		if (cycl && a==tot-1)
			sub_v3_v3v3(xyz, bevpfirst->vec, bevp->vec);
		else
			sub_v3_v3v3(xyz, (bevp+1)->vec, bevp->vec);
		
		*fp= *(fp-1)+len_v3(xyz);
		bevp++;
	}
	
	path->totdist= *fp;
	
		/* the path verts  in path->data */
		/* now also with TILT value */
	pp= path->data = (PathPoint *)MEM_callocN(sizeof(PathPoint)*path->len, "pathdata");
	
	bevp= bevpfirst;
	bevpn= bevp+1;
	bevplast= bevpfirst + (bl->nr-1);
	fp= dist+1;
	maxdist= dist+tot;
	fac= 1.0f/((float)path->len-1.0f);
		fac = fac * path->totdist;
	
	for (a=0; a<path->len; a++) {
		
		d= ((float)a)*fac;
		
		/* we're looking for location (distance) 'd' in the array */
		while ((d>= *fp) && fp<maxdist) {
			fp++;
			if (bevp<bevplast) bevp++;
			bevpn= bevp+1;
			if (bevpn>bevplast) {
				if (cycl) bevpn= bevpfirst;
				else bevpn= bevplast;
			}
		}
		
		fac1= *(fp)- *(fp-1);
		fac2= *(fp)-d;
		fac1= fac2/fac1;
		fac2= 1.0f-fac1;
		
		interp_v3_v3v3(pp->vec, bevp->vec, bevpn->vec, fac2);
		pp->vec[3]= fac1*bevp->alfa + fac2*bevpn->alfa;
		pp->radius= fac1*bevp->radius + fac2*bevpn->radius;
		pp->weight= fac1*bevp->weight + fac2*bevpn->weight;
		interp_qt_qtqt(pp->quat, bevp->quat, bevpn->quat, fac2);
		normalize_qt(pp->quat);
		
		pp++;
	}
	
	MEM_freeN(dist);
}
Ejemplo n.º 8
0
/* only meant for timer usage */
static int view3d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
{
	View3D *v3d = CTX_wm_view3d(C);
	RegionView3D *rv3d= CTX_wm_region_view3d(C);
	struct SmoothViewStore *sms= rv3d->sms;
	float step, step_inv;
	
	/* escape if not our timer */
	if(rv3d->smooth_timer==NULL || rv3d->smooth_timer!=event->customdata)
		return OPERATOR_PASS_THROUGH;
	
	if(sms->time_allowed != 0.0)
		step = (float)((rv3d->smooth_timer->duration)/sms->time_allowed);
	else
		step = 1.0f;
	
	/* end timer */
	if(step >= 1.0f) {
		
		/* if we went to camera, store the original */
		if(sms->to_camera) {
			rv3d->persp= RV3D_CAMOB;
			copy_v3_v3(rv3d->ofs, sms->orig_ofs);
			copy_qt_qt(rv3d->viewquat, sms->orig_quat);
			rv3d->dist = sms->orig_dist;
			v3d->lens = sms->orig_lens;
		}
		else {
			copy_v3_v3(rv3d->ofs, sms->new_ofs);
			copy_qt_qt(rv3d->viewquat, sms->new_quat);
			rv3d->dist = sms->new_dist;
			v3d->lens = sms->new_lens;

			ED_view3d_camera_lock_sync(v3d, rv3d);
		}
		
		if((rv3d->viewlock & RV3D_LOCKED)==0) {
			rv3d->view= sms->orig_view;
		}

		MEM_freeN(rv3d->sms);
		rv3d->sms= NULL;
		
		WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), rv3d->smooth_timer);
		rv3d->smooth_timer= NULL;
		rv3d->rflag &= ~RV3D_NAVIGATING;
	}
	else {
		int i;
		
		/* ease in/out */
		if (step < 0.5f)	step = (float)pow(step*2.0f, 2.0)/2.0f;
		else				step = (float)1.0f-(powf(2.0f*(1.0f-step),2.0f)/2.0f);

		step_inv = 1.0f-step;

		for (i=0; i<3; i++)
			rv3d->ofs[i] = sms->new_ofs[i] * step + sms->orig_ofs[i]*step_inv;

		interp_qt_qtqt(rv3d->viewquat, sms->orig_quat, sms->new_quat, step);
		
		rv3d->dist = sms->new_dist * step + sms->orig_dist*step_inv;
		v3d->lens = sms->new_lens * step + sms->orig_lens*step_inv;

		ED_view3d_camera_lock_sync(v3d, rv3d);
	}
	
	if(rv3d->viewlock & RV3D_BOXVIEW)
		view3d_boxview_copy(CTX_wm_area(C), CTX_wm_region(C));
	
	WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, v3d);
	
	return OPERATOR_FINISHED;
}
Ejemplo n.º 9
0
/* helper for apply() - perform sliding for quaternion rotations (using quat blending) */
static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
{
	FCurve *fcu_w = NULL, *fcu_x = NULL, *fcu_y = NULL, *fcu_z = NULL;
	bPoseChannel *pchan = pfl->pchan;
	LinkData *ld = NULL;
	char *path = NULL;
	float cframe;
	
	/* get the path to use - this should be quaternion rotations only (needs care) */
	path = BLI_sprintfN("%s.%s", pfl->pchan_path, "rotation_quaternion");
	
	/* get the current frame number */
	cframe = (float)pso->cframe;
	
	/* using this path, find each matching F-Curve for the variables we're interested in */
	while ( (ld = poseAnim_mapping_getNextFCurve(&pfl->fcurves, ld, path)) ) {
		FCurve *fcu = (FCurve *)ld->data;
		
		/* assign this F-Curve to one of the relevant pointers... */
		switch (fcu->array_index) {
			case 3: /* z */
				fcu_z = fcu;
				break;
			case 2: /* y */
				fcu_y = fcu;
				break;
			case 1: /* x */
				fcu_x = fcu;
				break;
			case 0: /* w */
				fcu_w = fcu;
				break;
		}
	}
	
	/* only if all channels exist, proceed */
	if (fcu_w && fcu_x && fcu_y && fcu_z) {
		float quat_prev[4], quat_next[4];
		
		/* get 2 quats */
		quat_prev[0] = evaluate_fcurve(fcu_w, pso->prevFrame);
		quat_prev[1] = evaluate_fcurve(fcu_x, pso->prevFrame);
		quat_prev[2] = evaluate_fcurve(fcu_y, pso->prevFrame);
		quat_prev[3] = evaluate_fcurve(fcu_z, pso->prevFrame);
		
		quat_next[0] = evaluate_fcurve(fcu_w, pso->nextFrame);
		quat_next[1] = evaluate_fcurve(fcu_x, pso->nextFrame);
		quat_next[2] = evaluate_fcurve(fcu_y, pso->nextFrame);
		quat_next[3] = evaluate_fcurve(fcu_z, pso->nextFrame);
		
		/* perform blending */
		if (pso->mode == POSESLIDE_BREAKDOWN) {
			/* just perform the interpol between quat_prev and quat_next using pso->percentage as a guide */
			interp_qt_qtqt(pchan->quat, quat_prev, quat_next, pso->percentage);
		}
		else if (pso->mode == POSESLIDE_PUSH) {
			float quat_diff[4], quat_orig[4];

			/* calculate the delta transform from the previous to the current */
			/* TODO: investigate ways to favour one transform more? */
			sub_qt_qtqt(quat_diff, pchan->quat, quat_prev);

			/* make a copy of the original rotation */
			copy_qt_qt(quat_orig, pchan->quat);
			
			/* increase the original by the delta transform, by an amount determined by percentage */
			add_qt_qtqt(pchan->quat, quat_orig, quat_diff, pso->percentage);
		}
		else {
			float quat_interp[4], quat_orig[4];
			int iters = (int)ceil(10.0f * pso->percentage); /* TODO: maybe a sensitivity ctrl on top of this is needed */

			/* perform this blending several times until a satisfactory result is reached */
			while (iters-- > 0) {
				/* calculate the interpolation between the endpoints */
				interp_qt_qtqt(quat_interp, quat_prev, quat_next, (cframe - pso->prevFrame) / (pso->nextFrame - pso->prevFrame));
				
				/* make a copy of the original rotation */
				copy_qt_qt(quat_orig, pchan->quat);
				
				/* tricky interpolations - blending between original and new */
				interp_qt_qtqt(pchan->quat, quat_orig, quat_interp, 1.0f / 6.0f);
			}
		}
	}
	
	/* free the path now */
	MEM_freeN(path);
}
Ejemplo n.º 10
0
static void do_kink_spiral(ParticleThreadContext *ctx, ParticleTexture *ptex, const float parent_orco[3],
                           ChildParticle *cpa, const float orco[3], float hairmat[4][4],
                           ParticleCacheKey *keys, ParticleCacheKey *parent_keys, int *r_totkeys, float *r_max_length)
{
	struct ParticleSettings *part = ctx->sim.psys->part;
	const int seed = ctx->sim.psys->child_seed + (int)(cpa - ctx->sim.psys->child);
	const int totkeys = ctx->segments + 1;
	const int extrakeys = ctx->extra_segments;

	float kink_amp_random = part->kink_amp_random;
	float kink_amp = part->kink_amp * (1.0f - kink_amp_random * psys_frand(ctx->sim.psys, 93541 + seed));
	float kink_freq = part->kink_freq;
	float kink_shape = part->kink_shape;
	float kink_axis_random = part->kink_axis_random;
	float rough1 = part->rough1;
	float rough2 = part->rough2;
	float rough_end = part->rough_end;

	ParticlePathIterator iter;
	ParticleCacheKey *key;
	int k;

	float dir[3];
	float spiral_start[3] = {0.0f, 0.0f, 0.0f};
	float spiral_start_time = 0.0f;
	float spiral_par_co[3] = {0.0f, 0.0f, 0.0f};
	float spiral_par_vel[3] = {0.0f, 0.0f, 0.0f};
	float spiral_par_rot[4] = {1.0f, 0.0f, 0.0f, 0.0f};
	float totlen;
	float cut_time;
	int start_index = 0, end_index = 0;
	float kink_base[3];

	if (ptex) {
		kink_amp *= ptex->kink_amp;
		kink_freq *= ptex->kink_freq;
		rough1 *= ptex->rough1;
		rough2 *= ptex->rough2;
		rough_end *= ptex->roughe;
	}

	cut_time = (totkeys - 1) * ptex->length;
	zero_v3(spiral_start);

	for (k = 0, key = keys; k < totkeys-1; k++, key++) {
		if ((float)(k + 1) >= cut_time) {
			float fac = cut_time - (float)k;
			ParticleCacheKey *par = parent_keys + k;

			start_index = k + 1;
			end_index = start_index + extrakeys;

			spiral_start_time = ((float)k + fac) / (float)(totkeys - 1);
			interp_v3_v3v3(spiral_start, key->co, (key+1)->co, fac);

			interp_v3_v3v3(spiral_par_co, par->co, (par+1)->co, fac);
			interp_v3_v3v3(spiral_par_vel, par->vel, (par+1)->vel, fac);
			interp_qt_qtqt(spiral_par_rot, par->rot, (par+1)->rot, fac);

			break;
		}
	}

	zero_v3(dir);

	zero_v3(kink_base);
	kink_base[part->kink_axis] = 1.0f;
	mul_mat3_m4_v3(ctx->sim.ob->obmat, kink_base);

	/* Fill in invariant part of modifier context. */
	ParticleChildModifierContext modifier_ctx = {NULL};
	modifier_ctx.thread_ctx = ctx;
	modifier_ctx.sim = &ctx->sim;
	modifier_ctx.ptex = ptex;
	modifier_ctx.cpa = cpa;
	modifier_ctx.orco = orco;
	modifier_ctx.parent_keys = parent_keys;

	for (k = 0, key = keys; k < end_index; k++, key++) {
		float par_time;
		float *par_co, *par_vel, *par_rot;

		psys_path_iter_get(&iter, keys, end_index, NULL, k);
		if (k < start_index) {
			sub_v3_v3v3(dir, (key+1)->co, key->co);
			normalize_v3(dir);

			par_time = (float)k / (float)(totkeys - 1);
			par_co = parent_keys[k].co;
			par_vel = parent_keys[k].vel;
			par_rot = parent_keys[k].rot;
		}
		else {
			float spiral_time = (float)(k - start_index) / (float)(extrakeys-1);
			float kink[3], tmp[3];

			/* use same time value for every point on the spiral */
			par_time = spiral_start_time;
			par_co = spiral_par_co;
			par_vel = spiral_par_vel;
			par_rot = spiral_par_rot;

			project_v3_v3v3(tmp, kink_base, dir);
			sub_v3_v3v3(kink, kink_base, tmp);
			normalize_v3(kink);

			if (kink_axis_random > 0.0f) {
				float a = kink_axis_random * (psys_frand(ctx->sim.psys, 7112 + seed) * 2.0f - 1.0f) * (float)M_PI;
				float rot[3][3];

				axis_angle_normalized_to_mat3(rot, dir, a);
				mul_m3_v3(rot, kink);
			}

			do_kink_spiral_deform((ParticleKey *)key, dir, kink, spiral_time, kink_freq, kink_shape, kink_amp, spiral_start);
		}

		/* Fill in variant part of modifier context. */
		modifier_ctx.par_co = par_co;
		modifier_ctx.par_vel = par_vel;
		modifier_ctx.par_rot = par_rot;
		modifier_ctx.par_orco = parent_orco;

		/* Apply different deformations to the child path/ */
		do_child_modifiers(&modifier_ctx, hairmat, (ParticleKey *)key, par_time);
	}

	totlen = 0.0f;
	for (k = 0, key = keys; k < end_index-1; k++, key++)
		totlen += len_v3v3((key+1)->co, key->co);

	*r_totkeys = end_index;
	*r_max_length = totlen;
}