A compact, self-contained PyTorch demonstrator for coordinate-based neural
fields as continuous representations of 3D geometry. A multilayer perceptron
It is the bridge from discrete geometry-processing meshes to the continuous, learned representations of modern 3D computer vision (neural SDFs, DeepSDF, NeRF). The same coordinate-network core drives two families:
- a neural signed distance field (
$f_\theta:\mathbb{R}^3\to\mathbb{R}$ ), rendered by sphere tracing, and - a NeRF-style radiance field ($x\mapsto(\sigma,\mathbf{c})$), rendered by emission–absorption volume integration.
The defining choices:
-
A shape is a function, not a mesh. Geometry lives in the weights
$\theta$ of a small MLP. It has no resolution: it is queried at any real coordinate, and meshed by marching cubes only when an explicit surface is wanted. -
Normals are autodiff, not stencils. The surface normal is
$\nabla_x f_\theta$ viatorch.autogradwithcreate_graph=True, so a renderer that shades with normals stays differentiable end-to-end. - Fitting is gradient descent through the renderer. Because the sphere march is an unrolled differentiable computation, the field can be learned from images alone (inverse rendering), not just from ground-truth distances.
Mathematical background, including the mesh ↔ SDF ↔ neural-field duality and the IGR / Eikonal recipe, is written up in
docs/theory.md.
| Stage | Module | What it does |
|---|---|---|
| Input encoding | encoding.py |
NeRF positional (Fourier-feature) encoding |
| The neural field | field.py |
Coordinate MLP: neural SDF or density/colour field; autodiff normals |
| Target geometry | geometry.py |
Analytic SDFs + CSG, samplers, marching-cubes mesh extraction |
| Differentiable rendering | render.py |
Sphere tracing + NeRF volume rendering; cameras and rays |
| Objectives | losses.py |
SDF, Eikonal, normal (geometric); depth, silhouette (rendered) |
| Optimisation | training.py |
fit_geometric (3D supervision) and fit_rendered (inverse render) |
A neural field is a small MLP on raw coordinates. With a single output it is a signed distance function whose zero level set is the surface,
The (normalised) gradient is the surface normal, obtained by autodiff:
To make the learned field an honest distance field, it is regularised towards
the Eikonal equation
$$ \mathcal{L} = \lambda_\text{sdf}, \mathbb{E}\big[|f_\theta(x) - d(x)|\big]
- \lambda_\text{eik}, \mathbb{E}\big[(\lVert\nabla_x f_\theta\rVert - 1)^2\big]
- \lambda_\text{nrm}, \mathbb{E}{x\in\mathcal{S}}\big[1 - n\theta!\cdot n\big]. $$
A geometric initialisation starts
Sphere tracing advances each camera ray by the field's own value, which is a safe step length because it is the distance to the surface:
Unrolling the march makes the hit point, depth, normals, and silhouette
differentiable in
All figures are produced on CPU by the scripts in examples/. A fitted field,
meshed at three resolutions, can be inspected interactively in the
live demo (GitHub
Pages, plain Three.js).
Geometric fit — a neural SDF fit to a target by distance regression +
Eikonal, then sphere-traced (examples/fit_geometric.py):
Continuous representation — the same learned field as a dense SDF slice
(with its zero level set) and meshed by marching cubes at three resolutions; the
triangle count is chosen at extraction time, not baked into the model
(examples/manifold_continuity.py):
Inverse rendering — a field learned from depth + silhouette images alone,
with gradients flowing back through the sphere march
(examples/inverse_rendering.py):
uv sync --extra dev # environment (PyTorch, etc.)
# Fit a neural SDF to a shape by direct geometric supervision:
uv run python examples/fit_geometric.py --target blob --iters 2000
# Learn the same kind of field from images only (inverse rendering):
uv run python examples/inverse_rendering.py --target torus --iters 1200
# The "continuous manifold" figure (SDF slice + multi-resolution meshing):
uv run python examples/manifold_continuity.py --target blob
# Mesh a fitted field to OBJ (needs the 'mesh' extra):
uv run python scripts/export_mesh.py --target blob --resolution 192 --out blob.objIn code:
import torch
from neural_fields import CoordinateMLP, FieldConfig, TrainConfig
from neural_fields import fit_geometric, make_target, render_image, Camera, RenderConfig
field = CoordinateMLP(FieldConfig()) # (x,y,z) -> signed distance
history = fit_geometric(field, make_target("torus"), TrainConfig(n_iters=2000))
img = render_image(field, Camera.look_at((1.6, 1.1, 1.8)), RenderConfig()) # (H, W, 3)
sdf = field.sdf(torch.zeros(1, 3)) # query the continuous field anywhereAvailable targets: sphere, box, torus, blob, csg.
neural-implicit-fields/
├── src/neural_fields/
│ ├── encoding.py NeRF positional / Fourier-feature encoding
│ ├── field.py CoordinateMLP (neural SDF) + RadianceField; autodiff normals
│ ├── geometry.py analytic SDFs, CSG, samplers, marching-cubes extraction
│ ├── render.py differentiable sphere tracing + NeRF volume rendering
│ ├── losses.py SDF, Eikonal, normal, depth, silhouette
│ ├── training.py fit_geometric (3D) and fit_rendered (inverse rendering)
│ ├── config.py FieldConfig / RenderConfig / TrainConfig dataclasses
│ └── utils.py seeding, device, checkpoints
├── tests/
│ ├── test_encoding.py encoding shapes/values
│ ├── test_field.py forward shapes, init, gradients, radiance head
│ ├── test_geometry.py analytic SDF values, CSG, sampling, marching cubes
│ ├── test_render.py rays, sphere-trace depth, soft mask, differentiability
│ ├── test_losses.py each loss term
│ ├── test_grad.py torch.autograd.gradcheck (first/second order)
│ └── test_training.py both fit pipelines reduce their loss
├── examples/ runnable figures (geometric, inverse, manifold)
├── scripts/ fit.py CLI + export_mesh.py
├── web/ static Pages demo (Three.js viewer of the fitted field)
├── assets/ committed result figures (referenced above)
├── docs/theory.md coordinate networks as continuous manifold representations
├── CITATION.cff
├── CHANGELOG.md
└── .github/workflows/ ci.yml (ruff + mypy + pytest, 3.10–3.12) + pages.yml (deploy)
uv run ruff check . # lint (E, F, W, I, UP, B, SIM)
uv run ruff format . # format (line length 100)
uv run mypy # type-check src/
uv run pytest # 42 tests, incl. gradient checks + convergenceGradient correctness is a first-class invariant: any new differentiable
operation comes with a torch.autograd.gradcheck test, since a silently broken
gradient (an in-place op, or a non-differentiable step slipping into the ray
march) is the most common and costly bug in differentiable-geometry code.
See CITATION.cff. This work builds on Implicit Geometric
Regularization (Gropp et al., 2020), DeepSDF (Park et al., 2019), NeRF
(Mildenhall et al., 2020), and sphere tracing (Hart, 1996).
MIT — see LICENSE.


