From the source
The stairs decision in code: each step is a cube with its collider stripped, and one hidden, rotated slab underneath is what the player and the NavMesh actually stand on. Two of the three comments are mine for this page; the rest is verbatim.
public static void Stairs(Transform parent, string name, Vector3 start, Vector3 direction, float run,
float rise, float width, int steps, Material material)
{
var root = Empty(name, parent, Vector3.zero).transform;
Vector3 dir = new Vector3(direction.x, 0f, direction.z).normalized;
Vector3 side = Vector3.Cross(Vector3.up, dir);
float stepRun = run / steps;
float stepRise = rise / steps;
for (int i = 0; i < steps; i++)
{
float top = start.y + stepRise * (i + 1);
Vector3 centre = start + dir * (stepRun * (i + 0.5f));
centre.y = top - stepRise * 0.5f;
var go = GameObject.CreatePrimitive(PrimitiveType.Cube);
go.name = "Step";
go.transform.SetParent(root, false);
go.transform.localPosition = centre;
go.transform.localRotation = Quaternion.LookRotation(dir, Vector3.up);
go.transform.localScale = new Vector3(width, stepRise, stepRun);
go.GetComponent<MeshRenderer>().sharedMaterial = material;
Object.DestroyImmediate(go.GetComponent<Collider>()); // the eye gets steps
}
BuildRamp(root, start, dir, side, run, rise, width); // the feet get a slope
}
private static void BuildRamp(Transform parent, Vector3 start, Vector3 dir, Vector3 side,
float run, float rise, float width)
{
const float thickness = 0.4f;
float slope = Mathf.Sqrt(run * run + rise * rise);
Vector3 alongSlope = (dir * run + Vector3.up * rise).normalized;
Quaternion rotation = Quaternion.LookRotation(alongSlope, Vector3.Cross(alongSlope, side).normalized);
// Sit the ramp so its top face passes through the step noses.
Vector3 topMid = start + dir * (run * 0.5f) + Vector3.up * (rise * 0.5f);
Vector3 centre = topMid - rotation * Vector3.up * (thickness * 0.5f);
var go = GameObject.CreatePrimitive(PrimitiveType.Cube);
go.name = "RampCollider";
go.transform.SetParent(parent, false);
go.transform.localPosition = centre;
go.transform.localRotation = rotation;
go.transform.localScale = new Vector3(width, thickness, slope);
go.GetComponent<MeshRenderer>().enabled = false; // never drawn, always walked on
}