• News

• Industries

• Learning & Support

• Community

• Marketplace

# Get Right Vector of Spline Component Segment

Hello all! I’m working on a brand new mode for the community and I’ve got the base part of it working (rendering the mesh along the spline):

The problem is that as I extend move it more to the right or left, it gets weird:

I already know what the problem is:

``````

FVector extendDir = FVector(0, width, 0);

one.Vertex0.Position = v0;
one.Vertex1.Position = v0 + extendDir;
one.Vertex2.Position = v2;

two.Vertex0.Position = one.Vertex2.Position + extendDir;
two.Vertex1.Position = one.Vertex2.Position;
two.Vertex2.Position = one.Vertex1.Position;

``````

It is because I’m extending it on the Y-axis. I did it intentionally for testing purposes. Now that I know that the mesh renders alright, the next thing on my list is to get the right vector of a segment on the spline component so I can extend the mesh in that direction. That way, it will never get squished like that and the width of the mesh will stay constant throughout the whole thing. How would I do this? Is it possible? I’ve been trying to do this all day. And I cannot use the point’s rotation because it has not been rotated, I just moved it. Is there a way to calculate this using the first point and connected point or something? Thanks!

If you want to get the right vector of the spline and are fine with restricting yourself to horizontal splines, you can just get the forward vector of the spline at any point, and cross-product it with the world Up vector to get a rotation transform. See FRotationMatrix::MakeFromXZ (C++) or MakeRotFromXZ (blueprint function).

However, if you want full 3D control over a spline’s orientation, and would like that to propagate to a spline mesh (eg. allowing construction of rollercoasters with loops, corkscrews etc.) then you’re out of luck unless you’re ready to dive into C++.

I’m currently working on a modified version of SplineComponent that tracks orientation (stored as a quaternion) as well as the spline position. This means at any point on the spline you can get a transform, not just a position. This information can then be passed to SplineMeshComponent to make cool stuff like corkscrews, loops etc. As part of this I’ve had to modify the spline component visualizer to show orientation + width info at each spline point. I’ve also made the scale tool work on separate axes, so the X axis controls the spline tangents and Y axis controls the spline “width” (which can be passed along to SplineMeshComponents for wider/thinner segments, eg. a race track). Unfortunately it’s required quite a few low-level engine changes to get working, so it won’t be the easiest thing to share. I’ll probably do a dev blog post on it once it’s complete though, and if there’s enough interest I can post the code changes.

Like this?

``````
FRotator centerRotation = Path->GetWorldRotationAtDistanceAlongSpline(Path->GetDistanceAlongSplineAtSplinePoint(i) + (segmentLength * s) + (segmentLength / 2));

FVector extendDir = (FVector::CrossProduct(centerRotation.Vector().ForwardVector, FVector::UpVector) * width).GetAbs();

``````

I still won’t maintain it’s width. I created a post here, but I can’t get it to work the way he says to do it. And sounds good bro!

Hmm what’s the GetAbs() for? That returns a vector with the absolute value of each component.

This is probably the most straight-forward way of getting the different axes from a FRotator - nabbed from UAnimInstance::CalculateDirection():

``````

FRotator SomeRotator;
FMatrix RotMatrix = FRotationMatrix(SomeRotator);
FVector ForwardVector = RotMatrix.GetScaledAxis(EAxis::X);
FVector RightVector = RotMatrix.GetScaledAxis(EAxis::Y);

``````

Also here’s some shots of the road spline tool I mentioned:

Width support:

Rotation support using quaternions (so there’s no gimbal lock issues) - corkscrew:

Rotation support using quaternions (so there’s no gimbal lock issues) - loop:

I should mention this road spline tool I’m working on is based off dokipen’s awesome 4-part video tutorial. I’ve taken the base work he did and am extending it with C++ code changes to work around the current gimbal-lock issues and glitching when facing directly up/down or going upside down:

That looks awesome dude! I am now trying out GetScaledAxis. I will report back if I can get it working. Thanks for the help, I really appreciate it.

It now seems to maintain constant width, but because I’m getting the direction from the center point of each segment and extending it in that direction, I get this:

So now I need connect the vertices somehow I guess. Here is how I am calculating these positions:

``````

FCustomMeshTriangle one, two;

FVector v0 = GetTransform().InverseTransformPosition(Path->GetWorldLocationAtDistanceAlongSpline(Path->GetDistanceAlongSplineAtSplinePoint(i) + (segmentLength * s)));
FVector v2 = GetTransform().InverseTransformPosition(Path->GetWorldLocationAtDistanceAlongSpline(Path->GetDistanceAlongSplineAtSplinePoint(i) + (segmentLength * s) + segmentLength));

FRotator centerRotation = Path->GetWorldRotationAtDistanceAlongSpline(Path->GetDistanceAlongSplineAtSplinePoint(i) + (segmentLength * s) + (segmentLength / 2));

FVector extendDir = FRotationMatrix(centerRotation).GetScaledAxis(EAxis::Y) * width;

switch (PositioningMode) {

case EWaterPositioningMode::WPM_Center:
{
one.Vertex0.Position = v0 - extendDir;
one.Vertex1.Position = v0 + extendDir;
one.Vertex2.Position = v2 - extendDir;

two.Vertex0.Position = v2 + extendDir;
two.Vertex1.Position = one.Vertex2.Position;
two.Vertex2.Position = one.Vertex1.Position;

break;
}

case EWaterPositioningMode::WPM_Left:
{
one.Vertex0.Position = v0;
one.Vertex1.Position = v0 + (extendDir * 2);
one.Vertex2.Position = v2;

two.Vertex0.Position = one.Vertex2.Position + (extendDir * 2);
two.Vertex1.Position = one.Vertex2.Position;
two.Vertex2.Position = one.Vertex1.Position;

break;
}

}

``````

How do you think I should connect them? I was thinking of checking which point I’m on and if the point is not the first, get the last triangle and connect them. But I don’t know. The dude on gamedev.net in the post I mentioned above talked about this, but I couldn’t get it working. I’ll try my solution and see if how it turns out then report back here.

Tried it, it works alright. Don’t really like the result the tiny hack gives. Here’s what I just tried out:

``````

if (s == 0)
{
if (i == 0)
{
one.Vertex0.Position = v0 - extendDir;
one.Vertex1.Position = v0 + extendDir;
one.Vertex2.Position = v2 - extendDir;

two.Vertex0.Position = v2 + extendDir;
two.Vertex1.Position = one.Vertex2.Position;
two.Vertex2.Position = one.Vertex1.Position;
}
else
{
one.Vertex0.Position = lastTri.Vertex1.Position;
one.Vertex1.Position = lastTri.Vertex0.Position;
one.Vertex2.Position = v2 - extendDir;

two.Vertex0.Position = v2 + extendDir;
two.Vertex1.Position = one.Vertex2.Position;
two.Vertex2.Position = one.Vertex1.Position;
}
}
else
{
one.Vertex0.Position = lastTri.Vertex1.Position;
one.Vertex1.Position = lastTri.Vertex0.Position;
one.Vertex2.Position = v2 - extendDir;

two.Vertex0.Position = v2 + extendDir;
two.Vertex1.Position = one.Vertex2.Position;
two.Vertex2.Position = one.Vertex1.Position;
}

break;

``````

But it doesn’t look too good. Have a better way of calculating the vertices? The mesh no longer looks smooth like it was before. I can see the triangles. How are you calculating the vertices?

Bump lol

You’re using SplineMeshComponents yeah? From your screenshots it looks like it’s not deforming them along the spline tangents properly. It’s best to work with a surface that has a higher number of vertices than the one you’ve got so it’ll deform more evenly - look for SM_Template_Map_Floor in engine content for a 4x4 subdivided plane. I’d also check that you’re scaling the surface start/end tangents enough - dokipen’s road spline tutorial videos that I linked above show how to do this in blueprint. Lemme know if that doesn’t work out, but those shots look like what I see if I don’t set the spline mesh component tangents properly.

Hey! Thanks for the reply. I’m not using SplineMeshComponents. I’m using one spline component to determine the path, then I create a custom mesh from the points using UCustomMeshComponent. I also can change how much each part between two points is subdivided. But I’ll check it out. Also, I’m going to look at Dokipen’s videos to see how he does it. Thanks!

Ah I see - I haven’t played around with CustomMeshComponent yet. But for the task of stretching a mesh over a spline, SplineMeshComponents are pretty well suited. Hence the name I guess.