Reading and display settings

Appearance

System follows your operating system and keeps following it, even if you change it later. The header's sun, moon and monitor cycle the same three options.

Text size (%) 100%

Default. Scales every text size on the site, equations and tables included.

Reading width 70ch

How much text runs across one line of prose. Narrower is easier to track; wider fits more on screen.

Line spacing 1.6

The leading on body text. Taller leading helps a tired eye stay on the line.

Density

Padding and gaps around controls, cards, and tables — how much breathing room the layout leaves itself.

Motion

System follows your operating system. Reduced removes every transition on this site. Full keeps them on unless your system asks for less.

0

Why P³

Motivation

Suppose you have two photographs of the same object and want its shape. Every point you want to recover lives in 3D; every measurement you actually have lives in a 2D image; and the object connecting the two — a camera — is a map from 3D points to 2D points. That is three different dimensions of geometry talking to each other, and the clean language for all of it is projective space one dimension up from Part 0: P³.

Three concrete needs make P³ unavoidable in what follows:

1. Reconstruction needs 3D points. Triangulation (Part 10), PnP (Part 11) and bundle adjustment (Part 15) all take 2D image measurements back to a 3D point X̃ = (X, Y, Z, W). The whole point of the series is to recover these, so their space has to come first.

2. A camera is a map P³ → P². Part 4's camera matrix is 3×4, literally a linear map from 4-vectors to 3-vectors. You cannot write that map down, or reason about its null space (the camera center), without knowing what a 3D projective point is.

3. Lines in space are the awkward object. Lots of real features are lines — building edges, lane markings, poles, the edges of a cube. A 3D line has no single obvious coordinate vector the way a point or a plane does. It needs a dedicated representation, and that representation (Plücker coordinates) is exactly what the trifocal tensor (Part 12) and line-based structure from motion are built on.

💡 What this page delivers: the 3D generalization of Part 0's point/line duality (points vs. planes), and a concrete representation for lines in space along with its one defining constraint d · m = 0. Nothing here depends on a camera yet — it is pure geometry, ready for Part 4 to project.
1

Points, planes, and incidence in P³

The duality, one dimension up

A point in P³ is a homogeneous 4-vector X̃ = (X, Y, Z, W), defined up to scale, exactly as in Part 0. A plane is also a 4-vector π = (π₁, π₂, π₃, π₄), and the plane is the set of points satisfying the incidence equation:

π · X̃ = π₁X + π₂Y + π₃Z + π₄W = 0

That is exactly Part 0's point-on-line rule l · x̃ = 0, with one more coordinate. In P² a point and a line are both 3-vectors related by a dot product; in P³ a point and a plane are both 4-vectors related by a dot product. This symmetry is the whole game: P³ has a duality between points and planes, and in this dimension a plane plays the role that a line played in P².

Everything Part 0 got from cross products has a P³ analogue, computed with a 4×4 determinant / generalized cross product:

join: plane through three points X̃₁, X̃₂, X̃₃ → πᵢ = (−1)⁸ · det(minorᵢ of [X̃₁ X̃₂ X̃₃])
meet: intersection of two planes π₁, π₂ → a line (a 2-dimensional subspace of the 4-vector space)
plane through two points and a line, or three planes meeting in a point — all determinant constructions

(The plane-through-three-points formula is the generalized cross product: πᵢ is the 3×3 minor of the 4×3 matrix whose columns are the three points, taken with an alternating sign, so that π is orthogonal to all three points at once — the same reason x̃₁ × x̃₂ was orthogonal to both points in Part 0.)

The plane at infinity. The special plane π∞ = (0, 0, 0, 1) acts on a point by reading off its last coordinate: π∞ · X̃ = W. So a point lies on the plane at infinity precisely when W = 0. Those are the ideal points — points at infinity — one for each 3D direction: a Euclidean direction d corresponds to the ideal point X̃∞ = (d, 0). Part 4 uses this directly: projecting an ideal point makes the camera's translation drop out and produces a vanishing point, v = K R d. The plane at infinity is also the object that separates a projective reconstruction from an affine one (Part 16).

Lines. A line is the intersection (meet) of two planes, which as a set is { X̃ : π₁ · X̃ = 0 and π₂ · X̃ = 0 } — a 2-dimensional subspace of the 4-dimensional vector space. It is not naturally a 4-vector like a point or plane; the set of all such 2-subspaces is the Grassmannian Gr(2, 4), whose dimension is 2 × (4 − 2) = 4. So a line in P³ has 4 degrees of freedom — and the rest of this page is about giving those 4 DOF usable coordinates.

⚠️ Compare the dimensions carefully: in P², points and lines both have 2 DOF and are dual. In P³, points and planes both have 3 DOF and are dual; lines have 4 DOF and are dual to themselves (the meet of two planes is also the join of two points). Lines are the "extra" object in 3D, and they are the ones that need special care.
2

Plücker coordinates for a line

A concrete representation, and its one constraint

Take a line in P³ and pick two distinct points on it, written in homogeneous form as X̃₁ = (X₁, W₁) and X̃₂ = (X₂, W₂), where each Xᵢ is the Euclidean 3-vector part and Wᵢ is the last coordinate. Define the pair

d = W₁ X₂ − W₂ X₁ (— the line’s direction)
m = X₁ × X₂ (— the line’s moment)

This is the convention used throughout this page: d is the direction, m is the moment (the 3-vector cross product of the two Euclidean point parts), and for finite points (W₁ = W₂ = 1) this simplifies to d = X₂ − X₁ and m = X₁ × X₂, which is the familiar geometry: the direction along the line, and the position of the line encoded by the cross product of two of its points.

The pair (d, m) is defined only up to a common scale — scaling both points equally, or choosing different points on the same line, rescales (d, m) together. And the two 3-vectors are not independent. They satisfy the Plücker relation:

d · m = (W₁X₂ − W₂X₁) · (X₁ × X₂) = W₁(X₂ · X₁×X₂) − W₂(X₁ · X₁×X₂) = 0

because a triple product with a repeated vector is always zero. This is the only equation the pair must obey, and it has a clean counting consequence:

6 coordinates − 1 overall scale − 1 constraint (d · m = 0) = 4 DOF  ✓

Six numbers, one scale redundancy, one constraint — exactly the 4 degrees of freedom a line in P³ has, matching the Grassmannian count from Step 1. The set of all (d, m) in P⁵ satisfying d · m = 0 is a quadric hypersurface called the Klein quadric, and every point of it corresponds to exactly one line in P³.

Dual form (line as the meet of two planes). The same recipe runs on plane coordinates. Two planes π = (π₀, π₄) and σ = (σ₀, σ₄) (each with a Euclidean normal 3-vector and a constant) meet in a line, and its Plücker matrix is L* = πσᵀ − σπᵀ, the formal dual of the point-based matrix below. In the dual, the direction comes from the normals and the moment from the plane constants, and the same constraint d · m = 0 holds.

The Plücker matrix. The most compact bookkeeping device is the skew 4×4 matrix

L = X̃₁ X̃₂ᵀ − X̃₂ X̃₁ᵀ

It is skew-symmetric and rank 2, and it stores the line without any explicit parameterization. Its 2-dimensional column space is precisely the line, i.e. the span of X̃₁ and X̃₂ — so X̃ lies on the line exactly when X̃ is in the column space of L. Its null space is the pencil of planes through the line, so the matrix tests incidence on planes directly:

X̃ on the line  ⇔  X̃ × d = m  ⇔  X̃ ∈ column space of L
π contains the line  ⇔  L π = 0

(L π = 0 holds precisely when π · X̃₁ = π · X̃₂ = 0, i.e. when plane π passes through both defining points. Note that incidence is tested on the left by planes, not by points — the left action of L annihilates planes through the line.)

How the line transforms. Apply a 3D projective map H (a 4×4 matrix) to the whole space. The image line is spanned by H X̃₁ and H X̃₂, so its Plücker matrix is

L′ = H L Hᵀ

For the 6-vector (d, m), the answer is not simply d′ = H d — d is a 3-vector and H is 4×4, so that product does not even type-check. The pair transforms linearly by the exterior square (“compound matrix”) ∧²H, a 6×6 matrix induced by H on the 2-forms. In the common cases it simplifies to something you can read off. For an affine map H = [[A, b], [0, 1]] (rotation, translation, and non-uniform scale, no projective part):

d′ = A d
m′ = det(A) A⁻ᵀ m + b × (A d)

and for a pure rigid motion (A = R a rotation, b = t, det R = 1) this becomes d′ = R d and m′ = R m + t × (R d): the direction simply rotates, while the moment picks up a translation term. In all cases the Plücker relation is preserved automatically, because H L Hᵀ is still skew of rank 2, hence still a valid line.

Projecting a line to an image line. Finally, the operation the rest of the series needs: given a camera P (3×4), a 3D line with two points X̃₁, X̃₂ projects to the image line through the two projected points, computed by Part 0's cross product:

l = (P X̃₁) × (P X̃₂)

One caveat carries real weight later: if the 3D line passes through the camera center, the two projected points coincide and l = 0. That is not a bug — the line is seen exactly edge-on, as a single pixel, and has no well-defined image line. Away from that degenerate case, every point of the 3D line projects onto l, which is the transfer that line-based multi-view methods rely on.

3

Play: a draggable 3D line and its Plücker coordinates

Interactive

🎯 Learning goal: the readout recomputes (d, m) from the drawn endpoints every time you move a slider, and d · m comes out zero — not by luck, but because any pair built as (X₂ − X₁, X₁ × X₂) satisfies the Plücker relation identically. Move the line anywhere in the cube: the constraint never breaks.

The 3D scene shows the world axes, a translucent reference cube, and an orange segment whose two endpoints you control with the six sliders. Two synthetic cameras watch the line: camera 1 sits at the world origin with identity rotation (its optical axis is the world +z axis, the OpenCV-style “z-forward” convention this series uses), and camera 2 has a modest rotation and a translation, positioned so it looks back at the scene. Each camera's image plane is drawn as a translucent square one unit in front of it, and the line's projected image is drawn on that plane. Both cameras are full 3×4 projection matrices P = K[R | −RC] computed live in JavaScript.

Drag to orbit the 3D scene, scroll to zoom. Faint square = a camera's image plane; the colored segment on it is the projected image line.

3D line & endpoints camera 1 · image line l₁ camera 2 · image line l₂

Watch two things. First, d · m always reads a numerical zero (something like 1e-16) no matter how you drag the line — that is the Plücker constraint, holding identically. Second, the two image lines' coefficients l₁ and l₂ change completely as the line moves, yet each one stays orthogonal to its own projected endpoints: l · (P X̃) = 0. That is Part 0's incidence equation reappearing inside a camera, and it confirms the projection and the drawing are numerically the same thing. Untick “Project into two views” to hide the image planes and see the 3D line on its own.

✓

Cheat sheet

Recap

QuantityExpressionWhere it resurfaces
3D pointX̃ = (X, Y, Z, W) ∈ P³Every P X̃ (Part 4); triangulation (Part 10); bundle adjustment (Part 15)
Planeπ = (π₁, π₂, π₃, π₄)Homography induced by a plane (Part 8); plane fitting in reconstruction
Incidenceπ · X̃ = 0Part 0's l · x̃ = 0 one dimension up; plane & line tests everywhere
Plane through 3 pointsgeneralized cross product (4×4 minors)Horizon / vanishing constructions; fitting planes to reconstructed points
Plane at infinityπ∞ = (0, 0, 0, 1); ideal points have W = 0Vanishing points (Part 4); projective → affine → metric upgrade and self-calibration (Part 16)
Line as meet of 2 planes{ X̃ : π₁·X̃ = π₂·X̃ = 0 }Line reconstruction; the trifocal tensor (Part 12)
Plücker paird = W₁X₂ − W₂X₁, m = X₁ × X₂Line features in SLAM / SfM; line-based triangulation; trifocal tensor (Part 12)
Constraintd · m = 0 (Klein quadric in P⁵)Enforcing that a 6-vector is a valid line during estimation
DOF6 − 1 (scale) − 1 (constraint) = 4Minimal line parameterization for nonlinear optimization (Part 15)
Plücker matrixL = X̃₁X̃₂ᵀ − X̃₂X̃₁ᵀ, skew rank 2; Lπ = 0 ⇔ π ∋ lineIncidence tests; line-plane transfer; transform L′ = HLHᵀ
Image of a linel = (P X̃₁) × (P X̃₂)Line features across views; line-based SfM; degenerate when the line passes through the camera center
With points, planes and Plücker lines in hand, the camera itself is the last missing piece: a single 3×4 matrix P = K[R|t] whose center is the null space of P, and whose back-projection inverts the lost depth. Continue: the pinhole camera →