Example #1
0
float FRichCurve::Eval(float InTime, float DefaultValue) const
{
	// Remap time if extrapolation is present and compute offset value to use if cycling 
	float CycleValueOffset = 0;
	RemapTimeValue(InTime, CycleValueOffset);

	const int32 NumKeys = Keys.Num();
	float InterpVal = DefaultValue;

	if (NumKeys == 0)
	{
		// If no keys in curve, return the Default value we passed in.
		InterpVal = DefaultValue;
	} 
	else if (NumKeys < 2 || (InTime <= Keys[0].Time))
	{
		if (PreInfinityExtrap == RCCE_Linear && NumKeys > 1)
		{
			float DT = Keys[1].Time - Keys[0].Time;
			
			if (FMath::IsNearlyZero(DT))
			{
				InterpVal = Keys[0].Value;
			}
			else
			{
				float DV = Keys[1].Value - Keys[0].Value;
				float Slope = DV / DT;
				InterpVal = Slope * (InTime - Keys[0].Time) + Keys[0].Value;
			}
		}
		else
		{
			// Otherwise if constant or in a cycle or oscillate, always use the first key value
			InterpVal = Keys[0].Value;
		}
	}
	else if (InTime < Keys[NumKeys - 1].Time)
	{
		// perform a lower bound to get the second of the interpolation nodes
		int32 first = 1;
		int32 last = NumKeys - 1;
		int32 count = last - first;

		while (count > 0)
		{
			int32 step = count / 2;
			int32 middle = first + step;

			if (InTime > Keys[middle].Time)
			{
				first = middle + 1;
				count -= step + 1;
			}
			else
			{
				count = step;
			}
		}

		int32 InterpNode = first;
		const float Diff = Keys[InterpNode].Time - Keys[InterpNode - 1].Time;

		if (Diff > 0.f && Keys[InterpNode - 1].InterpMode != RCIM_Constant)
		{
			const float Alpha = (InTime - Keys[InterpNode - 1].Time) / Diff;
			const float P0 = Keys[InterpNode - 1].Value;
			const float P3 = Keys[InterpNode].Value;

			if (Keys[InterpNode - 1].InterpMode == RCIM_Linear)
			{
				InterpVal = FMath::Lerp(P0, P3, Alpha);
			}
			else
			{
				const float OneThird = 1.0f / 3.0f;
				const float P1 = P0 + (Keys[InterpNode - 1].LeaveTangent * Diff*OneThird);
				const float P2 = P3 - (Keys[InterpNode].ArriveTangent * Diff*OneThird);

				InterpVal = BezierInterp(P0, P1, P2, P3, Alpha);
			}
		}
		else
		{
			InterpVal = Keys[InterpNode - 1].Value;
		}
	}
	else
	{
		if (PostInfinityExtrap == RCCE_Linear)
		{
			float DT = Keys[NumKeys - 2].Time - Keys[NumKeys - 1].Time;
			
			if (FMath::IsNearlyZero(DT))
			{
				InterpVal = Keys[NumKeys - 1].Value;
			}
			else
			{
				float DV = Keys[NumKeys - 2].Value - Keys[NumKeys - 1].Value;
				float Slope = DV / DT;
				InterpVal = Slope * (InTime - Keys[NumKeys - 1].Time) + Keys[NumKeys - 1].Value;
			}
		}
		else
		{
			// Otherwise if constant or in a cycle or oscillate, always use the last key value
			InterpVal = Keys[NumKeys - 1].Value;
		}
	}

	return InterpVal+CycleValueOffset;
}
Example #2
0
float FRichCurve::Eval(const float InTime, float DefaultValue) const
{
	const int32 NumKeys = Keys.Num();
	float InterpVal = DefaultValue;

	if (NumKeys == 0)
	{
		// If no keys in curve, return the Default value we passed in.
		InterpVal = DefaultValue;
	} 
	else if (NumKeys < 2 || (InTime <= Keys[0].Time))
	{
		// If only one point, or before the first point in the curve, return the first points value.
		InterpVal = Keys[0].Value;
	}
	else if (InTime < Keys[NumKeys - 1].Time)
	{
		// perform a lower bound to get the second of the interpolation nodes
		int32 first = 1;
		int32 last = NumKeys - 1;
		int32 count = last - first;

		while (count > 0)
		{
			int32 step = count / 2;
			int32 middle = first + step;

			if (InTime > Keys[middle].Time)
			{
				first = middle + 1;
				count -= step + 1;
			}
			else
			{
				count = step;
			}
		}

		int32 InterpNode = first;
		const float Diff = Keys[InterpNode].Time - Keys[InterpNode - 1].Time;

		if (Diff > 0.f && Keys[InterpNode - 1].InterpMode != RCIM_Constant)
		{
			const float Alpha = (InTime - Keys[InterpNode - 1].Time) / Diff;
			const float P0 = Keys[InterpNode - 1].Value;
			const float P3 = Keys[InterpNode].Value;

			if (Keys[InterpNode - 1].InterpMode == RCIM_Linear)
			{
				InterpVal = FMath::Lerp(P0, P3, Alpha);
			}
			else
			{
				const float OneThird = 1.0f / 3.0f;
				const float P1 = P0 + (Keys[InterpNode - 1].LeaveTangent * Diff*OneThird);
				const float P2 = P3 - (Keys[InterpNode].ArriveTangent * Diff*OneThird);

				InterpVal = BezierInterp(P0, P1, P2, P3, Alpha);
			}
		}
		else
		{
			InterpVal = Keys[InterpNode - 1].Value;
		}
	}
	else
	{
		// If beyond the last point in the curve, return its value.
		InterpVal = Keys[NumKeys - 1].Value;
	}

	return InterpVal;
}