Exemplo n.º 1
0
void USplineComponent::UpdateSpline()
{
	const int32 NumPoints = SplineInfo.Points.Num();
	check(!bClosedLoop || NumPoints == 0 || (NumPoints >= 2 && SplineInfo.Points[0].OutVal == SplineInfo.Points[NumPoints - 1].OutVal));

	// Automatically set the tangents on any CurveAuto keys
	SplineInfo.AutoSetTangents(0.0f, bStationaryEndpoints);

	// Nothing else to do if less than 2 points
	if (NumPoints < 2)
	{
		return;
	}

	// Adjust auto tangents for first and last keys to take into account the looping
	if (bClosedLoop)
	{
		auto& FirstPoint = SplineInfo.Points[0];
		auto& LastPoint = SplineInfo.Points[NumPoints - 1];
		const auto& SecondPoint = SplineInfo.Points[1];
		const auto& PenultimatePoint = SplineInfo.Points[NumPoints - 2];

		if (FirstPoint.InterpMode == CIM_CurveAuto || FirstPoint.InterpMode == CIM_CurveAutoClamped)
		{
			FVector Tangent;
			ComputeCurveTangent(
				PenultimatePoint.InVal - LastPoint.InVal, PenultimatePoint.OutVal,
				FirstPoint.InVal, FirstPoint.OutVal,
				SecondPoint.InVal, SecondPoint.OutVal,
				0.0f,
				FirstPoint.InterpMode == CIM_CurveAutoClamped,
				Tangent);

			FirstPoint.LeaveTangent = Tangent;
			FirstPoint.ArriveTangent = Tangent;
			LastPoint.LeaveTangent = Tangent;
			LastPoint.ArriveTangent = Tangent;
		}
	}

	const int32 NumSegments = NumPoints - 1;

	// Start by clearing it
	SplineReparamTable.Points.Reset(NumSegments * ReparamStepsPerSegment + 1);
	float AccumulatedLength = 0.0f;
	for (int32 SegmentIndex = 0; SegmentIndex < NumSegments; ++SegmentIndex)
	{
		for (int32 Step = 0; Step < ReparamStepsPerSegment; ++Step)
		{
			const float Param = static_cast<float>(Step) / ReparamStepsPerSegment;
			const float SegmentLength = (Step == 0) ? 0.0f : GetSegmentLength(SegmentIndex, Param);
			SplineReparamTable.AddPoint(SegmentLength + AccumulatedLength, SegmentIndex + Param);
		}
		AccumulatedLength += GetSegmentLength(SegmentIndex, 1.0f);
	}
	SplineReparamTable.AddPoint(AccumulatedLength, static_cast<float>(NumSegments));
}
Exemplo n.º 2
0
void FRichCurve::AutoSetTangents(float Tension)
{
	// Iterate over all points in this InterpCurve
	for(int32 KeyIndex=0; KeyIndex<Keys.Num(); KeyIndex++)
	{
		FRichCurveKey& Key =  Keys[KeyIndex];
		float ArriveTangent = Key.ArriveTangent;
		float LeaveTangent  = Key.LeaveTangent;

		if(KeyIndex == 0)
		{
			if(KeyIndex < Keys.Num()-1) // Start point
			{
				// If first section is not a curve, or is a curve and first point has manual tangent setting.
				if( Key.TangentMode == RCTM_Auto )
				{
					LeaveTangent = 0.0f;
				}
			}
		}
		else
		{
			
			if(KeyIndex < Keys.Num()-1) // Inner point
			{
				FRichCurveKey& PrevKey =  Keys[KeyIndex-1];

				if( Key.InterpMode == RCIM_Cubic && (Key.TangentMode == RCTM_Auto ))
				{
						FRichCurveKey& NextKey =  Keys[KeyIndex+1];
						ComputeCurveTangent(
							Keys[ KeyIndex - 1 ].Time,		// Previous time
							Keys[ KeyIndex - 1 ].Value,	// Previous point
							Keys[ KeyIndex ].Time,			// Current time
							Keys[ KeyIndex ].Value,		// Current point
							Keys[ KeyIndex + 1 ].Time,		// Next time
							Keys[ KeyIndex + 1 ].Value,	// Next point
							Tension,							// Tension
							false,						// Want clamping?
							ArriveTangent );					// Out

						// In 'auto' mode, arrive and leave tangents are always the same
						LeaveTangent = ArriveTangent;
				}
				else if( PrevKey.InterpMode == RCIM_Constant || Key.InterpMode == RCIM_Constant )
				{
					if(Keys[ KeyIndex - 1 ].InterpMode != RCIM_Cubic)
					{
						ArriveTangent = 0.0f;
					}
					LeaveTangent  = 0.0f;
				}
				
			}
			else // End point
			{
				// If last section is not a curve, or is a curve and final point has manual tangent setting.
				if( Key.InterpMode == RCIM_Cubic && Key.TangentMode == RCTM_Auto)
				{
					ArriveTangent = 0.0f;
				}
			}
		}

		Key.ArriveTangent = ArriveTangent;
		Key.LeaveTangent = LeaveTangent;
	}
}