Given an arbitrary spline (with only points that are CurveCustomTangent), place spline meshes continuously across the entire spline with even UVs distributed across the length.
Problems
A. Using Get Tangent At Distance Along Spline produces poor results, causing the meshes to not stay along the spline (see image below).
B. Using Get Point At Distance Along Spline is not uniform if the spline points are bunched. (edit: not true; see answer for details)
Details
I’ve created this Blueprint to subdivide a spline into Segment number of Spline Mesh Components:
When I subdivide my spline into many segments I get “elbows” in the middles, not aligned with the spline:
If my spline points are not already evenly-distributed in space, the Get Point At Distance Along Spline gives me non-uniform spacing of the points. (edit: not true; the points ARE evenly spaced, I just did not see it due to tangents; see the answer for details) Here’s a simple linear spline, whose tangents are all very short (1 unit, just long enough to ensure that the rotation is known). Notice how the pipes are not evenly distributed along the length, shrinking and growing in size:
Here I’ve taken a top-down screenshot of a planar spline in UE4 (seen in red) and overlaid upon it a cubic Bézier path in Photoshop (seen in blue), aligning the tangent handles with the positions in UE4. As you can see the two paths are not even close to being the same.
Based on the answer by @Benergy on this question, I tried manually scaling the tangent lengths in Photoshop down by exactly 1/3. The result is a spline that does match what UE4 is producing.
So…UE4 is (for no explainable reason; bug?) using tangents that are way too long, and then dividing them by 3 during some computation. If I also scale the tangent vectors returned by Get Tangent at Distance Along Spline down by 1/3, I get much better results, causing my spline mesh components to stick to the spline:
As seen in the comparison, at a large amount of subdivision it seems like dividing by even more (4, in this case) works better, while at a low amount of subdivision dividing the tangent lengths by lower numbers (1-2) works better.
This seems to solve the first problem I was having, but has no effect on the ~wrong positions returned by Get Point at Distance Along Spline.
I agree, this needs to be fixed. I think the inaccuracy is caused by the so called input keys, that approximate the spline.
Can a staff member please have a look at this? It really ruins the usability of the splines.
The issue UE-27979 has been marked as cannot reproduce, but clearly people can reproduce it.
As I’m looking into this more, I’m increasingly convinced that UE-27979 might be fine, and it’s justGet Tangent At Distance Along Spline that’s the culprit. I can’t exactly reproduce the bad spacing I was having before, but I am finding that the tangents are bad, and might have just been covered up in part in my screenshot. I’m going to be posting an update comment or answer on here, and maybe filing a new bug, in a few hours.
Here’s a teaser screenshot from my further investigations; the far pipe has the tangents returned from Get Tangent At Distance Along Spline; the near pipe has ‘fixed’ tangents.
The Get Location At Distance Along Spline will affect the ends of your mesh and it will stretch it in some cases. Depending on your mesh, it may or may not be noticeable.
Here’s a video where I demonstrate the location problem: https://youtu.be/HMSg7qX_gGw . I will post it on the other answer, as well.
Note: You must set the Input Key for each spline point to its zero-based index for this answer to work.
It looks like Get Tangent At Distance Along Spline is the cause of both of these bugs. I thought (per my comment) I had solved it with a simple tangent*0.33 scaling:
meshes on left are squished, meshes on right are OK in middle, but one end is squashed
From this I decided to first normalize all the tangents, and then scale then uniformly. Here’s the blueprint I used to test out various scaling strategies (see final blueprint in comment below):
top-to-bottom: splines with tangents uniformly scaled to 10, 65, and 130 units
As you can see by zooming in, making the tangents too short causes the ends of the mesh to be squashed, while making them too long causes the middle of the mesh to be squashed (and may cause bulges to appear):
And finally, showing that it works generically, here is the same spline with 4, 8, 12, 16, and 20 meshes repeated along its length. The fourth spline has the actual spline points overlaid, showing that there are a variety of point spacings and tangents used in this test.
Thanks for sharing your solution!
Unfortunately, it my case, it won’t help. It works only when using the Spline Mesh Component. I’m simply moving a mesh along the spline and it’s still bugged.
I see now what you mean by Input Key causing problems. Here are two instances of the same Blueprint, using my answer to this question to evenly-space four spline meshes across three spline segments. The only difference is that the top one has Input Key values of 0, 1, 2, 3 for the four spline points, while the bottom one has the first Input Key set to 0.5.
If you set each Input Key value to the index of the spline point, Get Location At Distance Along Spline seems to work correctly. If not, it’s wacky. I can’t say for sure that it’s a bug, because maybe this is what “Input Key” is designed for: some way to weight spline points as percentages along the line (or something).
But how do you manage to set the input keys? Did you do it through C++?
In the blueprients functions for Spline I only see Find Input Key Closest to World Location and Get input Key at Distance Along Spline.
I wanted to play around with the input keys, but I don’t know how to modify them. Going into C++ seems too much of a hassle…
I haven’t looked for a Blueprint way to do it yet. Right now I’m just selecting the Spline component in the Details pane, and for each selected point adjusting it in the Details pane:
The Make Spline Point function takes an Input Key parameter. However the only functions that use a Spline Point Structure are “Add Point” and “Add Points” (taking an array), and these appear to only add to the end of the Spline Point list. As such, it looks like the only way to use Blueprint to set Input Key is to loop through the spline points by index, and create new SplinePoint structures from them, then Clear Spline Points, and then Add Points.
I didn’t know about those because I always manipulated the spline through blueprints. The input key is yet another property that cannot be modified through blueprints. It’s not even explained what an input key is. How are we supposed to know how to use it? The Spline is a great component that is poorly executed.
Thanks again for the information. I really appreciate that you posted this info for everyone to see.
PS: There are more bugs awaiting if you count on using splines further. You’ll start seing them if you want to do loops. Here’s one: Spline tangent problem - Rendering - Unreal Engine Forums
I’m referring to available Blueprint function nodes, not C++. See attached (where “Make Smooth Tangents” is my own function). I share your frustration at the lack of documentation on what Input Key is for, and what it is—and is not—supposed to impact. Based on its behavior, I’m feeling pretty sure that it’s a way to remap the percent-through-the-spline per index.
I understand, but aren’t you modifying the tangents in the process in order to be compatible with the keys? Is there a relation between the two? I see that you’re doing something to smooth the tangents. How exactly are you smoothing them?
Ah, no. The Input Keys and Tangents are unrelated. The input keys just have to be set to match the integer index of the spline point to get useful results. My tangent calculations are just because I have a polyline (points only) that I’m trying to make a smooth path from. In my case I’m calculating the tangents by finding the vector between adjacent points, and then scaling it to the length of that segment. (Normally I’d scale by 1/3 of the length, but Unreal wants tangents 3x longer than traditional Bézier math calls for.)
For completeness, here’s that function (with edge case tests to handle the first and last points specially):