SampleAnimation() public method

public SampleAnimation ( AnimationClip animation, float time ) : void
animation AnimationClip
time float
return void
Example #1
0
    void StopAnim(GameObject agent){
        if (agent.GetComponent<ArmAnimator>().ArmC == null || agent.GetComponent<TorsoAnimator>().TorsoC == null) {
			Debug.Log ("Controller not assigned");
			return;
		}

        if (agent.animation.isPlaying) {
            agent.SampleAnimation(agent.animation.clip, 0); //instead of rewind
            agent.animation.Stop();           
        }       
    }
Example #2
0
	public override void Analyze(GameObject o) {
		Debug.Log("Starting analysis");
		gameObject = o;
		name = animation.name;
		m_samples = 50;
		
		// Initialize legs and cycle data
		legC = gameObject.GetComponent(typeof(LegController)) as LegController;
		legs = legC.legs.Length;
		m_cycles = new LegCycleData[legs];
		for (int leg=0; leg<legs; leg++) {
			cycles[leg] = new LegCycleData();
			cycles[leg].samples = new LegCycleSample[samples+1];
			for (int i=0; i<samples+1; i++) {
				cycles[leg].samples[i] = new LegCycleSample();
			}
			cycles[leg].debugInfo = new CycleDebugInfo();
		}
		
		graphMin = new Vector3(0, 1000, 1000);
		graphMax = new Vector3(0,-1000,-1000);
		
		for (int leg=0; leg<legs; leg++) {
			// Sample ankle, heel, toe, and toetip positions over the length of the animation.
			Transform ankleT = legC.legs[leg].ankle;
			Transform toeT = legC.legs[leg].toe;
			
			float rangeMax = 0;
			float ankleMin; float ankleMax; float toeMin; float toeMax;
			ankleMin = 1000;
			ankleMax = -1000;
			toeMin = 1000;
			toeMax = -1000;
			for (int i=0; i<samples+1; i++) {
				LegCycleSample s = cycles[leg].samples[i];
				gameObject.SampleAnimation(animation,i*1.0f/samples*animation.length);
				s.ankleMatrix = Util.RelativeMatrix(ankleT,gameObject.transform);
				s.toeMatrix = Util.RelativeMatrix(toeT,gameObject.transform);
				s.heel = s.ankleMatrix.MultiplyPoint(legC.legs[leg].ankleHeelVector);
				s.toetip = s.toeMatrix.MultiplyPoint(legC.legs[leg].toeToetipVector);
				s.middle = (s.heel+s.toetip)/2;
				
				// For each sample in time we want to know if the heel or toetip is closer to the ground.
				// We need a smooth curve with 0 = ankle is closer and 1 = toe is closer.
				s.balance = MotionAnalyzer.GetFootBalance(s.heel.y, s.toetip.y, legC.legs[leg].footLength);
				
				// Find the minimum and maximum extends on all axes of the ankle and toe positions.
				ankleMin = Mathf.Min(ankleMin,s.heel.y);
				toeMin = Mathf.Min(toeMin,s.toetip.y);
				ankleMax = Mathf.Max(ankleMax,s.heel.y);
				toeMax = Mathf.Max(toeMax,s.toetip.y);
			}
			rangeMax = Mathf.Max(ankleMax-ankleMin,toeMax-toeMin);
			
			// Determine motion type
			/*if (motionType==MotionType.AutoDetect) {
				motionType = MotionType.WalkCycle;
			}*/
			
			if (motionType==MotionType.WalkCycle) {
				FindCycleAxis(leg);
				
				// Foot stance time
				// Find the time when the foot stands most firmly on the ground.
				float stanceValue = Mathf.Infinity;
				for (int i=0; i<samples+1; i++) {
					LegCycleSample s = cycles[leg].samples[i];
					
					float sampleValue =
					// We want the point in time when the max of the heel height and the toe height is lowest
					Mathf.Max(s.heel.y, s.toetip.y)/rangeMax
					// Add some bias to poses where the leg is in the middle of the swing
					// i.e. the foot position is close to the middle of the foot curve
					+Mathf.Abs(
						Util.ProjectOntoPlane(s.middle-cycles[leg].cycleCenter, Vector3.up).magnitude
					)/cycles[leg].cycleScaling;
					
					// Use the new value if it is lower (better).
					if (sampleValue<stanceValue) {
						cycles[leg].stanceIndex = i;
						stanceValue = sampleValue;
					}
				}
			}
			else {
				cycles[leg].cycleDirection = Vector3.forward;
				cycles[leg].cycleScaling = 0;
				cycles[leg].stanceIndex = 0;
			}
			// The stance time
			cycles[leg].stanceTime = GetTimeFromIndex(cycles[leg].stanceIndex);
			
			// The stance index sample
			LegCycleSample ss = cycles[leg].samples[cycles[leg].stanceIndex];
			// Sample the animation at stance time
			gameObject.SampleAnimation(animation,cycles[leg].stanceTime*animation.length);
			
			// Using the stance sample as reference we can now determine:
			
			// The vector from heel to toetip at the stance pose 
			cycles[leg].heelToetipVector = (
				ss.toeMatrix.MultiplyPoint(legC.legs[leg].toeToetipVector)
				- ss.ankleMatrix.MultiplyPoint(legC.legs[leg].ankleHeelVector)
			);
			cycles[leg].heelToetipVector = Util.ProjectOntoPlane(cycles[leg].heelToetipVector, Vector3.up);
			cycles[leg].heelToetipVector = cycles[leg].heelToetipVector.normalized * legC.legs[leg].footLength;
			
			// Calculate foot flight path based on weighted average between ankle flight path and toe flight path,
			// using foot balance as weight.
			// The distance between ankle and toe is accounted for, using the stance pose for reference.
			for (int i=0; i<samples+1; i++) {
				LegCycleSample s = cycles[leg].samples[i];
				s.footBase = (
					(s.heel)*(1-s.balance)
					+(s.toetip-cycles[leg].heelToetipVector)*(s.balance)
				);
			}
			
			// The position of the footbase in the stance pose
			cycles[leg].stancePosition = ss.footBase;
			cycles[leg].stancePosition.y = legC.groundPlaneHeight;
			
			if (motionType==MotionType.WalkCycle) {
				// Find contact times:
				// Strike time: foot first touches the ground (0% grounding)
				// Down time: all of the foot touches the ground (100% grounding)
				// Lift time: all of the foot still touches the ground but begins to lift (100% grounding)
				// Liftoff time: last part of the foot leaves the ground (0% grounding)
				float timeA;
				float timeB;
				
				// Find upwards contact times for projected ankle and toe
				// Use the first occurance as lift time and the second as liftoff time
				timeA = FindContactTime(cycles[leg], false, +1, rangeMax, 0.1f);
				cycles[leg].debugInfo.ankleLiftTime = timeA;
				timeB = FindContactTime(cycles[leg], true,  +1, rangeMax, 0.1f);
				cycles[leg].debugInfo.toeLiftTime = timeB;
				if (timeA<timeB) {
					cycles[leg].liftTime = timeA;
					cycles[leg].liftoffTime = timeB;
				}
				else {
					cycles[leg].liftTime = timeB;
					cycles[leg].liftoffTime = timeA;
				}
				
				// Find time where swing direction and speed changes significantly.
				// If this happens sooner than the found liftoff time,
				// then the liftoff time must be overwritten with this value.
				timeA = FindSwingChangeTime(cycles[leg], +1, 0.5f);
				cycles[leg].debugInfo.footLiftTime = timeA;
				if (cycles[leg].liftoffTime > timeA) {
					cycles[leg].liftoffTime = timeA;
					if (cycles[leg].liftTime > cycles[leg].liftoffTime) {
						cycles[leg].liftTime = cycles[leg].liftoffTime;
					}
				}
				
				// Find downwards contact times for projected ankle and toe
				// Use the first occurance as strike time and the second as down time
				timeA = FindContactTime(cycles[leg], false, -1, rangeMax, 0.1f);
				timeB = FindContactTime(cycles[leg], true,  -1, rangeMax, 0.1f);
				if (timeA<timeB) {
					cycles[leg].strikeTime = timeA;
					cycles[leg].landTime = timeB;
				}
				else {
					cycles[leg].strikeTime = timeB;
					cycles[leg].landTime = timeA;
				}
				
				// Find time where swing direction and speed changes significantly.
				// If this happens later than the found strike time,
				// then the strike time must be overwritten with this value.
				timeA = FindSwingChangeTime(cycles[leg], -1, 0.5f);
				cycles[leg].debugInfo.footLandTime = timeA;
				if (cycles[leg].strikeTime < timeA) {
					cycles[leg].strikeTime = timeA;
					if (cycles[leg].landTime < cycles[leg].strikeTime) {
						cycles[leg].landTime = cycles[leg].strikeTime;
					}
				}
				
				// Set postliftTime and prelandTime
				float softening = 0.2f;
				
				cycles[leg].postliftTime = cycles[leg].liftoffTime;
				if (cycles[leg].postliftTime < cycles[leg].liftTime+softening) {
					cycles[leg].postliftTime = cycles[leg].liftTime+softening;
				}
				
				cycles[leg].prelandTime = cycles[leg].strikeTime;
				if (cycles[leg].prelandTime > cycles[leg].landTime-softening) {
					cycles[leg].prelandTime = cycles[leg].landTime-softening;
				}
				
				// Calculate the distance traveled during one cycle (for this foot).
				Vector3 stanceSlideVector = (
					cycles[leg].samples[GetIndexFromTime(Util.Mod(cycles[leg].liftoffTime+cycles[leg].stanceTime))].footBase
					-cycles[leg].samples[GetIndexFromTime(Util.Mod(cycles[leg].strikeTime+cycles[leg].stanceTime))].footBase
				);
				// FIXME: Assumes horizontal ground plane
				stanceSlideVector.y = 0;
				cycles[leg].cycleDistance = stanceSlideVector.magnitude/(cycles[leg].liftoffTime-cycles[leg].strikeTime+1);
				cycles[leg].cycleDirection = -(stanceSlideVector.normalized);
			}
			else {
				cycles[leg].cycleDirection = Vector3.zero;
				cycles[leg].cycleDistance = 0;
			}
			
			graphMax.y = Mathf.Max(graphMax.y,Mathf.Max(ankleMax,toeMax));
		}
		
		// Find the overall speed and direction traveled during one cycle,
		// based on average of speed values for each individual foot.
		// (They should be very close, but animations are often imperfect,
		// leading to different speeds for different legs.)
		m_cycleDistance = 0;
		m_cycleDirection = Vector3.zero;
		for (int leg=0; leg<legs; leg++) {
			m_cycleDistance += cycles[leg].cycleDistance;
			m_cycleDirection += cycles[leg].cycleDirection;
			Debug.Log("Cycle direction of leg "+leg+" is "+cycles[leg].cycleDirection+" with step distance "+cycles[leg].cycleDistance);
		}
		m_cycleDistance /= legs;
		m_cycleDirection /= legs;
		m_cycleDuration = animation.length;
		m_cycleSpeed = cycleDistance/cycleDuration;
		Debug.Log("Overall cycle direction is "+m_cycleDirection+" with step distance "+m_cycleDistance+" and speed "+m_cycleSpeed);
		nativeSpeed = m_cycleSpeed * gameObject.transform.localScale.x;
		
		// Calculate normalized foot flight path
		for (int leg=0; leg<legs; leg++) {
			if (motionType==MotionType.WalkCycle) {
				for (int j=0; j<samples; j++) {
					int i = Util.Mod(j+cycles[leg].stanceIndex,samples);
					LegCycleSample s = cycles[leg].samples[i];
					float time = GetTimeFromIndex(j);
					s.footBaseNormalized = s.footBase;
					
					if (fixFootSkating) {
						// Calculate normalized foot flight path
						// based on the calculated cycle distance of each individual foot
						Vector3 reference = (
							-cycles[leg].cycleDistance * cycles[leg].cycleDirection * (time-cycles[leg].liftoffTime)
							+cycles[leg].samples[
								GetIndexFromTime(cycles[leg].liftoffTime+cycles[leg].stanceTime)
							].footBase
						);
						
						s.footBaseNormalized = (s.footBaseNormalized-reference);
						if (cycles[leg].cycleDirection!=Vector3.zero) {
							s.footBaseNormalized = Quaternion.Inverse(
								Quaternion.LookRotation(cycles[leg].cycleDirection)
							) * s.footBaseNormalized;
						}
						
						s.footBaseNormalized.z /= cycles[leg].cycleDistance;
						if (time<=cycles[leg].liftoffTime) { s.footBaseNormalized.z = 0; }
						if (time>=cycles[leg].strikeTime) { s.footBaseNormalized.z = 1; }
						
						s.footBaseNormalized.y = s.footBase.y - legC.groundPlaneHeight;
					}
					else {
						// Calculate normalized foot flight path
						// based on the cycle distance of the whole motion
						// (the calculated average cycle distance)
						Vector3 reference = (
							-m_cycleDistance * m_cycleDirection * (time-cycles[leg].liftoffTime*0)
							// FIXME: Is same as stance position:
							+cycles[leg].samples[
								GetIndexFromTime(cycles[leg].liftoffTime*0+cycles[leg].stanceTime)
							].footBase
						);
						
						s.footBaseNormalized = (s.footBaseNormalized-reference);
						if (cycles[leg].cycleDirection!=Vector3.zero) {
							s.footBaseNormalized = Quaternion.Inverse(
								Quaternion.LookRotation(m_cycleDirection)
							) * s.footBaseNormalized;
						}
						
						s.footBaseNormalized.z /= m_cycleDistance;
						
						s.footBaseNormalized.y = s.footBase.y - legC.groundPlaneHeight;
					}
				}
				//cycles[leg].samples[cycles[leg].stanceIndex].footBaseNormalized.z = 0;
				cycles[leg].samples[samples] = cycles[leg].samples[0];
			}
			else {
				for (int j=0; j<samples; j++) {
					int i = Util.Mod(j+cycles[leg].stanceIndex,samples);
					LegCycleSample s = cycles[leg].samples[i];
					s.footBaseNormalized = s.footBase - cycles[leg].stancePosition;
				}
			}
		}
		
		for (int leg=0; leg<legs; leg++) {
			float heelToeZDist = Vector3.Dot(cycles[leg].heelToetipVector,cycleDirection);
			for (int i=0; i<samples; i++) {
				LegCycleSample s = cycles[leg].samples[i];
				float zVal = Vector3.Dot(s.footBase, cycleDirection);
				if (zVal < graphMin.z) graphMin.z = zVal;
				if (zVal > graphMax.z) graphMax.z = zVal;
				if (zVal+heelToeZDist < graphMin.z) graphMin.z = zVal+heelToeZDist;
				if (zVal+heelToeZDist > graphMax.z) graphMax.z = zVal+heelToeZDist;
			}
		}
		graphMin.y = legC.groundPlaneHeight;
	}