How To Calculate KXP Spline Derivatives A Tips & Techniques document for use with the IPAS Toolkit July 13, 1995 Introduction: Several IPAS developers have requested information regarding how the derivatives for 3DS spline interpolation are computed for KXP development. This document contains a fairly uncommented example that will demonstrate 3D Studio's implementation of spline interpolation. Example 3D Studio Key Interpolation Code The following is an example of 3D Studio's key interpolation code for KXP IPAS developers. Note that position keys are handled just like any other track type except for rotations. Those are handled as detailed in the CompAB() function below. NOTE: This is unsupported code; use at your own risk. static void CompElementDeriv( float pp, float p, float pn, float *ds, float *dd,float ksm, float ksp, float kdm, float kdp ) { float delm, delp; delm = p - pp; delp = pn - p; *ds = ksm*delm + ksp*delp; *dd = kdm*delm + kdp*delp; } /*------------------------------------------------------- This computes the derivative at key, as a weighted average of the linear slopes into and out of key, the weights being determined by the tension and continuity "ds" is the "source derivative", or "arriving derivative" "dd" is the "destination derivative" or "departing derivative" ----------------------------------------------------------*/ static void CompDeriv( PosKey *keyp, PosKey *key, PosKey *keyn ) { int i; /* Full TCB computation */ float tm,cm,cp,bm,bp,tmcm,tmcp,ksm,ksp,kdm,kdp,delm,delp,c; float dt,fp,fn; /* fp,fn apply speed correction when continuity is 0.0 */ dt = .5 * (float)( keyn->frame - keyp->frame ); fp = ( (float)( key->frame - keyp->frame ) ) / dt; fn = ( (float)( keyn->frame - key->frame ) ) / dt; c = fabs( key->cont ); fp = fp + c - c * fp; fn = fn + c - c * fn; cm = 1.0 - key->cont; tm = 0.5 * ( 1.0 - key->tens ); cp = 2.0 - cm; bm = 1.0 - key->bias; bp = 2.0 - bm; tmcm = tm*cm; tmcp = tm*cp; ksm = tmcm*bp*fp; ksp = tmcp*bm*fp; kdm = tmcp*bp*fn; kdp = tmcm*bm*fn; for( i = X; i <= Z; i++ ) { CompElementDeriv( keyp->pos[i], key->pos[i], keyn->pos[i], &key->ds[i], &key->dd[i], ksm, ksp, kdm, kdp ); } } /* ----------------------------------------------------------- Compute the "a" and "b" terms at key "cur", which determine the incoming and outgoing tangents (in quaternion space ) -----------------------------------------------------------*/ static int CompAB( RotKey *prev, RotKey *cur, RotKey *next ) { int i; float qprev[4],qnext[4],q[4],qzero[4]; float qp[4],qm[4],qa[4],qb[4],qae[4],qbe[4]; float tm,cm,cp,bm,bp,tmcm,tmcp,ksm,ksp,kdm,kdp,c; float dt,fp,fn; if( prev != NULL ) { if( cur->angle > TWOPI-.00001 ) { COPY_POINT3( q, cur->axis ); q[3] = 0; qlog( q,qm ); } else { qcopy( qprev, prev->quat ); if( qdot( qprev, cur->quat ) < 0 ) qnegate( qprev ); qlndif( qprev, cur->quat, qm ); } } if( next != NULL ) { if( next->angle > TWOPI-.00001 ) { COPY_POINT3( q, next->axis ); q[3] = 0; qlog( q, qp ); } else { qcopy( qnext, next->quat ); if( qdot( qnext, cur->quat ) < 0 ) qnegate( qnext ); qlndif( cur->quat, qnext, qp ); } } if( prev == NULL ) qcopy( qm, qp ); if( next == NULL ) qcopy( qp, qm ); fp = fn = 1.0; cm = 1.0 - cur->cont; if( prev && next ) { dt = 0.5 * (float)(next->frame - prev->frame ); fp = ((float)(cur->frame - prev->frame))/dt; fn = ((float)(next->frame - cur->frame))/dt; c = fabs( cur->cont ); fp = fp + c - c * fp; fn = fn + c - c * fn; } tm = .5*(1.0 - cur->tens); cp = 2.0 - cm; bm = 1.0 - cur->bias; bp = 2.0 - bm; tmcm = tm * cm; tmcp = tm * cp; ksm = 1.0 - tmcm * bp * fp; ksp = -tmcp * bm * fp; kdm = tmcp * bp * fn; kdp = tmcm * bm * fn - 1.0; for( i = 0; i < 4; i++ ) { qa[i] = .5 * ( kdm * qm[i] + kdp * qp[i] ); qb[i] = .5 * ( ksm * qm[i] + ksp * qp[i] ); } qexp( qa, qae ); qexp( qb, qbe ); qmul( cur->quat, qae, cur->a ); qmul( cur->quat, qbe, cur->b ); return TRUE; } /* Subject: Re: Question re derivs.c (fwd) It looks like deriv.c didn't contain the ease function -- just the geometric derivatives. In that case, here's the ease function: */ /* Ease: remap parameter between two keys to apply eases Call this with a = easeFrom of key[n], b = easeTo of key[n+1], and u = (t-t[n]/(t[n+1]-t[n]) -------------------------------------*/ local float Ease(float u, float a, float b) { float k; float s = a+b; if (s==0.0) return(u); if (s>1.0) { a = a/s; b = b/s; } k = 1.0/(2.0-a-b); if (u < a) return((k/a)*u*u); else if (u<1.0-b) return( k*(2*u - a)); else { u = 1.0-u; return(1.0-(k/b)*u*u); }