# 3. Evaluate and Placement Part of [[Splines]]. Prev: [[2. Knots and Tangent Modes]]. Next: [[4. SplineAnimate Dollies and Cameras]]. `t` in these APIs is a **normalized** interpolation value (0 at the start, 1 at the end of the evaluated spline). It is not metres. If you need even spacing in world units, convert with spline length (see pitfalls). ## 3.1 Evaluate a point `SplineUtility.Evaluate` (2.8/2.9 API) samples a `Spline`: ```csharp using UnityEngine; using UnityEngine.Splines; public static class SplineSample { /// <summary>Evaluates a container's spline 0 at normalized t. NOT compiled in Unity.</summary> public static bool TryEvaluate(SplineContainer container, float t, out Vector3 position, out Vector3 tangent, out Vector3 up) { position = default; tangent = default; up = default; if (container == null || container.Spline == null) return false; t = Mathf.Clamp01(t); return SplineUtility.Evaluate(container.Spline, t, out position, out tangent, out up); } } ``` `SplineContainer` also exposes `Evaluate` overloads: a **combined** evaluate (when the container has a path that should be treated as a whole) and a **per-spline-index** evaluate. Read the 2.9 IntelliSense for the overload you want: some return local positions that you must `container.transform.TransformPoint`, others already account for the container transform. **Confirm the space of the overload you call before you parent objects.** Flag: this series does not pin a single overload's space from memory - check the 2.9 method remarks in your Editor. If you use the container's `Evaluate` and the results sit at the origin, you almost certainly forgot the container transform or picked a local-space overload. ## 3.2 Place posts along a path ```csharp using UnityEngine; using UnityEngine.Splines; /// <summary> /// Instances a prefab at even *normalized* t steps. For even world spacing, see the length note below. /// NOT compiled in Unity. /// </summary> public sealed class SplinePrefabsPlacer : MonoBehaviour { [SerializeField] SplineContainer container; [SerializeField] GameObject prefab; [SerializeField] int count = 8; [SerializeField] bool lookAlongTangent = true; [ContextMenu("Place")] public void Place() { if (container == null || prefab == null || count < 1) return; var spline = container.Spline; if (spline == null) return; bool closed = spline.Closed; int steps = closed ? count : Mathf.Max(2, count); for (int i = 0; i < (closed ? count : steps); i++) { float t = closed ? (i / (float)count) : (i / (float)(steps - 1)); if (!SplineUtility.Evaluate(spline, t, out var pos, out var tangent, out var up)) continue; pos = container.transform.TransformPoint(pos); tangent = container.transform.TransformDirection(tangent); up = container.transform.TransformDirection(up); var instance = Instantiate(prefab, pos, Quaternion.identity, transform); if (lookAlongTangent && tangent.sqrMagnitude > 0.0001f) instance.transform.rotation = Quaternion.LookRotation(tangent, up.sqrMagnitude > 0.0001f ? up : Vector3.up); } } } ``` The `TransformPoint` step assumes `SplineUtility.Evaluate` on `container.Spline` is **local to the container**. If your 2.9 overload already returns world space, this will double-transform - **verify in Play Mode with the container off-origin** before you keep the conversion. That check is mandatory; it is the most common spline bug. For **even world spacing**, get the spline length (`SplineUtility.CalculateLength` or the equivalent 2.9 method - confirm the name in the API) and sample by distance / length, not by raw `t`. Uniform `t` packs posts tighter on a sharp curve if the parameterization is not arc-length. This is a generate-in-Editor / ContextMenu helper. Do not `Place()` every frame. If you need to regenerate, destroy previous children first in a *new* method you write carefully - this repo's safety rules for *tutorial authors* do not apply inside Unity, but a student who runs Place twice will stack prefabs. A production placer should clear or reuse instances. ## 3.3 Exercise Move the container away from the origin, Place 8 cubes, and confirm they sit on the visible curve. If they cluster at the origin or at a double-offset, you have a space bug - fix the transform step, do not "nudge" the container back to zero and call it solved. ## Sources - `SplineUtility` (2.8 docs; confirm 2.9): https://docs.unity3d.com/Packages/[email protected]/api/UnityEngine.Splines.SplineUtility.html - `SplineContainer` (2.8 docs; confirm 2.9): https://docs.unity3d.com/Packages/[email protected]/api/UnityEngine.Splines.SplineContainer.html