I'm making a rollercoaster and I'm having trouble figuring out the tracks up and side vectors from the track tangent. I have a series nodes with roll values and points that make up the track. Now, I want to keep the track upright as much as possible so it doesn't start to roll around corners but at the same time allow for the node roll values to make loops. No matter what I do, I get twists and bends when the loop goes up and starts to bend back around.
This is the code I have now that works okay apart from loops. I'm at a dead end with this, I just can't figure out a way to keep the track upright but still allow for loops. I know it's possible - I just don't know the maths to do it. My requirement is that there can't be any other data the user needs to give - just the node positions and roll values at each node. I'm using bezier curves if that helps.
m_trackLength = 0.0f;
const Vector3f up(0.0f, 1.0f, 0.0f);
size_t segmentIndex = 0;
size_t segmentPointIndex = 0;
for (unsigned int i = 0; i < m_points.size(); ++i)
{
Point& point = m_points[i];
Vector3f trackDelta;
size_t rollIndex;
size_t nextRollIndex;
float rollPercentage;
if (i < m_points.size() - 1)
{
trackDelta = m_points[i + 1].position - point.position;
size_t segmentPointCount = m_segments[segmentIndex].pointCount;
rollIndex = segmentIndex;
nextRollIndex = rollIndex + 1;
rollPercentage = (float)segmentPointIndex / ((float)segmentPointCount - 1);
++segmentPointIndex;
if (segmentPointIndex >= (segmentPointCount - 1))
{
++segmentIndex;
segmentPointIndex = 0;
}
}
else
{
trackDelta = m_points[1].position - point.position;
rollIndex = m_nodes.size() - 1;
nextRollIndex = 0;
rollPercentage = 1.0f;
}
m_trackLength += trackDelta.Length();
point.tangent = trackDelta.Normalise();
float firstNodeRoll = m_nodes[rollIndex].GetRoll();
float nextNodeRoll = m_nodes[((rollIndex < (m_nodes.size() - 1)) ? nextRollIndex : 0)].GetRoll();
float pointRoll = Math::RadiansToDegrees(nextNodeRoll - firstNodeRoll);
pointRoll -= floor(pointRoll / 360.0f) * 360.0f;
if (pointRoll >= 270.0f)
{
pointRoll -= 360.0f;
}
else if (pointRoll <= -270.0f)
{
pointRoll += 360.0f;
}
pointRoll = Math::DegreesToRadians(pointRoll);
pointRoll = firstNodeRoll + Util::Interpolate(0.0f, pointRoll, rollPercentage);
point.normal = up;
point.normal.Rotate(-pointRoll, point.tangent);
point.binormal = point.tangent.Cross(point.normal).Normalise();
point.normal = point.binormal.Cross(point.tangent).Normalise();
}
And here's a picture of the problem:
I've heard about "Parallel Transport Frames" and have tried implementing them but all it seems to do is make the track roll around corners - something I don't want to happen. Maybe I'm just doing it wrong?