Unity Splines

Yes indeed, the up vector evaluation is expensive as we are using a Frenet frame computation to compute these.
We are currently trying to think of a better way using caching to do that, but you are right, we should also update the doc accordingly while it’s not the case! Thanks for pointing this out!

1 Like

Hi @soleron ! Have you checked our samples ?
In the package manager, and the samples table, you can download a unch or samples that should help you to work with some basic use cases like generate a road, move a car along it. Use of the built-in components: SplineAnimate, SplineExtrude and SplineInstantiate. Distance computation between a spline and a 3D point. Use of spline paths to connect different splines together… and else! :slight_smile:

Other than that there is currently no official tutorials on the web to use splines…
You can find some beginning of explanations on the use of splines in the second half of this video from @gabrielw_unity :

https://www.youtube.com/watch?v=BfNNAJ-JhrQ

Hope this help!

Cheers

9046141--1249618--upload_2023-5-30_10-25-17.jpg

Thanks for reaching out @ManuelRauber !
We are exposing public API for Spline handles and SplineTool in the next release 2.3.0 which should be happening in the 2 coming weeks :slight_smile: This is almost ready and available for you!

3 Likes

That sounds great! Thanks :slight_smile:

Another question @ThomasLopez

Do you also open “EditorSplinesUtility.ReverseFlow”?

I have the following scenario:

9046480--1249681--upload_2023-5-30_19-17-12.png

I build the level with multiple tiles.
Each tile has its own Spline.
Via some code I connect all tiles into a final spline.

That works well until the rotation of a tile leads to being reverse.
As you can see in the picture, the spline, starting from bottom left, flows to the right.
However, in the corner due to rotation of that tile, the flow is being reversed, which is wrong.

To solve that, I can select the corner tile in the editor, then a knot and finally select “Reverse Spline Flow”. After that, everything is correct.

It would be nice to do this in the code as well, but the said API (“EditorSplinesUtility.ReverseFlow”) is internal. Sure, I can copy it’s code but I prefer reusing heavy work due to some maths being involved.

Thanks!

1 Like

Hello. Splines have been working great for me until yesterday. Now instead of creating a single spline with knots when I click, it creates multiple splines that are not connected. Did I change a setting somewhere that I don’t know about? How can I return to clicking to add nodes?

This package really is a pleasure to use, big fan of the UX.

For a personal project I’ve prototyped some C^2 continuous splines that others might find useful:

2 Likes

Thanks for reaching out on that topic.
For now it was not planned to expose this but this is something that could be done indeed! I’ll have to check the reason why it has not been exposed cause I don’t remember.

On another thing, regarding your use case, did you take a look at our SplinePath sample?
SplinePath have been made for usecases like this: join multiple splines to define a global one composed of multiple splines segments. Maybe that could help you as well :slight_smile:

Have fun!

9066307--1254154--splinePath.gif

Hi @Crowsinger !
I didn’t see that case before… It seems like you are clicking to add a knot and pressing the Enter key after (enter allows to validate the current spline, stay in the tool and start drawing a new one). But if you don’t do that, this is strange.
Can you let us know the Unity and Splines versions you are using ? Thanks!

Hey there (and to keep you up to date @ManuelRauber )!
Splines 2.3.0 is now out :smile: The SplineTool API and handles are now public to make your own custom spline tools!
Can’t wait to see what you come up with!

1 Like

This is very cool work, Ohmnivore

2 Likes

I’m not seeing Splines 2.3 for Unity 2022.3.1f1 LTS as an update available in the Package Manger. Am I missing something? Was this update withdrawn?

So one thing that’s been bugging me for ages about the spline package and how it integrates with my code is that it thinks we care about splines. We don’t - users don’t care about splines, I don’t care about splines, what we care about is the path we are making in the terrain, the road, the way a camera or car might move down a path, etc. So the current workflow for editing, say, a road is:

  • Select the road from the hierarchy
  • Find the tool bar and select the game object and switch it to spline edit mode
  • Now you can see the spline, find the knot on it you want to edit
  • Make sure you select the knot and not the tangent
  • Move the knot

If you want to add a new knot, then you have additional steps to change into the add more, or SplineData edit mode, etc.

This is basically a lot of mode shifts, and makes the editing feel clunky. What I want is:

  • User selects knot on the road and moves it.

What this means:

  • The spline tool is set to always show the knots
  • There is no mode shifts involved, selecting a knot means you want to edit it, like any other object you’d edit in Unity

I want to edit the “road”, not the spline. I want to move the roads control points, not the splines. The spline is just the mathematical construct behind resolving these needs, not the need itself.

I also want the knots being created or edited to make sense within the context they are used. For instance, I don’t want my road to roll 45 degrees around the spline creating an impossible bank, I want it flat or within the parameters of what a normal road is. I could interpolate the data of the spline to disallow roll, but what I really want is to allow it, but only when the user wants it, not when they just click out a path and get it by accident.

What we’re currently experimenting with to combat this:

  • Drawing selectable knots over the spline’s control points ourselves
  • When the user selects the (fake) knot, we pass through to select the spline knot and putting the user into spline edit mode for that knot. This has the bonus of not accidentally selecting tangents.
  • When the user adjusts a knot (the actual spline one), we apply various post processing filters to it to prevent roll (which can be disabled)

What we run into issues with:

  • Various bits of the editing API being sealed or private
  • We’re essentially rewriting large parts of the editor framework
  • Eventually we might have to replace the whole thing if there are issues we can’t find a way around.
  • All this hoop jumping takes a lot of development time
  • I have already spent more time on trying to work around spline issues than it would have taken me to write a spline package for my needs.

When you extrapolate this out to other potential tools we find similar kinds of issues. If we were creating a camera path, we’d want to do that from the camera’s point of view, not from a spline in the scene so much. We’d want to avoid certain types of data in our spline (roll), or easily prevent things like crinkles in the spline path caused by tangent shifts. A small thing like that can have a huge affect on the experience but not be easily seen in the spline, and difficult to edit out.

So what I’d like to see:

  • Continue to open up the API so we’re not fighting with it.
  • Try to view the spline system as something we use for a greater reason, not for the sake of the spline, and build out ways to customize and filter the data easily for such things.
  • Extendable knot data. Ideally my splines never have roll unless the users want it, so they turn off “roll protection” on the knots they want to allow it for. (This might be able to be done with SplineData, but sounds like a synchronization nightmare).
  • Make it possible to easily reduce modality- I don’t want spline edit mode, add point mode, 4 spline data modes, etc. I want road editing mode, and camera path editing mode, etc. I want control over when data is drawn, so I can draw the knots at all times, but not the handles (maybe the pass through trick is right here, but some settings for what the spline draws when unselected or selected would be way simpler). I want to be able to get the user to whatever mode they need to be in from script instead of having to teach them 7 steps to get there.
3 Likes

After further reviewing of this topic. Looks like Curvy Splines 8 is the best unofficial option for Unity spline manipulation, even if there is an extra cost. Thanks Unity for the splines feature. We have that as a fallback for now. We are also looking forward to watching that package mature.

2 Likes

Hi @jbooth_1 ,
Thanks for the feedback here.
This is actually the direction we are trying to take!

In Splines 2.3.0 we exposed new API so that you can make your own tools and use spline handles as well directly in these tools.

Moreover, you should be able to use direct manip to directly move your knots around without adding them to the selection or change the roll :slight_smile: This is already existing in the package. Also, if you want to “Make sure you select the knot and not the tangent” then hide the tangents! There is an option for that in the visuals. (For direct manip and the visuals I add a gif to this post to demo that.)

Regarding your feedback, I understand that in your case you don’t want a roll, but lots of other usecases require that (roller coaster, spaceship trajectory… ), the good thing which is also a problem with splines is that they are used in so many different usecases that it’s hard to find a large common ground for all of the solutions, so yes, the idea is to build a base here that is extensible for your usecases. The base class ISpline is there for that. If you want to define a new kind of splines with no roll (or limit that one to 45 degrees), just extend that and you’ll be compatible with all the tooling from our package as well. Can’t wait to see what you make out of that :smile:

Also last point regarding the shifts between GameObjects and Spline mode. the classic Move, Rotate, Scale tools are only acting on game objects, so yes to manipulate knots, which are sub-objects contained in the spline, we are leveraging the Tool Context but this also adds extra steps. However, once in that context you can really focus your work on the splines and out of that context you ensure that you won’t mess up your knots/tangents. The knots addition require extra steps as it’s a different tool and could not be part of the MRS tools indeed. However, to fasten context switching, you can easily switch between GameObject Context and other contexts using shortcuts, there is 2 shortcuts you can use for that under:
Edit>Shortcuts>Tools>Enter GameObject Mode and Edit>Shortcuts>Tools>Cycle Tool Modes

Hope this helps!

9074746--1255705--splines-directmanip.gif

The package has not landed yet for 2022.3 but that should be coming soon (only available for 2023.1 and after for now).

However, before that, you should be able to get it in 2022.3 right now by getting the package by name9074770--1255714--upload_2023-6-12_10-17-5.png

1 Like

Any examples of this stuff being used yet? I’ve noticed a bunch of new API calls, but the docs are pretty thin on how these are supposed to be used.

So what I am doing now is just post processing out the roll when a spline is edited - as an option (users can turn it off on the cases where they want roll). This works well, but obviously the user can still attempt to roll the spline by rotating the knot. In an ideal world that wouldn’t be possible but this is good enough for now at least.

For direct manipulation, I’m using gizmo’s to draw my own control points:

static GizmoType splineEditMode = GizmoType.Pickable | GizmoType.Selected | GizmoType.Active | GizmoType.InSelectionHierarchy;

        [DrawGizmo(GizmoType.Active | GizmoType.Pickable | GizmoType.NonSelected | GizmoType.Selected)]
        static void RenderExtraGizmo(Road editorTarget, GizmoType gizmoType)
        {
            if ((gizmoType & GizmoType.Pickable) == GizmoType.Pickable || gizmoType == splineEditMode)
            {
                SelectSpline(editorTarget.splineContainer);
            }

            SplineContainer splineContainer = editorTarget.splineContainer;

            if (splineContainer == null)
                return;

            Color prevColor = Gizmos.color;
            Gizmos.color = new Color(0, 0, 1, 0.5f);
            foreach (Spline spline in splineContainer.Splines)
            {
                if (spline.Count > 0)
                {
                    for (int i = 1; i < spline.Count; ++i)
                    {
                        Gizmos.DrawSphere(splineContainer.transform.TransformPoint(spline[i].Position), 0.5f);
                    }

                }
            }
            Gizmos.color = prevColor;
        }

and when the user clicks on one, I do:

static void SelectSpline(SplineContainer spline)
        {
            if (spline != null)
            {
                Selection.activeGameObject = spline.gameObject;
                ActiveEditorTracker.sharedTracker.RebuildIfNecessary();
                ToolManager.SetActiveContext<SplineToolContext>();
                ToolManager.SetActiveTool<SplineMoveTool>();
                //EditorSplineUtility.SetKnotPlacementTool();
            }
        }

However, while this lets me click on the gizmo and get right into spline move mode, I can’t seem to get it to let me click on a different spline’s gizmo as it won’t trigger the click on the gizmo while in spline edit mode. And obviously I’d prefer better handling than this hack - being able to click-drag to go directly into add point mode and dragging out a new knot, for instance. Handles would give me that, but they don’t show up when the object is not selected. Is there something new in the 2.3 API that can help here?

Also, I would love the ability to shut off the users capability to create multiple splines in one spline container. In my current use case, there is no valid reason to do this, as splines should never intersect or share points but rather get constructed between game object based anchor points.

How can I get the normalized time of a given knot? I thought I could iterate over the knots/length like this:

float len = splinePath.GetLength();
float runningTotalLen = 0f;
for (int i = 0; i < splinePath.Count; i++)
{
       data[i].normalizedTime = runningTotalLen / len;
       runningTotalLen += splinePath.GetCurveLength(i);
}

to build an array of knot times, but in my tests I’ve found this to be not entirely accurate. The results are slightly off, but I need a more accurate result for what I’m trying to do.

I want to make a SplineAnimate follow the path, but stop exactly on each point for a short delay. I do this by setting the SplineAnimate.NormalizedTime when it passes the time I calculate using the above code. In testing, the SplineAnimate is stopping shortly after the position of the knot, so I think the calculations above are returning inaccurate results.

Is there an API way to get an accurate normalized time of a knot?

Hi @Damocles ,
I would give you the same answer that on [this post]( https://discussions.unity.com/t/896343 page-4#post-8941401) basically:
SplineUtility.ConvertIndexUnit is your friend!
in your case that’ll be:
splinePath.ConvertIndexUnit(i,PathIndexUnit.Knot, PathIndexUnit.Normalized);