Cubic Surfaces From Blowups
The materials below are based on a collaborative illustration with Gabriel Ddorfsman-Hopkins and Steve Trettel, exhibited at Creation: Between Art and Mathematics at the Maison Poincaré museum in Paris. Steve also put together a really nice applet here.
Blowups and the Cayley–Salmon Theorem
In algebraic geometry, blowups are an operation used, among other things, to resolve singularities or separate intersecting curves. Geometrically, blowing up a point on a surface replaces that point with a copy of \(\mathbb{P}^1\), whose points correspond to the possible directions of lines passing through the point.
For example, we can define the blowup of the plane at a point \(P \in \mathbb{P}^2\) formally as the incidence variety \[ \mathrm{Bl}_{P}({\mathbb{P}^2}) \mathrel{:=}\left\{ (Q, \ell) \in \mathbb{P}^2 \times (\mathbb{P}^2)^\vee : Q \in \ell, P \in \ell \right\}. \] This comes equipped with the blowup morphism \[ \begin{aligned} \pi : \mathrm{Bl}_{P}({\mathbb{P}^2}) &\longrightarrow \mathbb{P}^2 \\ (Q,\ell) &\longmapsto Q. \end{aligned} \] Away from \(P\), this morphism is an isomorphism: its inverse is given by the canonical rational map \[ \begin{aligned} \mathbb{P}^2 &\dashrightarrow\mathrm{Bl}_{P}({\mathbb{P}^2}) \\ Q &\mapsto (Q,\overline{PQ}), \end{aligned} \] defined for every \(Q \neq P\). On the other hand, the fiber over \(P\) is \[ \pi^{-1}(P) = \left\{(P,\ell):P\in\ell\right\} \cong \mathbb{P}^1, \] which is the exceptional divisor.
The Cayley–Salmon theorem tells us that every smooth cubic surface contains exactly 27 lines. Moreover, a classical result tells us that every smooth cubic surface is isomorphic to the blowup up six points in \(\mathbb{P}^2\), provided they are in general position—meaning no three points are collinear, and all six do not lie on a single conic. This description gives a geometric way to see where the 27 lines come from!
Interactive Applet
Drag the blowup points in the projective plane (left) to see how they govern the geometry and the 27 lines of the resulting cubic surface (right). When you grab a point, a degeneracy locus appears! These are teaching us:
- Some (11) of the curves in \(\mathbb{P}^2\) which pass to lines on the cubic surface—they light up in the right pane!
- The places where, should we drag the point through them,1 the blow-ups fail to be in general position.
Mapping to the Surface
We can construct the blowup \(\phi : \mathbb{P}^2 \dashrightarrow\mathbb{P}^3\) explicitly in terms of cubic polynomials. The space of all possible homogeneous cubic forms in three variables (\(t_0, t_1, t_2\)) is spanned by 10 monomials. If we demand that our cubic curve passes through one of our blowup points in \(\mathbb{P}^2\), we impose a single linear constraint on the coefficients; there is a 4-dimensional vector space of cubic forms that vanish at all 6 blowup points. If we write \((f_0, f_1, f_2, f_3)\) as an ordered basis2 for this space, these four polynomials give us exactly the coordinates we need to map our plane into projective space: \[ \phi(t_0, t_1, t_2) = [f_0(t_0, t_1, t_2) : f_1(t_0, t_1, t_2) : f_2(t_0, t_1, t_2) : f_3(t_0, t_1, t_2)] \]
Where do the 27 Lines Come From?
We can make sense of why certain curves in \(\mathbb{P}^2\) become lines on the cubic surface using Bézout’s Theorem.
If we slice our cubic surface in \(\mathbb{P}^3\) with a generic plane, the intersection is a degree-\(3\) curve (a plane cubic). The equation for a plane in \(\mathbb{P}^3\) is linear: \(Ax + By + Cz + Dw = 0\). If we pull this plane back to \(\mathbb{P}^2\) through our map \(\phi\), we substitute our polynomials to get \(A f_0 + B f_1 + C f_2 + D f_3 = 0\). Because every \(f_i\) was explicitly constructed to equal zero at our six blowup points, this linear combination must also equal zero at those points. Therefore, the pre-image of any plane section is a cubic curve in \(\mathbb{P}^2\) that passes through all six points.
By Bézout’s theorem, a generic curve of degree \(d\) in \(\mathbb{P}^2\) will intersect this cubic in \(3d\) points. However, if the curve already passes through \(k\) of our blowup points, \(k\) of those intersections are “used up” at the blowup sites. The remaining \(3d - k\) intersections happen away from the blowups, meaning the mapped curve in \(\mathbb{P}^3\) will intersect our slicing plane exactly \(3d - k\) times. To map a curve to a line in \(\mathbb{P}^3\), we need \(3d - k = 1\). This gives us our 27 lines via three distinct families:
- 15 Pair Lines: There are 15 distinct ways to draw a line through any 2 of our 6 blowup points. A line has degree \(d=1\) and passes through \(k=2\) points, and \(3(1)-2=1\).
- 6 Conic Lines: There are 6 ways to draw a conic section through 5 of the 6 points (leaving one point out). A conic has degree \(d=2\) and passes through \(k=5\) points, and \(3(2)-5=1\).
- 6 Exceptional Lines: The blowup process replaces each of the 6 points with a \(\mathbb{P}^1\) representing its tangent directions, yielding the final 6 lines.
Putting it All Together
Given our six blow-up points in general position, we want to actually put a cubic surface with all of its lines on the screen! We can accomplish this as follows:
Finding the Lines
For the 15 pair lines and 6 conic lines, we pick two arbitrary points on the corresponding curve, map them through \(\phi\), and draw a line (in \(\mathbb{P}^3\)) connecting the results.
For the 6 exceptional lines, we can’t map the blowup points directly because \(\phi\) evaluates to \([0:0:0:0]\); instead, we use the Jacobian. By evaluating the gradient of our four polynomials at each point, we can push these tangent directions forward to map out the exceptional line in \(\mathbb{P}^3\).
Recovering the Implicit Equation
Our map gives us a parameterized surface, but attempting to render it directly is messy—we are blowing up the surface, which is inherently discontinuous at the blowup points! To render it efficiently, we want to determine the cubic polynomial \(F(x, y, z, w)\) which actually cuts out the surface by its zero set. A general cubic equation in \(\mathbb{P}^3\) has 20 terms: \[ C_0 x^3 + C_1 x^2 y + C_2 x^2 z + \dots + C_{19} w^3 = 0 \] To find the 20 unknown coefficients \(C_i\), we use 19 random points in \(\mathbb{P}^2\) and map them to points \([X_i,Y_i,Z_i,W_i] \in \mathbb{P}^3\) using \(\phi\). Because these points are guaranteed to lie on our surface, plugging them into our 20-term polynomial must equal zero! This sets up a \(19 \times 20\) system of linear equations:
\[ \begin{bmatrix} X_1^3 & X_1^2 Y_1 & X_1^2 Z_1 & \dots & W_1^3 \\ X_2^3 & X_2^2 Y_2 & X_2^2 Z_2 & \dots & W_2^3 \\ \vdots & \vdots & \vdots & \ddots & \vdots \\ X_{19}^3 & X_{19}^2 Y_{19} & X_{19}^2 Z_{19} & \dots & W_{19}^3 \end{bmatrix} \begin{bmatrix} C_0 \\ C_1 \\ \vdots \\ C_{19} \end{bmatrix} = \begin{bmatrix} 0 \\ 0 \\ \vdots \\ 0 \end{bmatrix} \]
By calculating the null space of this matrix, we determine the coefficients of our implicit surface.
Raymarching
Finally, a WebGL fragment shader takes this 20-coefficient equation and renders it (in an affine chart) using a technique called raymarching. The shader casts mathematized rays from the camera, through every pixel on the screen, into a 3D bounding box. As the ray marches through the scene, it evaluates \(F(x,y,z,1)\) at each point: when the value changes sign, the shader knows the ray just punctured the implicit surface. It performs a rapid binary search to hone in on the exact zero-crossing, calculates the 3D gradient \(\nabla F\) at that point to determine how the surface is angled, and applies realistic lighting using techniques from computer graphics. With a modern GPU, the result is a smooth cubic surface that we can explore in real time!
Footnotes
This will cause the surface to behave erratically!↩︎
You might notice abrupt discontinuities in the surface when tinkering with the applet, even away from the degeneracy locus! This is caused by our algorithms for determining the \(f_i\) (recall all that business about “pivots” from linear algebra class).↩︎