Access landscape spline data from C++

We have implemented roads on our landscape using landscape spines. I would like to animate a car moving along one of these splines by doing a very simple interpolation between spline points.

I have successfully implemented this before using the non-landscape USplineComponent, by using functions like GetLocationAtSplineInputKey().

I would like to do something similar with landscape splines, but can’t find any similar functions in ULandscapeSplineSegment or ULandscapeSplinesComponent. Also, I am unable to access the Segments member of Landscape->SplineComponent as it is marked protected.

Is there anything I can do to achieve this, short of modifying Engine code?

1 Like

For anyone who sees this in the future, I ended up using a TObjectIterator to find the landscape spline segments and stored them in BeginPlay():

TArray< TWeakObjectPtr<ULandscapeSplineSegment> > Segments;
for (TObjectIterator<ULandscapeSplineSegment> Itr; Itr; ++Itr)
{
	Segments.Add(TWeakObjectPtr<ULandscapeSplineSegment>(*Itr));
}
3 Likes

I have stumbled upon the same exact problem. Why is there no way to access the spline segments of a given Landscape?

Yeah unfortunately most of the information is hidden in protected and private member variables.
While it’s not pretty or particularly efficient, the code I posted below should work for you though. Let me know if you have further issues

These don’t need to be TWeakObjPtrs, but I was using level streaming so the splines references could become invalid if the player crosses to a different map.

In fact it turns out I was too tired to notice what I was trying to access were USplineMeshComponents… I just had to get them all from the landscape actor. So our problems might not be related. Anyway I think there might be a problem with the splines collision in UE4 though. To make it short, once you enable spline collisions in the spline editor, it seems like all the collisions filters I set up on the spline mesh are completely ignored once I run the simulation ( I don’t know if I’m very clear… ). I have to enforce them manually in the code for some reason. Might make a thread about it but I don’t have much time right now… Thank you for your time anyway.

I’m using your code and it works fine except for the one thing. It returns each segments twice. If I print segments names there are always segments with and without PIE prefix. Did you have the same issue?

1 Like

I’m trying to get access to the Landscape instance, but I’m not sure what method to call.

Thank you SO MUCH for sharing this. I have looked everywhere and couldn’t figure out how to access the control points or segments of a landscape spline. Could you help explaining how the code works? I can get the reference to the Landscape actor, but unfortunately all of my years in easy-bake-oven Javascript land can’t figure out how to implement your above code segment. To be specific, I don’t see where you are referencing the landscape reference to draw the segments from. Cheers!

edit: After poking my head through the engine code for segments and control points, I actually couldn’t find the info that would directly translate to creating a point in a blueprint spline. Specifically, I couldn’t find the arrive and leave tangents. How did you figure out your solution? I am trying to do the same as you - have an actor follow a spline mirroring a landscape spline.

Hi jeevcat.

Could you give me a little help with this?
How do I get the location from those segments?
Thanks

I know this is an old post, but sadly still seems to be the only way to get the spline segments at runtime (without changing the engine source to make Segments public or with an accessor per this post: https://www.reddit.com/r/unrealengine/comments/snl34m/how_to_access_landscape_splines_in_unreal_for/

One additional thing to keep in mind is you should check the UWorld instance that the segments are a part of because you may get “duplicates” when playing in the editor (the play session and the editor map itself) per these guidelines for TObjectIterator:

In the for loop, add this filter:

//World Check
if(Itr->GetWorld() != GetWorld())
{
  continue;
}