An exploration of Derived Surface Shading (DSS) - a family of techniques for lighting voxel models by the surface they imply rather than by the cube faces they are made of.
This repository has two parts:
whitepaper/- the motivation and theory. This is the heart of the project: it defines DSS, derives the normal-generation methods, and lays out the design space.src/- a small WebGL voxel editor (a MagicaVoxel-inspired UX) built to implement those ideas and explore them interactively.
The whitepaper is the why; the app is a hands-on way to see and feel the what.
Identical voxel geometry, two shading approaches: traditional cube-face normals (left) make the lattice obvious, while derived surface normals (right) communicate the implied sphere. See the whitepaper for the full set of figures.
Traditional voxel renderers light each visible cube face using its geometric normal (+X, -Y,
…). This makes lighting describe the voxel lattice - emphasizing stair-stepping - instead of the
shape the voxels represent. A voxel model actually contains two representations at once: explicit
cube geometry, and an implicit surface defined by the occupancy field. DSS keeps the cube geometry
(and silhouette) exactly as-is, but derives surface normals from the occupancy field, so that
lighting communicates the larger-scale form. See the
whitepaper for the full treatment.
The problem splits into two independent axes:
- Normal-field generation - how to extract surface orientation from occupancy.
- Density gradient - the direction from solid space toward empty space (
N = ∇ρ). - Occupancy centroid - the direction away from nearby occupied mass (
N = p − C).
- Density gradient - the direction from solid space toward empty space (
- Normal-field application - how that orientation is used while shading.
- Cube faces - classic per-face geometric normals (the baseline).
- Per-voxel - one derived normal per voxel.
- Vertex-interpolated - derived normals blended at cube corners for continuous, smooth-shaded lighting across faces.
Both DSS methods use an adjustable kernel radius (1 → 3³, up to 4 → 9³): small kernels
preserve local detail, large kernels communicate global form.
The app lets you build voxel models and toggle between shading approaches in real time so you can directly compare the baseline against DSS.
Features:
- Sculpt mode - attach / erase / paint / pick tools, with voxel / box / line / face brushes, adjustable brush size, and X/Y/Z mirror symmetry.
- Tri-view mode - draw top / front / side silhouettes on planes; the model becomes their intersection.
- DSS shading controls - pick the normal field (gradient vs. centroid), the application mode (cube / per-voxel / vertex-interpolated), and the kernel radius live.
- Derived ambient occlusion - occupancy-based AO with per-voxel or vertex-interpolated modes, adjustable radius and intensity.
- Starter shapes, a customizable palette, and .vox import (MagicaVoxel files).
- Dynamic lighting (with optional auto-rotation), ground grid, voxel edges, undo/redo, and live voxel/face stats.
src/voxel/dss.ts- the core of the paper: gradient and centroid normal fields, the kernel/Gaussian weighting, the normal cache, and vertex-interpolated normals.src/voxel/ao.ts- occupancy-derived ambient occlusion.src/voxel/meshBuilder.ts- builds the cube mesh and applies the chosen normals/AO.src/engine/- the Three.js engine, viewport interaction, and tri-view planes.
Requires Node.js (18+).
npm install
npm run dev # start the dev server (Vite)Then open the printed local URL in a browser.
Other scripts:
npm run build # type-check and build for production
npm run preview # preview the production build
npm run typecheck # type-check only
npm run lint # run ESLintThe whitepaper figures are produced from the project's own code so they stay faithful to the implementation:
- 3D render figures are drawn by a small harness in
figures/that reuses the realbuildVoxelMesh/ DSS code. With the dev server running, openhttp://localhost:<port>/figures/?fig=N(N = 1, 7, 8, 9, 12, 13) and screenshot the figure. Figure 13 loads the real.voxassets fromsrc/examples/. - Conceptual diagrams (the SVG cross-sections) are generated by
figures/gen-diagrams.mjs:
node figures/gen-diagrams.mjs # writes whitepaper/figures/figure-{2,5,6,11}.svg- The dynamic-lighting animation (
lighting-phasing.gif) is recorded by a small capture server that renders the orbiting split-view and encodes the frames to a GIF with a pure-JS encoder (no ffmpeg needed):
node figures/record-gif.mjs # then open http://localhost:7788/ once- React + TypeScript
- Three.js for WebGL rendering
- Zustand for editor state
- Vite for tooling
This is a research prototype. The whitepaper outlines several open directions - larger kernels, alternative weighting functions, GPU normal generation, and DSS combined with palette-quantized lighting - that remain to be explored.
The DSS method library is released under the MIT License. This covers the
core algorithm and data files in src/voxel/:
dss.ts- gradient & centroid normal fields, kernel weighting, normal cache, and vertex-interpolated normalsao.ts- occupancy-derived ambient occlusionmeshBuilder.ts- cube mesh construction with derived normals/AO appliedVoxelData.ts- sparse voxel volume / occupancy fieldpalette.ts- color palette model used by the above
Each of these files carries an SPDX-License-Identifier: MIT header.
The editor application is intentionally excluded. Everything else in the repository - the React
UI (src/components/, src/state/), the Three.js engine
(src/engine/), the editor-support helpers in src/voxel/ (voxParser.ts,
starterShapes.ts, TriViewMasks.ts), the figure harness, and the whitepaper - is not covered
by the MIT license unless a file carries its own MIT SPDX header. The method library is self-contained
(it has no dependencies back into the editor), so it can be reused independently of this app.
The example voxel models in src/examples/ - used for several whitepaper figures
and bundled with the editor - were contributed by Zach Soares (@Voxels).
Thanks!