/** * Resamples animation until maximum error is smaller than specified value. * @param maxErr Maximum absolute error */ static void resampleFloatKeys( KeyFrameContainer& anim, Interval range, float maxErr, const Vector<float>& frames ) { TimeValue dticks = SGEXPORT_TICKS_PER_SAMPLE; int frame = range.Start() / dticks; require( frame >= 0 && frame < frames.size() ); TimeValue rangeLen = (range.Duration()/SGEXPORT_TICKS_PER_SAMPLE)*SGEXPORT_TICKS_PER_SAMPLE; for ( TimeValue ticks = range.Start() ; ticks < range.End() ; ticks += dticks ) { if ( ticks > range.End() ) ticks = range.End(); // find out error (distance) between real and sampled animation require( frame >= 0 && frame < frames.size() ); float realValue = frames[frame++]; float sampledValue = 0.f; anim.getValue( TicksToSec(ticks), &sampledValue, 1 ); float err = Math::abs( realValue - sampledValue ); // sample more accurately if needed if ( err > maxErr && rangeLen > dticks ) { TimeValue halfRange = alignTicks( (range.End() + range.Start())/2 ); anim.insertKey( KeyFrame( TicksToSec(halfRange), INTERP_TYPE, &frames[halfRange/dticks], 1 ) ); if ( ticks <= halfRange ) resampleFloatKeys( anim, Interval(range.Start(),halfRange), maxErr, frames ); else resampleFloatKeys( anim, Interval(halfRange,range.End()), maxErr, frames ); } if ( ticks == range.End() ) break; } }
void FloatMC::BeginCapture(Interval record,TimeValue sampSize) { // Set the base point to the controller value at the start time. cont->GetValue(record.Start(),&base,FOREVER,CTRL_ABSOLUTE); // Allocate a data buffer sampleCount = record.Duration()/sampSize + 1; data = new float[sampleCount]; for (int i=0; i<sampleCount; i++) data[i] = 0.0f; }
void ScaleMC::BeginCapture(Interval record,TimeValue sampSize) { // Set the base point to the controller value at the start time. ScaleValue s; cont->GetValue(record.Start(),&s,FOREVER,CTRL_ABSOLUTE); base = s.s; // Allocate a data buffer sampleCount = record.Duration()/sampSize + 1; data = new Point3[sampleCount]; for (int i=0; i<sampleCount; i++) data[i] = Point3(1,1,1); }
void RotationMC::BeginCapture(Interval record,TimeValue sampSize) { // Set the base point to the controller value at the start time. Quat q; cont->GetValue(record.Start(),&q,FOREVER,CTRL_ABSOLUTE); QuatToEuler(q,base); // Allocate a data buffer sampleCount = record.Duration()/sampSize + 1; data = new Point3[sampleCount]; for (int i=0; i<sampleCount; i++) data[i] = Point3(0,0,0); }
/** * Resamples animation until maximum error is smaller than specified angle (radians). * @param maxErr Maximum absolute error (radians). */ static void resampleRotationKeys( KeyFrameContainer& anim, Interval range, float maxErr, const Vector<Matrix4x4>& tm ) { TimeValue dticks = SGEXPORT_TICKS_PER_SAMPLE; int frame = range.Start() / dticks; require( frame >= 0 && frame < tm.size() ); TimeValue rangeLen = (range.Duration()/SGEXPORT_TICKS_PER_SAMPLE)*SGEXPORT_TICKS_PER_SAMPLE; for ( TimeValue ticks = range.Start() ; ticks < range.End() ; ticks += dticks ) { if ( ticks > range.End() ) ticks = range.End(); // find out error (distance) between real and sampled animation require( frame >= 0 && frame < tm.size() ); const Matrix4x4& m = tm[frame++]; Matrix3x3 ref = m.rotation().orthonormalize(); float q[4]; anim.getValue( TicksToSec(ticks), q, 4 ); Matrix3x3 cmp( Quaternion(q[0],q[1],q[2],q[3]) ); float xang = Math::abs( Math::acos( clamp(cmp.getColumn(0).dot(ref.getColumn(0)), -1.f, 1.f) ) ); float yang = Math::abs( Math::acos( clamp(cmp.getColumn(1).dot(ref.getColumn(1)), -1.f, 1.f) ) ); float zang = Math::abs( Math::acos( clamp(cmp.getColumn(2).dot(ref.getColumn(2)), -1.f, 1.f) ) ); float err = xang; if ( yang > err ) err = yang; if ( zang > err ) err = zang; // sample more accurately if needed if ( err > maxErr && rangeLen > dticks ) { TimeValue halfRange = alignTicks( (range.End() + range.Start())/2 ); AnimExportUtil::addRotationKey( anim, tm[halfRange/dticks], TicksToSec(halfRange) ); if ( ticks <= halfRange ) resampleRotationKeys( anim, Interval(range.Start(),halfRange), maxErr, tm ); else resampleRotationKeys( anim, Interval(halfRange,range.End()), maxErr, tm ); } if ( ticks == range.End() ) break; } }
/** * Resamples animation until maximum error is smaller than specified value. * @param maxErr Maximum relative error, i.e. 0.05f == 5%. */ static void resampleScaleKeys( KeyFrameContainer& anim, Interval range, float maxErr, const Vector<Matrix4x4>& tm ) { TimeValue dticks = SGEXPORT_TICKS_PER_SAMPLE; int frame = range.Start() / dticks; require( frame >= 0 && frame < tm.size() ); TimeValue rangeLen = (range.Duration()/SGEXPORT_TICKS_PER_SAMPLE)*SGEXPORT_TICKS_PER_SAMPLE; for ( TimeValue ticks = range.Start() ; ticks < range.End() ; ticks += dticks ) { if ( ticks > range.End() ) ticks = range.End(); // find out error (distance) between real and sampled animation require( frame >= 0 && frame < tm.size() ); const Matrix4x4& m = tm[frame++]; Vector3 ref; Vector3 a; a = getAxis(m,0); ref[0] = a.dot(normalize0(a)); a = getAxis(m,1); ref[1] = a.dot(normalize0(a)); a = getAxis(m,2); ref[2] = a.dot(normalize0(a)); float cmp[3]; anim.getValue( TicksToSec(ticks), cmp, 3 ); float err = (Vector3(cmp[0],cmp[1],cmp[2]) - ref).length(); if ( ref.length() > Float::MIN_VALUE ) err /= ref.length(); // sample more accurately if needed if ( err > maxErr && rangeLen > dticks ) { TimeValue halfRange = alignTicks( (range.End() + range.Start())/2 ); AnimExportUtil::addScaleKey( anim, tm[halfRange/dticks], TicksToSec(halfRange) ); if ( ticks <= halfRange ) resampleScaleKeys( anim, Interval(range.Start(),halfRange), maxErr, tm ); else resampleScaleKeys( anim, Interval(halfRange,range.End()), maxErr, tm ); } if ( ticks == range.End() ) break; } }