all lessons / computer_vision_3d / 13 · generative 3D & systems lesson 13 / 13

Generative 3D, dynamics, and 3D systems

Every lesson so far — from the depth sensors of lesson 03 through the radiance fields of lesson 09 and the Gaussians of lesson 10 to the learned depth of lesson 12 — recovered 3D from observations: something out there was measured, and we inverted the measurement. This capstone flips the arrow. Now there is no captured scene: we want to generate 3D from a prompt or a single image, to handle scenes that move (time — the fourth dimension), and to ship the result under real latency, memory, and sensor constraints. Then we name the metrics that decide whether any of it worked — and expose the ones that quietly lie.

The plan
Six moves, then a wrap-up. (1) Name the obstacle that makes generation different from recovery: there is no ImageNet-scale 3D dataset, so the whole subfield is organized around three routes past the data gap. (2) Route 1 — lift a 2D prior into 3D (Score Distillation / DreamFusion): optimize a NeRF or 3DGS so its renders please a frozen text-to-image diffusion model, using the differentiable renderer of lesson 01 §4. (3) Route 2 — native 3D generation: train directly on 3D data, with the triplane as the workhorse backbone. (4) Route 3 — feed-forward reconstruction (LRM): a transformer that maps images → 3D in one pass, amortizing the per-scene optimization of lessons 09–10. (5) Dynamics / 4D: deformation fields, 4D Gaussians, and parametric human models (SMPL/FLAME/MANO). (6) Systems & deployment — the 3D analog of CV lesson 19: representation-by-product, the evaluation metrics and their pitfalls, and the silent failures (calibration, time-sync, annotation cost, sim-to-real). We close by folding all ten lessons back into lesson 01's one loop.

1 · The obstacle for generation: there is no ImageNet-scale 3D

Recovery and generation look symmetric but are not, and the asymmetry is a data problem. To recover 3D you point a sensor at the world and it hands you geometry (lesson 03), or you photograph a scene from many angles and invert the renderer (lessons 09–10). To generate 3D you need a model that has seen enough 3D to know what a plausible chair, dragon, or street looks like from every angle. And that is exactly what does not exist at scale.

Count the orders of magnitude. Image-text pretraining runs on billions of image-caption pairs scraped from the web (LAION-scale); the 2D generative models of CV lesson 17 are trained on that firehose. The largest curated 3D asset collections — Objaverse and its successors — are on the order of a million to ten million objects, and most are untextured, inconsistently scaled, or low quality. 3D assets are expensive: each is authored by an artist or reconstructed by a capture rig, whereas an image is a single button-press. So the field faces a hard fact: you cannot train a 3D generator the way you train an image generator, because the 3D data is roughly three orders of magnitude scarcer.

The organizing question
Every method in generative 3D is an answer to one question: where do you get the 3D supervision from, given that there is no web-scale 3D? There are exactly three routes, and §2–§4 are one each. Route 1 borrows a 2D model that was trained at web scale and distills it into 3D (no 3D data). Route 2 trains on whatever 3D data exists, directly. Route 3 trains a network on multiview/3D data to reconstruct in a single forward pass. Read the rest of the lesson as: how each route pays the data bill.

RouteWhere the 3D signal comes fromLandmarkPer-asset costMain failure
1 · Lift a 2D priora frozen 2D diffusion model (no 3D data at all)DreamFusion (SDS)slow — per-asset optimizationJanus / oversaturation / low diversity
2 · Native 3Ddirect 3D data (Objaverse-scale)EG3D / triplane diffusiontrain once, sample fastlimited by 3D data scale & quality
3 · Feed-forward reconlarge multiview / 3D datasets, amortizedLRMseconds — one forward passbounded by training distribution

2 · Route 1 — lift a 2D prior into 3D (Score Distillation / DreamFusion)

The first route is the cleverest, because it needs zero 3D data. The idea: a pretrained text-to-image diffusion model (CV lesson 17) already encodes, implicitly, what objects look like from every viewpoint — it has seen millions of chairs from every angle. So instead of training a 3D generator, distill that 2D knowledge into a single 3D asset by optimization.

Set up the loop exactly as in lesson 01 §1, but with a generative critic in place of a captured image. Let the thing we optimize be a 3D representation with parameters θ — a NeRF (lesson 09) or a set of 3D Gaussians (lesson 10). Repeat:

This is Score Distillation Sampling (SDS), the engine of DreamFusion. Concretely, noise the render, let the diffusion U-Net \hat{ε}_\phi predict the noise, and the SDS gradient of the loss L w.r.t. the 3D parameters is (dropping a per-step weight w(t)):

θ LSDS = 𝔼t,ε[ w(t)\,(\hat{ε}φ(xt; y, t) − ε)\;·\;∂x/∂θ ] .

Read it piece by piece. The bracket (\hat{ε}φ − ε) is "predicted noise minus the noise we actually added" — the direction in image space that raises the render's likelihood under the diffusion prior for prompt y. The factor ∂x/∂θ is the Jacobian of the renderer: it carries that image-space push back into 3D parameters. The key trick that makes SDS cheap is that it skips differentiating through the diffusion U-Net's own Jacobian (which would be enormous) — it uses the noise-residual directly as the gradient. No 3D data appears anywhere: the loop distills a 2D model into one 3D asset.

The trap: the multi-face "Janus" artifact
SDS supervises each rendered viewpoint independently against a 2D prior that has an overwhelming bias toward canonical front views (the web is full of faces and product fronts, not backs). So every viewpoint independently tries to become a front — and you get an animal with a face on the back of its head, or a person with two fronts. This is the Janus problem (named for the two-faced Roman god), and it is the signature failure of naïve SDS. Its cause is structural: a per-view 2D prior has no notion of a consistent 3D object. Alongside it: oversaturated, cartoonish colors and low diversity (many prompts collapse to similar looks), both traceable to the high guidance weights SDS needs to get a usable gradient.

Fixes, and why they work. Two lines of attack, each removing one root cause:

The whole route is remarkable precisely because of the data argument in §1: it manufactures a 3D asset from a model that never saw 3D. Its cost is the flip side — it is a per-asset optimization, minutes to hours each, exactly the expense that Route 3 will amortize away.

3 · Route 2 — native 3D generation

The second route confronts the data gap head-on: train a generative model directly on 3D data (Objaverse and friends). The generative machinery is the same as in 2D — diffusion or autoregression — only the data type changes. The question becomes what 3D representation do you generate?, and the answer recapitulates the representation zoo of lesson 01:

The representation that made 3D-aware generation practical is the triplane (introduced by EG3D). The obstacle is exactly lesson 01 §3: a dense 3D feature volume is O(N³) and blows up memory. The triplane factors that volume into three orthogonal 2D feature planes — one each in the XY, XZ, and YZ planes. To read the feature at any 3D point (x,y,z), project it onto all three planes, bilinearly sample each, sum (or concatenate) the three feature vectors, and decode with a tiny MLP into color and density:

f(x,y,z) = \text{MLP}\big(\,Pxy(x,y) + Pxz(x,z) + Pyz(y,z)\,\big) .

Three wins fall out at once, and they are why the triplane is the backbone of so many 3D-aware GANs and diffusion models. Memory drops from O(N³) to O(3N²) — surface-scale, not volume-scale. The planes are ordinary 2D feature maps, so you can generate them with a standard 2D CNN or 2D diffusion backbone, reusing all the mature 2D generative machinery. And the tiny decoder MLP keeps the whole thing a continuous field you can volume-render (lesson 09) and differentiate. The triplane is, in effect, the compromise the field found between the storage explosion of voxels and the query cost of a pure MLP.

4 · Route 3 — feed-forward reconstruction (LRM)

Routes 1 and 2 still, in the image→3D setting, tend to optimize per scene. Route 3 removes that entirely. A Large Reconstruction Model (LRM) is a transformer trained on large multiview/3D datasets that maps one or a few images directly to a 3D representation in a single forward pass — typically a triplane (as in §3) or a set of Gaussians (lesson 10) — in seconds, with no per-scene optimization.

This is the sharpest contrast in the whole track. Recall how lessons 09–10 produce a 3D asset: you take posed images of one scene and run gradient descent for minutes-to-hours on that scene's parameters, from scratch, every time. NeRF and 3DGS are per-scene optimizations — brilliant fits, but the work is not reusable across scenes. LRM amortizes that optimization into a network: it pays the cost once, at training time, over many scenes, and thereafter reconstruction is a forward pass. Put side by side:

NeRF / 3DGS (lessons 09–10)LRM (feed-forward)
What is optimizedthe 3D parameters of this one scenenetwork weights, once, over many scenes
Cost at inferenceminutes–hours of gradient descent per sceneone forward pass — seconds
Views neededmany posed viewsone or a few images
Quality ceilingas good as the optimization & views allowbounded by the training distribution
Outputa radiance field / Gaussians for that scenea triplane or Gaussians, predicted directly

The trade is generalization for speed: an LRM cannot exceed what its training data taught it, whereas a per-scene NeRF will happily overfit any scene you give it. But for the image→3D problem — "here is a photo, give me the object in 3D, now" — feed-forward amortized reconstruction is the current sweet spot, and it is where the field's momentum sits.

5 · Dynamics — the fourth dimension (4D)

Everything up to here, generation included, assumed a static scene. Real scenes move: people walk, cloth flaps, cars drive. Adding time turns 3D into 4D, and the representations of lessons 09–10 extend in two natural ways.

Dynamic NeRF / 4D Gaussian Splatting. Two strategies dominate, and they map onto the implicit/explicit split:

Parametric models for the special case that matters most: humans. A general deformation field is unconstrained; but humans (bodies, faces, hands) are so common and so structured that the field built low-dimensional parametric mesh generators for them, fit from data:

ModelCoversParameters
SMPLfull bodypose θ (joint rotations) + shape β
FLAMEface / headexpression + shape + pose
MANOhandshand pose + shape

Each is a differentiable function M(θ, β) → \text{mesh}: feed a few dozen numbers, get a full mesh. Crucially the rotations here are exactly the SO(3) joint rotations of lesson 02 — SMPL's pose θ is a stack of axis-angle rotations, optimized on the manifold. Because the parameter count is tiny, you fit the model to images or point clouds by optimizing those few parameters (the inverse-rendering loop of lesson 01, restricted to a low-dimensional prior). This is what powers markerless motion capture, avatar/AR try-on, and animation: the parametric model supplies the missing 3D prior that makes an otherwise ill-posed fit well-posed.

6 · 3D systems and deployment — the CV 19 analog

This section is to this track what CV lesson 19 was to the 2D track: the shift from "does the method work in a paper" to "does the system survive contact with a product." Three parts: representation by product, evaluation metrics and their pitfalls, and the silent failures nobody puts in the paper.

(a) Representation by product

The whole track's refrain — choose the representation from the constraint, not the fashion (lesson 01) — is decided here. Four products, almost no shared design choices:

ProductRepresentationHard constraintWhy
AR / VRtextured meshes, level-of-detail streamingtight memory + battery; GPU-native drawmobile GPUs rasterize meshes cheaply; LOD streams only what's visible
Autonomous vehiclesLiDAR points → voxels / BEV / occupancyhard real-time, multi-sensor fusiondetection/planning run in bird's-eye-view; occupancy handles unknown objects (lesson 11)
Content / graphicsmeshes, or Gaussians for captureartist editability + tool ecosystemmeshes plug into DCC tools; Gaussians (lesson 10) capture real scenes fast
RoboticsSDF / TSDF, occupancy gridsfast collision queries for planningan SDF answers "how far to the nearest surface?" in O(1) — ideal for motion planning

Two of these deserve a note. Robotics leans on TSDF fusion (truncated signed distance function) — the KinectFusion recipe: integrate each depth frame into a running voxel SDF, averaging out sensor noise into a clean surface you can both render and query for collisions. And autonomous stacks increasingly predict occupancy directly (lesson 11) precisely because a bounding-box detector fails on the object classes it was never trained on, whereas "is this volume occupied?" degrades gracefully.

(b) Evaluation metrics — and their pitfalls

Each 3D task has its own metric; you must know what each measures and where each lies.

What you evaluateMetricMeasures
Geometry (shape)Chamfer distance, F-score@τChamfer: mean bidirectional nearest-neighbor distance. F-score: precision/recall of points within threshold τ
Novel-view synthesisPSNR, SSIM, LPIPSpixel error; structural similarity; learned perceptual distance
DepthAbsRel, δ<1.25mean relative error; fraction of pixels within a 25% ratio band
3D detection3D mAP, nuScenes NDSmean average precision over 3D IoU; NDS blends AP with translation/scale/orientation errors
6-DoF poseADD, ADD-Smean 3D distance between predicted and GT model points (ADD-S uses nearest-neighbor, for symmetric objects)
The trap: a metric can pass while the result is wrong
Two pitfalls to say out loud in an interview. (1) Chamfer distance is dominated by outliers. Because it averages nearest-neighbor distances, a single stray point far from the surface adds a huge term and spikes the score — even if the rest of the reconstruction is perfect. Chamfer also rewards coverage over fine detail: a blobby, over-dense prediction that blankets the shape can score well while missing every crisp edge. The F-score@τ is more robust — it counts what fraction of points fall within τ, so one far outlier costs at most one point of precision, not an unbounded distance. (2) PSNR ≠ perceptual quality. A slightly blurry render can beat a sharp one on PSNR because blur has low pixel error, yet look worse to a human — which is exactly why LPIPS (a learned perceptual metric) exists and why novel-view papers report all three. The widget below makes pitfall (1) tangible: add one outlier and watch Chamfer explode while the F-score barely moves.

(c) The silent failures

These sink real 3D systems and appear in no benchmark:

Where this leaves you — the whole track in one line

Step all the way back. Lesson 01 claimed the entire field is a single loop: pick a 3D representation → render it → compare to observations → backprop the error into the representation, and it closes only if the renderer is differentiable. Every one of the ten lessons was a move inside that loop. Lesson 02 gave us the SE(3) machinery to place things in it and optimize their poses on the manifold. Lessons 03–05 supplied the observations (depth, point clouds), aligned them (ICP), and turned them into surfaces (meshes, SDFs). Lessons 09–10 built the differentiable renderers — volume rendering / NeRF, then Gaussian Splatting — that let ordinary images close the loop, and 08–09 learned across scenes (3D backbones, detection) and pulled depth from single images.

This capstone did the one thing the loop had left implicit. Every prior lesson ran the loop with the observations in hand — the arrow pointed from a measured scene back to its 3D. Generation runs the same loop with the observation replaced by a prior: SDS swaps the captured image for a frozen 2D diffusion critic; native 3D and LRM move the optimization to training time so inference is a forward pass; 4D adds time to the representation; and the systems section decides which representation, rendered how, judged by which metric, a real product can afford. There is no new machine here — only the recognition that recovering 3D and generating 3D are the same inverse-rendering loop, differing only in whether the thing on the right-hand side is a photograph or a prior. That is the whole track, and it points back to where it started: the track index and its four questions — representation, rendering, recovery, system.

Takeaway
Generation differs from recovery because there is no ImageNet-scale 3D — 3D assets are ~1000× scarcer than images — so the subfield is three routes past the data gap. Route 1 (SDS / DreamFusion) optimizes a NeRF/3DGS so its renders from random views please a frozen 2D diffusion prior, backpropagating through the differentiable renderer (lesson 01 §4); it needs no 3D data but suffers the multi-face Janus artifact, oversaturation, and low diversity, fixed by multiview-aware diffusion (MVDream) and variational SDS (ProlificDreamer). Route 2 (native 3D) trains directly on 3D data, with the triplane (EG3D) factoring an O(N³) volume into three 2D feature planes decoded by a tiny MLP. Route 3 (LRM) is a transformer mapping images → 3D in one forward pass — amortizing the per-scene optimization of NeRF/3DGS. Dynamics/4D add time via deformation fields or per-Gaussian trajectories, plus parametric human models (SMPL/FLAME/MANO). For systems: representation follows the product (AR meshes, AV occupancy/BEV, robotics TSDF); evaluate with the right metric while knowing its lie — Chamfer is outlier-dominated (F-score is robuster), PSNR ≠ perceptual (hence LPIPS); and the real killers are calibration, time-sync, annotation cost, and sim-to-real, none of which a model can fix. The whole track is one loop: recovering and generating 3D are the same inverse rendering, differing only in whether the right-hand side is a measurement or a prior.
Chamfer distance vs F-score — why one metric lies
A fixed ground-truth shape (blue points along a curve) and a prediction (orange, a copy you perturb). We compute both directions of Chamfer, the symmetric Chamfer, and the F-score@τ (harmonic mean of precision and recall within threshold τ). Faint gray links show a few nearest-neighbor matches. Now click "add outlier": one stray point sends the Chamfer distance soaring while the F-score barely flinches — the §6(b) pitfall, made tangible. Then shrink τ to watch a blobby, over-dense prediction lose F-score even when one Chamfer direction looks fine.
outliers: 0
Chamfer(GT→pred)
Chamfer(pred→GT)
Symmetric Chamfer
F-score@τ
Show the core JS
// nearest-neighbour distance from point p to set Q (brute force)
function nnDist(p, Q){
  var best = Infinity;
  for (var i=0;i<Q.length;i++){
    var dx=p.x-Q[i].x, dy=p.y-Q[i].y, d=dx*dx+dy*dy;
    if (d<best) best=d;
  }
  return Math.sqrt(best);
}
// directional Chamfer = MEAN of nearest-neighbour distances (one direction)
function chamferDir(A, B){
  var s=0; for (var i=0;i<A.length;i++) s+=nnDist(A[i], B); return s/A.length;
}
var cGP = chamferDir(GT, PRED);        // GT → pred
var cPG = chamferDir(PRED, GT);        // pred → GT
var symmetric = 0.5*(cGP + cPG);       // symmetric Chamfer (average form)

// F-score@τ = harmonic mean of precision and recall of points within τ
function frac(A, B, tau){               // fraction of A within tau of some B point
  var n=0; for (var i=0;i<A.length;i++) if (nnDist(A[i],B)<=tau) n++;
  return n/A.length;
}
var precision = frac(PRED, GT, tau);    // preds that are near a GT point
var recall    = frac(GT, PRED, tau);    // GT points that are covered by a pred
var F = (precision+recall>0) ? 2*precision*recall/(precision+recall) : 0;

// KEY: adding one far outlier to PRED spikes chamferDir(PRED,GT) (its NN dist is huge,
//   and it enters the MEAN) while precision drops by only 1/|PRED| → F-score barely moves.

Interview prompts