Skip to content

Instantly share code, notes, and snippets.

@killthekitten
Created October 8, 2026 11:13
Show Gist options
  • Select an option

  • Save killthekitten/27a27eec8956c855d99b853c36896f78 to your computer and use it in GitHub Desktop.

Select an option

Save killthekitten/27a27eec8956c855d99b853c36896f78 to your computer and use it in GitHub Desktop.
Anchoring objects to splines with the Spline Extension plugin
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);
}
}
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