Appearance
Developer notes — kids.kapish.splines.meshes
unity
Role
The "extrude a cross-section along a spline" core, factored out so paths, walls and rivers share one sweeper and differ only by StripProfile. Depends on kids.kapish.splines (the Strip substrate) and kids.kapish.meshes (the MeshBuilder accumulator) — base splines stays mesh-free.
StripMeshBuilder
- Resample: the dense
Stripis resampled to rings atsegmentLengtharc spacing (Center/Left/Right/Up/Tangent). - Place: a
StripProfilePointsits atLerpUnclamped(Left, Right, Across) + Up * Up— Across rides the (terrain-conformed) edges, Up rides the frame. - Stitch: adjacent rings × adjacent profile points → two triangles. Winding is aligned to a per-quad outward reference (edge-midpoint minus cross-section centroid, mapped to world), so the surface is never inside-out regardless of how the profile was wound.
flipFacesinverts it. - Caps: closed profiles fan-triangulate the section at each end (outward = ∓tangent). Fan assumes a convex section — fine for the v1 wall presets; concave sections want ear-clipping (
kids.kapish.maths'EarClipTriangulator) later. - Normals: flat per-face (crisp edges). Smooth/welded normals (for hedges, rounded copings) are a later option.
Future
Paths' PathMeshBuilder can migrate onto this (its skirts/chunking layered on top) once it's worth a [SerializeReference] profile migration. Rivers/fences are just more profiles.
Usage Guide
You rarely use this directly — a primitive component (e.g. WallMeshStrip) drives it. To build a sweeper of your own:
csharp
using Carrot.Splines; // Strip, StripCalculator, StripSettings
using Carrot.Splines.Meshes; // StripProfile, StripMeshBuilder
using UnityEngine.Splines;
// 1. Author a profile (closed = a tube you can cap).
sealed class MyProfile : StripProfile
{
public override bool Closed => true;
public override void GetCrossSection(System.Collections.Generic.List<StripProfilePoint> into)
{
into.Add(new StripProfilePoint(0f, 0f, 0f));
into.Add(new StripProfilePoint(1f, 0f, 1f));
into.Add(new StripProfilePoint(1f, 2f, 1f));
into.Add(new StripProfilePoint(0f, 2f, 0f));
}
}
// 2. Strip from the spline, then sweep.
var container = GetComponent<SplineContainer>();
Strip[] strips = StripCalculator.ComputeAll(container, new StripSettings { Width = 0.4f, ConformToTerrain = true });
foreach (Strip s in strips)
{
// Returns one mesh per chunk (chunkLength arc; 0 = a single mesh).
foreach (Mesh m in StripMeshBuilder.Build(s, new MyProfile(), segmentLength: 1f, capEnds: true, transform.worldToLocalMatrix, chunkLength: 25f))
{
// ... assign each chunk to its own MeshFilter
}
}If faces render inside-out, pass
flipFaces: true— the profile's outward sense is reversed.