What a machine computes

A tilted span walks a staircase

A span along a banked floor's constant-depth direction is exact, and a renderer visits pixels rather than the span. Snapped to the grid, a 120 px span at a 20° bank costs 0.577 px where the same span along a page row costs 13.26 — twenty-three times better — and it never rises above 1.22 px at any bank. The price is bookkeeping: a band of twenty-four such spans draws 53 of its 1,368 pixels twice.

Worth reading first: A texture does not interpolate on the page · The precision a depth buffer has left.

Along a line of constant depth the page is affine found the one direction in which a renderer can step a texture across a receding surface without dividing at every pixel. Every plane meets each plane of constant camera depth in a line parallel to the picture, those lines image parallel to the plane’s own vanishing line, and along one of them the projection is affine: the worst texel on a 120-pixel span is 7×10147\times10^{-14} px. Bank the floor twenty degrees about the line of sight and that direction tips by the same twenty degrees, so the page’s rows — exact on a level floor — are 13.26 px out.

The obvious consequence is that a renderer should walk the tilted direction rather than the rows. The obvious objection is that the page is made of rows. A span at twenty degrees crosses a new page row every 2.9 pixels, and a renderer does not visit the span, it visits pixels — so the walk is a staircase, and the pixels of a staircase are not on the line.

This measures what the staircase costs, and what has to be bought with it.

The pixels are not on the line

A renderer walking a tilted span visits the grid point nearest the ideal line at each step. That pixel sits up to half a pixel off the line, perpendicular — and half a pixel perpendicular to a constant-depth line is a change of depth.

A span at 20 degrees crosses a row every 2.9 px, and its pixels sit up to 0.60 px off itA stretch of the constant-depth direction on a floor banked 20 degrees, with the pixels a nearest-pixel walk visits drawn as squares and the ideal line through them. The line runs at 20.0 degrees, so it crosses a new page row every 2.9 px and the walk is a staircase. The worst pixel sits 0.601 px off the line, and half a pixel across a constant-depth line is a change of depth: over a 120 px span that costs 0.577 px of texel where the unsnapped span costs 4e-7.the constant-depth direction, 20.0°a floor banked 20°, 40 pixels of the walkworst 0.60 px off the line
Fig. 1 A stretch of the constant-depth direction on a floor banked twenty degrees, with the pixels a nearest-pixel walk visits drawn as squares. The line crosses a row every 2.9 px and the worst pixel sits 0.60 px off it. The slider runs the bank.

So that exactness belongs to the line and not to the walk. The attribute a renderer hands a pixel is the one the ideal line carries at the foot of the perpendicular; the attribute the surface actually has at that pixel is a different one, because the pixel is at a different depth. The difference is the staircase’s cost, and it is measured here the same way every error in this field is measured — in pixels of page along the span, so it can be set beside the 13.26.

On a floor banked twenty degrees, a 120-pixel span a hundred pixels below the horizon costs 0.577 px snapped, against 2×10142\times10^{-14} unsnapped. The staircase is real and it is small.

Twenty-three times better, and never worse

The comparison to make is between that number and what the same span costs along a row.

At a 20 degree bank a row walk costs 13.26 px and a snapped tilted walk 0.577The worst texel on a 120 px span a hundred pixels below the horizon, walked two ways, against the floor's bank. Along the page's rows the error is the closed form in the depth ratio between the span's ends and grows steadily with the bank: 0.628 px at 1 degree and 40.0 at 45. Along the constant-depth direction, snapped to the pixel grid, it is 0.000 to 0.755 px across the whole range. At 20 degrees the tilted walk is 23 times better, and it never loses.0.0010.010.111010203040the floor's bank, degreesworst texel on a 120 px span, pxalong the rowstilted, snappeda 120 px span, 100 px below the horizon×23 at 20°
Fig. 2 The worst texel on the same 120 px span, walked along the page’s rows and along the constant-depth direction, against the floor’s bank. The row walk grows steadily; the tilted walk stays under a pixel.

A row walk’s error is the closed form in the depth ratio between the span’s ends, and it grows steadily with the bank: 0.63 px at one degree, 3.15 at five, 13.26 at twenty, 40.0 at forty-five. The snapped tilted walk stays between 0.15 and 0.76 px across the same range.

At a twenty-degree bank the tilted walk is twenty-three times better. At forty-five degrees it is better by a factor no number properly describes, because the staircase there costs nothing at all. And at one degree, where a row walk is only 0.63 px out and hardly worth replacing, the tilted walk is still 0.15 px — it never loses.

That answers the first half of the question. Snapping tilted spans to the pixel grid leaves a texel error far smaller than the row walk makes on the same banked floor, at every bank.

It is worth noticing what the two curves are made of, because they are not the same kind of quantity. The row walk’s error is geometry: the depth ratio between a span’s ends, which the surface and the camera fix between them, and which a texture does not interpolate on the page gave in closed form as (k1)/(k+1)(\sqrt{k}-1)/(\sqrt{k}+1) of the span’s length. Nothing a renderer does changes it except dividing. The tilted walk’s error is arithmetic: where a line of a given slope falls relative to a lattice of unit squares. The first grows without limit as a surface recedes or tips; the second cannot exceed what half a pixel of offset is worth, whatever the scene does.

That difference is the reason the comparison is so one-sided, and it is also the reason the result is robust. A scene twice as deep, a lens twice as long or a floor twice as steep moves the row walk’s curve and leaves the staircase’s where it is.

The cost is the grid’s, not the floor’s

The second half asked how the error depends on the bank angle and on the depth. Neither dependence is the one the question expected.

The staircase costs nothing at all at a 45 degree bank and 1.22 px at its worstThe snapped tilted walk's worst texel against the bank, swept half a degree at a time. It is not a trend: what a nearest-pixel walk costs depends on how nearly the line's slope is a ratio of small whole numbers, so it collapses to nothing wherever the constant-depth direction runs through grid points — 1 banks in this sweep leave under 0.08 px — and reaches 1.217 px between them. Every value in the sweep is inside 1.22 px, which is the thing that matters beside the 13.3 px a row walk costs the same span at a twenty degree bank.00.50011020304050the floor's bank, degreesworst texel on a 120 px span, pxone pixelswept half a degree at a timenever above 1.22 px
Fig. 3 The snapped walk’s worst texel against the bank, swept half a degree at a time. It is not a trend: the cost collapses wherever the constant-depth direction runs through grid points.

Swept finely, the staircase does not grow with the bank. It jumps about, reaching 1.22 px at its worst and collapsing to nothing at a forty-five-degree bank, where the line’s slope is exactly one and every step of the walk lands on the line. The cost of a nearest-pixel walk depends on how nearly the line’s slope is a ratio of small whole numbers, which is a fact about the grid and about arithmetic, and not about the floor.

Close to the horizon a row walk costs 36 px and the staircase 1.12The same two walks against how far down the picture the span is drawn, on a floor banked 20 degrees. Near the horizon the floor recedes fastest and a row walk is worst: 35.65 px at 40 px below it, against 6.92 at 190. The staircase barely moves — 0.404 to 1.118 px over the same range — because half a pixel off a constant-depth line is half a pixel wherever it is, and what it costs is set by the grid rather than by the recession.0.313103050100150how far below the horizon the span is drawn, pxworst texel on a 120 px span, pxalong the rowstilted, snappedbanked 20°, 23.8–5.0 mthe staircase hardly moves
Fig. 4 The same two walks against how far down the picture the span is drawn, on a floor banked twenty degrees. The row walk is worst near the horizon; the staircase barely moves.

The dependence on depth is just as lopsided. Near the horizon, where the floor recedes fastest, a row walk on a banked floor is 35.65 px out on a 120-pixel span; a hundred and ninety pixels down the page it is 6.92. The staircase over the same range runs between 0.404 and 1.118 px, and not monotonically — it does move, and it is not tracking the recession. Half a pixel off a constant-depth line is half a pixel wherever it is, and what that costs is set by how fast the attribute changes across the line, which near the horizon is large and far down small. The two effects partly cancel.

So the tilted walk is not merely better; it is better in a way that does not deteriorate where a renderer is most exposed. The row walk’s error is worst exactly where a floor’s texture is most compressed, and the staircase’s is not.

What has to be bought with it

Nothing here is free, and along a line of constant depth the page is affine named the price: neighbouring spans must tile the surface without gaps or double-drawn pixels.

A band of 24 tilted spans draws 53 of its 1368 pixels twice and leaves 0 holes24 constant-depth spans a pixel apart across a floor banked 20 degrees, each rasterised to the nearest pixels. The band covers 1315 distinct pixels where 1368 were drawn, so 53 of them — 3.9 per cent — are visited by two spans, and 0 pixels inside the band are visited by none. Two adjacent tilted spans do not tile the grid, which is the bookkeeping a renderer walking them would have to do and which a row walk never has to.53 of 1368 pixels drawn twice24 spans a pixel apart, banked 20°3.9% drawn again
Fig. 5 Twenty-four constant-depth spans a pixel apart across a floor banked twenty degrees, each rasterised to the nearest pixels. The darker pixels are visited by two spans.

They do not tile. Twenty-four spans a pixel apart across a banked floor draw 1,368 pixels between them and cover 1,315 distinct ones: 53 pixels — 3.9 per cent — are visited twice, and none is missed. The double visits are harmless for an opaque surface and are not harmless for anything that accumulates: a blend, a stencil count, an additive light.

That no pixel is missed is worth as much as the count of doubles, and it is not an accident of this band. Spans spaced a pixel apart along the direction of steepest depth change are spaced a little more than a pixel apart on the page, because that direction is not aligned with either axis of the grid; rounding each span’s pixels inward is what produces the overlap, and rounding is also what prevents the gap. A scheme that spaced the spans to avoid the overlap would produce holes instead, and a hole is the worse defect — a pixel drawn twice is wrong in a way that shows only under accumulation, and a pixel drawn never is wrong in every picture.

That is the bookkeeping a tilted-span renderer owes, and it is the honest form of the last part of the question — at what bank a per-pixel division is cheaper than walking tilted spans. The answer is that the comparison is not between two errors, because the tilted walk’s error is under 1.22 px at every bank and a divide’s is zero. It is between a divide at every pixel and the cost of deciding, once per pixel, which span owns it. A renderer that already writes each pixel exactly once has that bookkeeping; one that does not has to build it, and the pixels it would draw twice are the reason.

Why a nearest-pixel walk is as good as it is

The staircase’s size deserves an account, because half a pixel of perpendicular offset sounds like it should cost more than it does.

The attribute being stepped along a constant-depth span changes with position on the page in two ways. Along the span it changes affinely, which is the result along a line of constant depth the page is affine reached, and is why the span was chosen. Across the span it changes with depth, and near the horizon it changes fast. So the cost of being half a pixel off the line ought to be the gradient across the line, times a half.

It is not, and the reason is that a renderer hands the pixel the attribute at the foot of the perpendicular rather than at the span’s own centre. Two of the three errors a half-pixel offset could produce cancel there: the along-the-span position is right, and the depth is wrong only by what the perpendicular half-pixel changes it by. What remains is the second-order term — the curvature of the attribute across the line — and a second-order term in a half pixel is small.

That also says where the scheme would break. If the perpendicular offset were a whole pixel rather than half of one, the term would be four times larger; if a renderer stepped along the nominal direction rather than recomputing the foot at each pixel, the error would be first-order in the offset instead of second and the staircase would cost tens of pixels rather than tenths. The scheme is good because of a detail in how the attribute is looked up, and a renderer that skipped that detail would find the tilted walk no better than the rows.

What a renderer would actually decide

Three readings, in the order a renderer would need them.

A banked surface is worth walking tilted. The error falls by a factor of twenty-three at a twenty-degree bank and by more at steeper ones, and it never rises above 1.22 px at any bank, which is under the tolerance a texture filter already imposes. A pixel is not a point is the essay about why a pixel’s own extent is the floor under any such tolerance.

A nearly level surface is not. At one degree of bank a row walk is 0.63 px out and the tilted walk 0.15, so the whole gain is half a pixel and the bookkeeping is the same bookkeeping. There is a bank below which the scheme is not worth its complexity, and on these numbers it is somewhere around two or three degrees — not because the tilted walk gets worse but because the row walk stops being bad.

And a surface whose bank varies across the frame is the hard case. A curved screen is eight flat ones is the same difficulty in another part of the pipeline: a surface that is not one plane is handled by being cut into planes, and what the cutting costs is a separate measurement from what each piece costs. The constant-depth direction is the plane’s own vanishing line, so it is one direction for one plane, but a scene is many planes at many banks and each wants its own walk. A renderer choosing per triangle pays the bookkeeping per triangle, which is where one plane is nearly free and the cost of a plane change becomes the question.

What this does not settle

One floor, one frame, one field. The camera stands 1.5 m up with a sixty-degree field on a 690 × 400 frame, and the spans are 120 px long. A longer span crosses more rows and a shorter one fewer, and the staircase scales with neither in a simple way, because its size is a property of the slope rather than of the length.

The walk is nearest-pixel and nothing else. A renderer could sample each pixel’s own position rather than the line’s, which removes the staircase entirely and reintroduces a division — that is the trade this essay is about, and only one side of it is measured here. Supersampling, or a half-pixel offset chosen per span, would both move the number.

The attribute is position on the surface. Every error above is a texel error in page pixels, which is the currency a texture does not interpolate on the page established. A renderer interpolating a colour, a normal or a depth code has the same geometry and a different tolerance, and depth is a reciprocal is about why the last of those is the touchy one.

The double-drawn pixels were counted, not repaired. Deciding which span owns a contested pixel is a rule, and a rule that assigns each pixel to exactly one span changes which attribute it receives — by up to the same half-pixel offset, on the losing span’s terms. The divide is postponed is the essay about the discipline of doing arithmetic in the right order, and this is a place where the order has not been settled.

And the surface is a plane. A curved surface has no constant-depth lines at all in this sense, and the tilted-span scheme has nothing to walk along. What it has instead is the plane of each triangle, which is what a renderer actually works with, and the approximation error of that is not measured here.

The staircase, priced

A span along a banked floor’s own constant-depth direction is exact and a renderer cannot visit it. The pixels it visits instead sit up to half a pixel off the line, perpendicular, and perpendicular to a constant-depth line is where the depth changes.

Snapped to the grid, a 120-pixel span on a floor banked twenty degrees costs 0.577 px of texel where the same span along a page row costs 13.26 — twenty-three times better — and across banks from one degree to forty-five the snapped walk never exceeds 1.22 px while the row walk runs from 0.63 to 40.0.

What the staircase costs is a fact about the grid and not about the floor. It collapses to nothing at a forty-five-degree bank, where the slope is one and every step lands on the line, and it stays between 0.404 and 1.118 px down the whole picture where the row walk runs from 35.65 px near the horizon to 6.92 far down it.

The price is bookkeeping. Twenty-four spans a pixel apart draw 53 of their 1,368 pixels twice, so a renderer walking tilted spans has to decide which span owns each pixel — which is a different kind of cost from a division and is the reason the choice is not simply arithmetic.

Still open: whether a triangle can be walked in its own frame

Everything above walks spans across a surface and snaps them to the page’s grid, because the page’s grid is where pixels are. The staircase exists entirely because those two lattices are not aligned, and the measurement shows the cost is a property of the angle between them.

There is an arrangement in which they would be. A renderer could rasterise a triangle in a frame of its own — one axis along the constant-depth direction, the other across it — producing samples on a lattice that has no staircase at all, and then resample that image onto the page’s grid once at the end.

The question with a number in it is what the resampling costs against what the staircase costs. A resample is a filter and a filter blurs; the tilted lattice’s samples would be spaced differently from the page’s, by a factor that depends on the bank, so the reconstruction is not free and its error is not a texel error but a loss of sharpness. The measurement that settles it draws the same banked floor both ways at the same sample count, compares the two against a heavily supersampled reference, and asks at what bank a resample’s blur first exceeds the 1.22 px the staircase costs at its worst — and whether the answer moves when the texture is a checker rather than a gradient, since a filter’s damage depends on what is being filtered and a texel error’s does not.

Shares its objects with

Essays that name at least two of the same things, and that neither author linked.

Named objects

A flat tag is an object no other essay names yet.

Depth divisionForeshorteningHomogeneous coordinatesProjective invariantQuantisationResidualTransversalVanishing line