Okay, made some progress. Finally got the particles to follow correctly, the issue now is the strength of the Tangents themselves. Below, you can see the current state of the code and the orbit lines. In circular orbits this works pretty well, but for eccentric/elliptical orbits it’s not working so well, I know exactly why, but figuring out the calculation is the hard part.
The above is created using the following code. Note that the ‘GetRolloverArrayIndex’ is just a way to make the array loop back on itself if I give it a number outside of the array bounds, both forwards and backwards. This allows me to join the start and end segments and keep the smoothing.
void UGESGameplayStatics::SetTLEParticleSplinePoints(TArray<FVector>& InSplinePoints, UParticleSystemComponent* InputPS)
{
/* Get amount of entries in the Array, Subtract 1 so we get a full loop */
uint32 AmountOfPoints = InSplinePoints.Num();
/* Calculate the Start & End Point for each segment of the spline, and it's tangent for smooth interpolation */
for (uint32 i = 0; i <= (AmountOfPoints - 1); i++)
{
/* Start Location is always * in the array, Target point is 1 > that */
InputPS->SetBeamSourcePoint(0, InSplinePoints*, i);
InputPS->SetBeamTargetPoint(0, InSplinePoints[GetRolloverArrayIndex(AmountOfPoints, i + 1)], i);
/* Calculate The Tangents. Effectively Source(B) = C - A, Target(B) = D - B. */
FVector NewSourceTangent = FVector(InSplinePoints[GetRolloverArrayIndex(AmountOfPoints, i + 1)] - InSplinePoints[GetRolloverArrayIndex(AmountOfPoints, i - 1)]);
FVector NewTargetTangent = FVector(InSplinePoints[GetRolloverArrayIndex(AmountOfPoints, i + 2)] - InSplinePoints*);
InputPS->SetBeamSourceTangent(0, FVector(NewSourceTangent) / 2.0f, i);
InputPS->SetBeamTargetTangent(0, FVector(NewTargetTangent) / 2.0f, i);
}
}
uint32 UGESGameplayStatics::GetRolloverArrayIndex(uint32 InArraySize, uint32 InArrayIndex)
{
if (InArrayIndex >= 0)
{
return InArrayIndex % InArraySize;
}
else
{
uint32 NewIndex = (InArrayIndex + InArraySize) % InArraySize;
while (NewIndex < 0)
{
NewIndex += InArraySize;
}
return NewIndex;
}
}
The important part is where I divide the tangents by two before feeding them in. Not doing this causes the lines to be fairly straight, but they curve close to the point. Normalizing the tangents is not the right way to go, as we use the size of the tangent as it’s strength (which I didn’t realise until today). Unfortunately they don’t seem to be completely proportional to anything so I don’t get the correct curve on elliptical orbits.
So, this is what I tried instead, which again gets me closer, but still not quite there. All it does it calculate the distance to the next point, and scales the tangent by that amount (after normalizing it).
void UGESGameplayStatics::SetTLEParticleSplinePoints(TArray<FVector>& InSplinePoints, UParticleSystemComponent* InputPS)
{
/* Get amount of entries in the Array, Subtract 1 so we get a full loop */
uint32 AmountOfPoints = InSplinePoints.Num();
/* Calculate the Start & End Point for each segment of the spline, and it's tangent for smooth interpolation */
for (uint32 i = 0; i <= (AmountOfPoints - 1); i++)
{
/* Start Location is always * in the array, Target point is 1 > that */
InputPS->SetBeamSourcePoint(0, InSplinePoints*, i);
InputPS->SetBeamTargetPoint(0, InSplinePoints[GetRolloverArrayIndex(AmountOfPoints, i + 1)], i);
/* Calculate The Tangents. Effectively Source(B) = C - A, Target(B) = D - B. */
FVector NewSourceTangent = FVector(InSplinePoints[GetRolloverArrayIndex(AmountOfPoints, i + 1)] - InSplinePoints[GetRolloverArrayIndex(AmountOfPoints, i - 1)]);
FVector NewTargetTangent = FVector(InSplinePoints[GetRolloverArrayIndex(AmountOfPoints, i + 2)] - InSplinePoints*);
/* Calculate The Distance To The Next Point In The Spline - use this to scale the tangents */
float TangentStrength = FVector(InSplinePoints* - InSplinePoints[GetRolloverArrayIndex(AmountOfPoints, i + 1)]).Size();
/* Calculate the strength of the Tangent */
NewSourceTangent.Normalize();
NewTargetTangent.Normalize();
NewSourceTangent *= TangentStrength;
NewTargetTangent *= TangentStrength;
InputPS->SetBeamSourceTangent(0, FVector(NewSourceTangent), i);
InputPS->SetBeamTargetTangent(0, FVector(NewTargetTangent), i);
}
}
Again, elliptical orbits seem to suffer the most. Essentially what I have is a situation like the image below, but what I want to do is figure out how strong the tangents should be for each point, and I’ll get my smooth interpolated curve. The image below is a simple plot of Bezier curves using this website: HTML5 Canvas bezierCurveTo generator
I think a contributing factor to why the problem occurs because the distance between the spline points is NOT equal. We divide the orbit into segments based on time, and the further away you are, the longer it takes to go around the Earth so the more dense the points. On the above elliptical orbit, there are only two points close to the Earth, above and below.
So, imagine I have a scenario like below. What I need to do is calculate how long those arms need to be, in order to make the curve completely smooth. I feel like this is something I should be doing a Masters thesis in…