Created
October 8, 2026 11:13
-
-
Save killthekitten/27a27eec8956c855d99b853c36896f78 to your computer and use it in GitHub Desktop.
Anchoring objects to splines with the Spline Extension plugin
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using sc.splines.extensions.runtime.components; | |
| using UnityEditor; | |
| using UnityEngine; | |
| using UnityEngine.Splines; | |
| public class ReanchorSelected | |
| { | |
| [MenuItem("Tools/Spline Tricks/Re-anchor Selected Objects to nearest Splines")] | |
| private static void Perform() | |
| { | |
| GameObject[] gameObjects = Selection.gameObjects; | |
| Undo.SetCurrentGroupName("Re-anchor Selected Objects to nearest Splines"); | |
| int currentGroup = Undo.GetCurrentGroup(); | |
| Undo.RecordObjects(gameObjects, "add AttachTransformToSpline and reset transform"); | |
| foreach (GameObject gameObject in gameObjects) | |
| { | |
| if (gameObject.GetComponent<AttachTransformToSpline>()) | |
| continue; | |
| (SplineContainer nearestSpline, float nearestT, Vector3 nearestPositionWorld) = | |
| SplineTricks.FindNearestSpline(gameObject.transform); | |
| if (!nearestSpline) | |
| continue; | |
| Vector3 offset = new Vector3(0f, gameObject.transform.position.y - nearestPositionWorld.y, 0f); | |
| float customPosition = SplineUtility.ConvertIndexUnit( | |
| nearestSpline.Spline, | |
| nearestT, | |
| PathIndexUnit.Distance | |
| ); | |
| AttachTransformToSpline newComponent = Undo.AddComponent<AttachTransformToSpline>(gameObject); | |
| newComponent.customPositionType = PathIndexUnit.Distance; | |
| newComponent.customPosition = customPosition; | |
| newComponent.offset = offset; | |
| newComponent.point = AttachTransformToSpline.ConnectionPoint.Custom; | |
| newComponent.splineContainer = nearestSpline; | |
| newComponent.splineIndex = 0; | |
| newComponent.alignRotation = false; | |
| newComponent.Apply(); | |
| } | |
| Undo.CollapseUndoOperations(currentGroup); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using Unity.Mathematics; | |
| using UnityEngine; | |
| using UnityEngine.Splines; | |
| public class SplineTricks | |
| { | |
| public static (SplineContainer, float, Vector3) FindNearestSpline(Transform transform) | |
| { | |
| Vector3 transformPositionWorld = transform.position; | |
| Vector3 nearestSplinePositionWorld = new Vector3(0, 0, 0); | |
| SplineContainer[] candidateSplines = Object.FindObjectsByType<SplineContainer>(); | |
| SplineContainer nearestSpline = null; | |
| float nearestDistanceSquared = float.PositiveInfinity; | |
| float nearestT = 0f; | |
| foreach (SplineContainer candidateSpline in candidateSplines) | |
| { | |
| float3 transformPositionLocal = candidateSpline.transform.InverseTransformPoint(transform.position); | |
| Ray verticalRay = new Ray(transformPositionLocal, Vector3.down); | |
| SplineUtility.GetNearestPoint( | |
| candidateSpline.Spline, | |
| verticalRay, | |
| out float3 nearestCandidateSplinePointLocal, | |
| out float nearestCandidateT | |
| ); | |
| Vector3 nearestCandidateSplinePointWorld = candidateSpline.transform.TransformPoint( | |
| nearestCandidateSplinePointLocal | |
| ); | |
| // The distance is calculated in horizontal plane (i.e. without Y) to avoid false positives | |
| // when the object is far above the relevant spline and there are other splines on the side | |
| float distanceSquared = ( | |
| new Vector3(nearestCandidateSplinePointWorld.x, 0, nearestCandidateSplinePointWorld.z) | |
| - new Vector3(transformPositionWorld.x, 0, transformPositionWorld.z) | |
| ).sqrMagnitude; | |
| if (distanceSquared < nearestDistanceSquared) | |
| { | |
| nearestSplinePositionWorld = nearestCandidateSplinePointWorld; | |
| nearestDistanceSquared = distanceSquared; | |
| nearestSpline = candidateSpline; | |
| nearestT = nearestCandidateT; | |
| } | |
| } | |
| Debug.DrawLine(nearestSplinePositionWorld, transformPositionWorld, Color.red, 10f); | |
| return (nearestSpline, nearestT, nearestSplinePositionWorld); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment