Search Unity

Official Unity Splines

Discussion in 'World Building' started by gabrielw_unity, Oct 5, 2022.

  1. ThomasLopez

    ThomasLopez

    Unity Technologies

    Joined:
    Jun 8, 2020
    Posts:
    159
    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!
     
    fxlange likes this.
  2. ThomasLopez

    ThomasLopez

    Unity Technologies

    Joined:
    Jun 8, 2020
    Posts:
    159
    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! :)

    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 :


    Hope this help!

    Cheers

    upload_2023-5-30_10-25-17.png
     
  3. ThomasLopez

    ThomasLopez

    Unity Technologies

    Joined:
    Jun 8, 2020
    Posts:
    159
    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 :) This is almost ready and available for you!
     
    GDevTeam, fxlange and ManuelRauber like this.
  4. ManuelRauber

    ManuelRauber

    Joined:
    Apr 3, 2015
    Posts:
    122
    That sounds great! Thanks :)
     
  5. ManuelRauber

    ManuelRauber

    Joined:
    Apr 3, 2015
    Posts:
    122
    Another question @ThomasLopez

    Do you also open "EditorSplinesUtility.ReverseFlow"?

    I have the following scenario:

    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!
     
    Fep310 likes this.
  6. Crowsinger

    Crowsinger

    Joined:
    Apr 23, 2022
    Posts:
    19
    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?

    upload_2023-6-7_9-11-24.png
     
  7. Ohmnivore

    Ohmnivore

    Joined:
    Dec 16, 2013
    Posts:
    5
    ThomasLopez and KimmoFactor like this.
  8. ThomasLopez

    ThomasLopez

    Unity Technologies

    Joined:
    Jun 8, 2020
    Posts:
    159
    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 :)

    Have fun!
     

    Attached Files:

  9. ThomasLopez

    ThomasLopez

    Unity Technologies

    Joined:
    Jun 8, 2020
    Posts:
    159
    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!
     
  10. ThomasLopez

    ThomasLopez

    Unity Technologies

    Joined:
    Jun 8, 2020
    Posts:
    159
    Hey there (and to keep you up to date @ManuelRauber)!
    Splines 2.3.0 is now out :D 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!
     
    GDevTeam likes this.
  11. kaarrrllll

    kaarrrllll

    Unity Technologies

    Joined:
    Aug 24, 2017
    Posts:
    552
    GDevTeam and Ohmnivore like this.
  12. GDevTeam

    GDevTeam

    Joined:
    Feb 14, 2014
    Posts:
    90
    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?
     
  13. jbooth

    jbooth

    Joined:
    Jan 6, 2014
    Posts:
    5,461
    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<T> 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<T>, 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.
     
  14. GDevTeam

    GDevTeam

    Joined:
    Feb 14, 2014
    Posts:
    90
    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.
     
    Unifikation likes this.
  15. ThomasLopez

    ThomasLopez

    Unity Technologies

    Joined:
    Jun 8, 2020
    Posts:
    159
    Hi @jbooth ,
    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 :) 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 :D

    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!
     

    Attached Files:

  16. ThomasLopez

    ThomasLopez

    Unity Technologies

    Joined:
    Jun 8, 2020
    Posts:
    159
    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 name upload_2023-6-12_10-17-5.png
     
    GDevTeam likes this.
  17. jbooth

    jbooth

    Joined:
    Jan 6, 2014
    Posts:
    5,461
    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:

    Code (CSharp):
    1. static GizmoType splineEditMode = GizmoType.Pickable | GizmoType.Selected | GizmoType.Active | GizmoType.InSelectionHierarchy;
    2.  
    3.         [DrawGizmo(GizmoType.Active | GizmoType.Pickable | GizmoType.NonSelected | GizmoType.Selected)]
    4.         static void RenderExtraGizmo(Road editorTarget, GizmoType gizmoType)
    5.         {
    6.             if ((gizmoType & GizmoType.Pickable) == GizmoType.Pickable || gizmoType == splineEditMode)
    7.             {
    8.                 SelectSpline(editorTarget.splineContainer);
    9.             }
    10.  
    11.             SplineContainer splineContainer = editorTarget.splineContainer;
    12.  
    13.             if (splineContainer == null)
    14.                 return;
    15.  
    16.             Color prevColor = Gizmos.color;
    17.             Gizmos.color = new Color(0, 0, 1, 0.5f);
    18.             foreach (Spline spline in splineContainer.Splines)
    19.             {
    20.                 if (spline.Count > 0)
    21.                 {
    22.                     for (int i = 1; i < spline.Count; ++i)
    23.                     {
    24.                         Gizmos.DrawSphere(splineContainer.transform.TransformPoint(spline[i].Position), 0.5f);
    25.                     }
    26.  
    27.                 }
    28.             }
    29.             Gizmos.color = prevColor;
    30.         }
    and when the user clicks on one, I do:

    Code (CSharp):
    1. static void SelectSpline(SplineContainer spline)
    2.         {
    3.             if (spline != null)
    4.             {
    5.                 Selection.activeGameObject = spline.gameObject;
    6.                 ActiveEditorTracker.sharedTracker.RebuildIfNecessary();
    7.                 ToolManager.SetActiveContext<SplineToolContext>();
    8.                 ToolManager.SetActiveTool<SplineMoveTool>();
    9.                 //EditorSplineUtility.SetKnotPlacementTool();
    10.             }
    11.         }
    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?
     
  18. jbooth

    jbooth

    Joined:
    Jan 6, 2014
    Posts:
    5,461
    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.
     
  19. Damocles

    Damocles

    Joined:
    Jul 21, 2012
    Posts:
    46
    How can I get the normalized time of a given knot? I thought I could iterate over the knots/length like this:

    Code (CSharp):
    1. float len = splinePath.GetLength();
    2. float runningTotalLen = 0f;
    3. for (int i = 0; i < splinePath.Count; i++)
    4. {
    5.        data[i].normalizedTime = runningTotalLen / len;
    6.        runningTotalLen += splinePath.GetCurveLength(i);
    7. }
    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?
     
  20. ThomasLopez

    ThomasLopez

    Unity Technologies

    Joined:
    Jun 8, 2020
    Posts:
    159
    Hi @Damocles,
    I would give you the same answer that on this post basically:
    SplineUtility.ConvertIndexUnit is your friend!
    in your case that'll be:
    splinePath.ConvertIndexUnit(i,PathIndexUnit.Knot, PathIndexUnit.Normalized);
     
  21. ThomasLopez

    ThomasLopez

    Unity Technologies

    Joined:
    Jun 8, 2020
    Posts:
    159
    In that case I would try to do my owm implementation of the IContainerSpline interface. In your case
    Splines
    will just be an array of 1 spline and the KnotLinkCollection will not be of any use.
     
  22. Damocles

    Damocles

    Joined:
    Jul 21, 2012
    Posts:
    46
    Thanks for the help, Thomas. As some feedback for splines, I think that method is a bit confusing, especially in terms of the docs. I saw it before I posted asking for help, and had dismissed as not what I was looking for. In the docs, the parameter 't' is described as "Interpolation in the original PathIndexUnit". This made me think it was only useful for converting between normalized values, I never considered that a float value could be passed in as a knot index.

    Overall, I think making some well-named wrappers for more common functions (like getting the normalized time of a knot), and adding them to the SplineUtility class would be useful for people that don't have an in-depth knowledge of spline terminology.
     
  23. ThomasLopez

    ThomasLopez

    Unity Technologies

    Joined:
    Jun 8, 2020
    Posts:
    159
    I understand your usecase but there is nothing straightforward in the current API to help around with that indeed.
    The problem is that gizmos are here for visualization/selection but not manipulation and Handles are here for manipulation but , as you say, they are only active depending on the selection.

    It's interesting how you use gizmo to handle the siwtch between context and indeed remove some clicks, I'm curious to see how this handles multiple selection with splines and gameObject, I didn't think about that one :D

    The way I would go for your idea would be to create my own AddKnotTool inheriting from SplineTool (using the new exposed API) and draw all the segments and all the knots using SplineHandles API, then draw your knot handle and manage the behavior of the knot you add directly in your tool to move it around. All the handles and the visual should be pretty easy using the new API, only the new knot manipulation might be a little trickier (depending the behavior you look for) but nothing complicated.

    I've attached a small tool sample to use the new exposed API, the tool doesn't do anything interesting, just display a mesh at the start, middle and end of the spline, but the idea here is just to show how to use the SplineTool/SplineHandle API to make your own tools.
     

    Attached Files:

  24. ThomasLopez

    ThomasLopez

    Unity Technologies

    Joined:
    Jun 8, 2020
    Posts:
    159

    About your code just a slight problem I can see here is that you cannot go back to the GameObject mode whenever you have a spline selected, so you cannot use the default Move/Rotate/Scale tools here, am I correct?
     
  25. jbooth

    jbooth

    Joined:
    Jan 6, 2014
    Posts:
    5,461
    The gizmo approach would work, except when you go to select a different spline while in spline edit mode via this method you don't get a gizmo callback for clicking on the gizmo, because it's not triggered while you're in spline edit mode. So right now it feels great to get into editing, but once you're in edit mode you feel a little trapped to that spline until you realize you have to exit spline edit mode and then select another spline from game object mode.


    Thanks for taking the time to write this! So if I understand correctly, this gets run regardless of if the spline is selected or not, but then I basically have to rewrite all the spline rendering and manipulation controls myself? That seems like a lot of potentially changing code to replicate with splines still in development - is there any way I can fall through to the existing code for 90% of it?

    Once your in edit mode the spline controls work fine- the issue is that if you go to select a different spline via it's gizmo, the gizmo code does not get triggered so the selection is ignored. The work around is to go back to game object mode, then select the other spline, which is clunky.
     
  26. Damocles

    Damocles

    Joined:
    Jul 21, 2012
    Posts:
    46
    How should I apply the NormalizedTime value of the SplineAnimate component, when using PingPong loop type?

    I've noticed that during the 'forward' part of the ping-pong, setting the NormalizedTime value works as expected. However, during the 'reverse' half of the ping-pong, setting NormalizedTime makes it start moving forward again, but I want it to continue on its reverse direction. Is there some trick to making it remember that it's in the back half of the ping-pong?
     
  27. freyzorr

    freyzorr

    Joined:
    Jul 26, 2015
    Posts:
    30
    I seem to be missing some basic spline tools from my tool bar. I only seem to have the draw spline tool and width (if available). I tried updating my spline package from 2.2.1 to 2.3.0 along with samples but change. I'm unable to add knots to existing splines which is pretty crippling.
    I recently upgraded the project from 2021 LST to 2022 LTS.
    Any ides what might cause this or how to enable the other tools?

    upload_2023-6-14_17-48-23.png
     

    Attached Files:

  28. ThomasLopez

    ThomasLopez

    Unity Technologies

    Joined:
    Jun 8, 2020
    Posts:
    159
    You have it,
    the "Draw spline tool" is the one you want, to draw a new spline or to add knots to an existing on, just select that tool and click on any spline segment to add a knot. That'll start to create a new spline from that position, just click the Enter key to only add a knot and don't add a new spline.
     
    freyzorr and cwelbon like this.
  29. ThomasLopez

    ThomasLopez

    Unity Technologies

    Joined:
    Jun 8, 2020
    Posts:
    159
    Hi @Damocles,
    Using the ping-pong mode, I don't really get a usecase where you would want to change the NormalizedTime as that'll teleport the object to another location and break the ping-pong effect. However if you want to do that this is not possible out-of-the box for now indeed. I'll add a fix for that.

    If you need it right now, I'll advice you to do this instead of setting the normalized time:

    Code (CSharp):
    1. var currentDirection = (int)(m_SplineAnimate.ElapsedTime / m_SplineAnimate.Duration);
    2. m_SplineAnimate.ElapsedTime = m_SplineAnimate.Duration * m_Time + ((currentDirection % 2 == 1) ? m_SplineAnimate.Duration : 0f);
     
  30. Damocles

    Damocles

    Joined:
    Jul 21, 2012
    Posts:
    46
    Thanks for your help. For information purposes, what I needed it for is this: I'm making a system where a platform moves along a linear spline, but has the ability to stop and wait at various knots along the spline. The issue was, it needs to stop precisely at the knot point, of course the animator would overshoot a varying amount depending on frame rate. So I am using NormalTime to "teleport" it back a tiny amount, then pause it, so it stays in the perfect position.

    After looking at your code example and experimenting, I've reduced it to:

    Code (CSharp):
    1. splineFollower.NormalizedTime = desiredNormalizedTime + (splineFollower.NormalizedTime >= 1f ? 1f : 0f);
    The NormalizedTime value is very odd for ping pong loops. The first half runs from 0-1 (makes sense), but the second half runs from 2 to 1 (unexpected!).

    Also, it would be great if we could set MaxSpeed to negative numbers (or maybe set a boolean) to reverse the direction of the SplineAnimate movement.
     
  31. pbritton

    pbritton

    Joined:
    Nov 14, 2016
    Posts:
    160
    I am currently using ElapsedTime to control the behavior of an GameObject in the scene. However, there is a bug in which ElapsedTime being set to 0 after being set to the max time, places the GameObject at the end of the spline instead of the start. This issue is easily replicable by setting the value manually in the Editor. This issue also occurs in script.
     
  32. ThomasLopez

    ThomasLopez

    Unity Technologies

    Joined:
    Jun 8, 2020
    Posts:
    159
    That sounds weird indeed, Normalized time should always be between 0 and 1, looking at the inspector in debug mode also shows values staying between 0 and 1 in both directions :
     

    Attached Files:

  33. ThomasLopez

    ThomasLopez

    Unity Technologies

    Joined:
    Jun 8, 2020
    Posts:
    159
    Indeed, that's a bug thanks for reported, I fixed it, that'll be part of the next release :)
     
    GDevTeam and pbritton like this.
  34. pbritton

    pbritton

    Joined:
    Nov 14, 2016
    Posts:
    160
    Awesome.
     
  35. Damocles

    Damocles

    Joined:
    Jul 21, 2012
    Posts:
    46
    @ThomasLopez

    I think I've tracked down why I was seeing values going from 2 to 1 in the back half of a ping-pong.

    In my code, I was making the SplineAnimate wait at the last knot in the spline, and to do this I was setting the NormalizedTime to 1f to set a precise location. I think the issue then lies on line 542 of SplineAnimate.cs, at the end of the CalculateNormalizedTime(float deltaTime) method...

    Code (CSharp):
    1. m_NormalizedTime = Mathf.Floor(m_NormalizedTime) + t;
    This line is setting m_NormalizedTime to 2f only when it is already exactly 1f. 99% of the time this would never happen, but I made it happen every time.
     
  36. sand_lantern

    sand_lantern

    Joined:
    Sep 15, 2017
    Posts:
    210
    I need help understanding if this is expected behavior or a bug (2022.3.2f1 LTS, Spline V 2.2.1). I have made a test script to illustrate my issue.

    Code (CSharp):
    1. using System;
    2. using Unity.Mathematics;
    3. using UnityEngine;
    4. using UnityEngine.Splines;
    5.  
    6. public class SplineTest: MonoBehaviour
    7. {
    8.     [NonSerialized]
    9.     Spline spline;
    10.     private void OnDrawGizmos ()
    11.     {
    12.         var container = GetComponent<SplineContainer> ();
    13.         if (container == null)
    14.         {
    15.             container = this.gameObject.AddComponent<SplineContainer> ();
    16.             container.Spline.Add (new BezierKnot (new float3 (1f, 0f, 0f)));
    17.             container.Spline.Add (new BezierKnot (new float3 (0f, -10f, 0f)));
    18.             container.Spline.Add (new BezierKnot (new float3 (0f, -25f, 0f)));
    19.             container.Spline.Add (new BezierKnot (new float3 (-1f, -47f, 0f)));
    20.             container.Spline.Add (new BezierKnot (new float3 (0f, -100f, 0f)));
    21.             container.Spline.Add (new BezierKnot (new float3 (10f, -100f, 0f)));
    22.             container.Spline.Add (new BezierKnot (new float3 (20f, -100f, 0f)));
    23.             container.Spline.Add (new BezierKnot (new float3 (30f, -100f, 0f)));
    24.             container.Spline.Add (new BezierKnot (new float3 (30f, -100f, 10f)));
    25.             container.Spline.Add (new BezierKnot (new float3 (30f, -100f, 20f)));
    26.             container.Spline.Add (new BezierKnot (new float3 (30f, -100f, 30f)));
    27.             container.Spline.Add (new BezierKnot (new float3 (30f, -90f, 30f)));
    28.             container.Spline.Add (new BezierKnot (new float3 (30f, -60f, 30f)));
    29.         }
    30.  
    31.         var spl = container.Spline;
    32.         bool init = false;
    33.         if (spline == null)
    34.         {
    35.             spline = new Spline ();
    36.             init = true;
    37.         }
    38.         float3 center = transform.position;
    39.         //Quaternion rot;
    40.         for (int iB = 0; iB < spl.Count; iB++)
    41.         {
    42.             BezierKnot curveKnot;
    43.             float3 dir1, dir2;
    44.             float3 current = spl[iB].Position;
    45.             if (iB == 0)
    46.             {
    47.                 dir1 = math.normalize (spl[iB + 1].Position - current);
    48.                 dir2 = -dir1;
    49.             } else
    50.             {
    51.                 dir1 = math.normalize (current - spl[iB - 1].Position);
    52.                 dir2 = -dir1;
    53.             }
    54.  
    55.             curveKnot = new BezierKnot (current, dir1, dir2);
    56.  
    57.             if (init)
    58.             {
    59.                 spline.Add (curveKnot);
    60.             } else
    61.             {
    62.                 spline[iB] = curveKnot;
    63.             }
    64.         }
    65.  
    66.  
    67.         float3 position, tangent, upVector;
    68.         spline.Evaluate (0f, out position, out tangent, out upVector);
    69.         float3 prevPosition = (float3) transform.position + position;
    70.         for (float i = 0; i <= 1f; i += .01f)
    71.         {
    72.             spline.Evaluate (i, out position, out tangent, out upVector);
    73.             position = position + (float3) transform.position;
    74.  
    75.             Gizmos.color = Color.green;
    76.             Gizmos.DrawLine (prevPosition + 1f, position + 1f);
    77.             if (float.IsNaN (upVector.x))
    78.             {//We have a NaN value, output something to illustrate bad region
    79.                 Gizmos.color = Color.red;
    80.                 upVector = new float3 (3f, 3f, 3f);
    81.             } else
    82.             {
    83.                 Gizmos.color = Color.blue;
    84.             }
    85.             Gizmos.DrawLine (position + 1f, position + upVector + 1f);
    86.             prevPosition = position;
    87.         }
    88.     }
    89. }
    90.  

    Basically, every time that multiple knots are directly vertical of each other, the value of upVector from
    spline.evaluate(t, out position, out tangent, out upVector)
    results in a NaN float3 (Illustrated in my screenshot with diagonally outwards red lines).

    To me this reads as a bug for the following reasons.
    1) the upVector isn't up, so there shouldn't be some non vector/divide by zero mathiness going on as far as I know.
    2) I can concieve of some expected value to be output for upVector (in this case, something like
    new float3(1f, 0f, 0f)
    but really anything perpendicular to that axis would probably make sense).
    3) upVector isn't a useful value to use if it sometimes returns NaN.

    Is this expected output? If so, what should I be doing to mitigate this.

    In my case, I'm building a somewhat tube shaped mesh following a spline, and using the upVector multiplied by a changing radius and then rotated a discrete number of times around that position in order to offset my spline from the center position given by my position spline.

    If my tube is pointing directly downards nothing gets generated due to NaN vectors.
     

    Attached Files:

    Last edited: Jun 16, 2023
    ThomasLopez likes this.
  37. voodooRod

    voodooRod

    Joined:
    Jun 12, 2014
    Posts:
    8
    This is an observation...the SplineContainer's EvaluatePosition (2022.3.1f1) call allocs 32B of GC for every call. I know that isn't much but over time with several entities traveling over splines things can get dodgy.
     
    ThomasLopez and sand_lantern like this.
  38. MirzaBeig

    MirzaBeig

    Joined:
    Dec 27, 2014
    Posts:
    602
    Getting in to using the Spline tool more. Unity has needed something like this for a long time. :)
    My primary focus right now is VFX. Splines come in handy for all kinds of effects.

    I have this stylized flowing water shader applied to the extruded mesh of a spline. I'm noticing the UVs are not normalized, something very useful to have for shaders.

    upload_2023-6-17_21-19-56.png
    upload_2023-6-17_21-20-5.png

    In the images above, the blue should automatically scale to the end, but it's dependent on the length of the spline. Could this information be provided in another channel?

    The length could be baked in, allowing it to be used for normalizing the UV in the shader, or other things as well. It could be passed in manually, but it feels like it should be available somewhere.
     
    fxlange and Unifikation like this.
  39. hafu985

    hafu985

    Joined:
    Aug 27, 2021
    Posts:
    7
    SplineAnimation not ready for use on start.
    I want to make some configs on start and then invoke Play, but it not working.
    It begin work only on next frame.
    example
    Code (CSharp):
    1.     public class WagonAnimation : MonoBehaviour
    2.     {
    3.         [field: SerializeField] public float DistanceBetween { get; private set; }
    4.  
    5.         [SerializeField] private SplineAnimate _splineAnimate;
    6.  
    7.         private void OnValidate() => _splineAnimate = _splineAnimate ? _splineAnimate : GetComponent<SplineAnimate>();
    8.  
    9.         private IEnumerator Start()
    10.         {
    11.             yield return null;
    12.             Activate();
    13.         }
    14.  
    15.         public void Activate()
    16.         {
    17.             var length = _splineAnimate.Container.CalculateLength();
    18.             var totalTime = _splineAnimate.Duration;
    19.             var firstWagon = transform.parent.GetChild(0).GetComponent<WagonAnimation>();
    20.             var index = transform.GetSiblingIndex();
    21.             _splineAnimate.ElapsedTime = Time.time + index * (firstWagon.DistanceBetween / length) * totalTime;
    22.             _splineAnimate.Play();
    23.         }
    24.     }
    Spline v2.2.1

    p.s. it happens only on scene start, other game objects which started after working correctly
     
    Last edited: Jun 19, 2023
  40. sand_lantern

    sand_lantern

    Joined:
    Sep 15, 2017
    Posts:
    210

    I have worked around this issue by checking if upVector is NaN, then I do
    upVector = cross(tangent, new float3(0,0,1));


    I still feel like I shouldn't have to be doing this. Am I crazy?
     
    ThomasLopez likes this.
  41. MirzaBeig

    MirzaBeig

    Joined:
    Dec 27, 2014
    Posts:
    602
    Also noticing when copy-pasting a spline, it will constantly revert back and forth between the original and any changes you make. Seems like it's not letting go of a reference.

    upload_2023-6-20_0-17-36.png

    ^Notice the spline shape doesn't match. The straight cylinder is what I copied and started modifying, and I was sure to change the references, too.

    upload_2023-6-20_0-19-18.png

    ^When I hit play, or toggle the extrusion, it fixes itself.

    upload_2023-6-20_0-21-14.png

    A closer look at the assigned Spline (which is correct, and updated to the copy).

    upload_2023-6-20_0-20-11.png
    upload_2023-6-20_0-22-26.png

    Even though the Spline that is assigned to Spline Extrude is correct, as it's the new copy, the mesh seems to swap back and forth anyways. The geometry doesn't update if you animate the extrusion range, either.
     
    Last edited: Jun 20, 2023
    Unifikation likes this.
  42. Unifikation

    Unifikation

    Joined:
    Jan 4, 2023
    Posts:
    1,086
    Amazing stuff. Can't wait to see what you do with splines and particles!

    @Unity, in "fixing" this, could you provide both: referenced copies and unique copies? That way we can do fancy animations by changing the origins and rotations of replicants and animating one of them, or all of them.

    EDIT: Addendum.

    for the newer workers at Unity, or those that have worked primarily in code, this guy: @Mirza-Beig is one of the greatest exponents of visual effects and training in how to use visual effects within Unity, and has been for quite some time. His works are truly inspiring and educational, and often right at the cutting edge of what's been possible with Unity. He is not your average Unity user: https://www.youtube.com/c/MirzaBeig

    If he's intrigued by inbuilt splines, there's probably lots of very good reasons for that, and enormous potential about to be unleashed. So please take any suggestions or improvements ideas he has under very serious consideration, as we'll all benefit from them.

    Thank you, Mirza. Have learnt a lot from you!
     
    Last edited: Jun 20, 2023
  43. MirzaBeig

    MirzaBeig

    Joined:
    Dec 27, 2014
    Posts:
    602
    Alhamdulillah. And I didn't even remember that account! Must have been around the time I started using Unity myself. For reference, I'm just creating a visual step-wise tutorial for spline-based shaders (flow), like this stylized 'stream' of water. It could just as well be a laser.

    upload_2023-6-21_5-12-13.png

    upload_2023-6-21_5-12-55.png

    While the extrusion range works in the editor, it doesn't work at runtime if animated via an animator/animation clip.

    upload_2023-6-21_5-17-18.png

    Combined with the issue of the UVs, it limits what can be done in terms of VFX. With the updated UVs, at least I could clip the geometry in the shader itself (likely faster, because the geometry can be static at this point), but the extra complexity from having to pass the length manually is not intuitive.

    Currently using Unity 2022.3.0 with Splines 2.3.0 added from the manager by name.

    upload_2023-6-21_5-27-2.png
     
    Last edited: Jun 21, 2023
    ThomasLopez likes this.
  44. olivecrow

    olivecrow

    Joined:
    Jul 15, 2017
    Posts:
    24
    I have a very interesting use of the spline package. Perhaps more developments are possible in the future.
    To do so, the following are the functions necessary for spline, which I felt while using the spline package.

    1. Components that procedurally create meshes or objects, such as <SplineInstantiate> and <SplineExtrude>, must have a function such as Apply() as a C# API and inspector button. <SplineInstantiate> will expose the instances in a hierarchy view. And <SplineExtrude> will save the created mesh as an asset. Of course, when the work is done, the existing component should be removed or disabled.

    2. The rotation offset function of <SplineInstantiate> requires snapping. If you have a rect column, you might want to snap the y angle to 90 to properly avoid repeating.

    3. <SplineExtrude> must support various shapes, not just simple tube shapes. One of the spline samples already has a custom script that draws roads, but it looks like it needs to be integrated into <SplineExtrude>.

    4. The decal must be rendered along the spline. This is very useful for detail work, such as drawing Pavestone on a bumpy terrain, or drawing long tire skidmarks.

    5. At each point on the spline, not only the tangent, but also the direction of the normal must be exposed as a vector. If a point is perfectly vertical on flat ground, the normal of it would be (0, 1, 0). This is more intuitive than dealing with tangents. And should be able to edit the normals of all points at once.

    Thanks to everyone developing splines for their hard work.
    I hope that good features will continue to be updated in the future.
     
    ThomasLopez and Unifikation like this.
  45. udede

    udede

    Joined:
    Jul 26, 2011
    Posts:
    72
    Hello
    I want the prefabs with spline instantiate to always move in the direction I choose, how can I do that? thank you...
     
  46. Rowlan

    Rowlan

    Joined:
    Aug 4, 2016
    Posts:
    4,290
  47. jbooth

    jbooth

    Joined:
    Jan 6, 2014
    Posts:
    5,461
    Optimizations for SplineUtility- I'd submit a bug, but QA would just bounce it unless I shoot a video about it. And you don't take git PRs, so..

    Code (CSharp):
    1.             var currentPos = spline.EvaluatePosition(fromT);
    2.             resultPointT = fromT;
    3.  
    4.             var forwardSearch = relativeDistance >= 0;
    5.             var residual = math.abs(relativeDistance);
    6.             float linearDistance = 0;
    7.             float3 point = spline.EvaluatePosition(fromT);
    You sample evaluate spline twice here, when the same value is used in either case.

    Code (CSharp):
    1. if (resultPointT > 1f) //forward search
    2.                 {
    3.                     resultPointT = 1f;
    4.                     point = spline.EvaluatePosition(1f);
    5.                 }
    6.                 else if (resultPointT < 0f) //backward search
    7.                 {
    8.                     resultPointT = 0f;
    9.                     point = spline.EvaluatePosition(0f);
    10.                 }
    11.  
    12.                 point = spline.EvaluatePosition(resultPointT);
    Again, you call evaluate position twice when you don't need to. Just setting resultPointT is enough.
     
  48. kaarrrllll

    kaarrrllll

    Unity Technologies

    Joined:
    Aug 24, 2017
    Posts:
    552
    Thanks @jbooth, I integrated this improvement on our dev branch.

    I enjoyed your article on Optimizing Spline Ops as well, nice work.
     
    freyzorr, mgear and Rowlan like this.
  49. duzbot

    duzbot

    Joined:
    Aug 31, 2017
    Posts:
    17
    Hi everyone,

    I'm trying to find a way of being able to move items that are instantiated on the spline around the spline itself, similiar to how a gameobject with Spline Animate works.

    I've tried adding the Spline Animate component to those items, but no luck (also tried making the an item a prefab)
    For that matter, how would you give the Instantiated Items colliders etc? I'm getting up to speed with DOTS so I take it that item instantiates are rendered through the ecs renderer and don't work like GameObjects?

    My second idea is to get the positions from the instantiates and then instantiate prefabs in the positions with all the desired components. Although that feels unncessarily complex. Could someone point me to the right APIs if that is in fact the way to go?
     
  50. CogumeloSoft

    CogumeloSoft

    Joined:
    Dec 28, 2012
    Posts:
    88
    Sory if it's a stupid question but how to rotate the whole spline using C# to make it copy the transform rotation? There's no way to make it work in Local space instead of World space?
     
    Last edited: Jul 4, 2023