Skip to content

Latest commit

 

History

18 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Western Chamber Vase

An interactive 3D viewer for a historic Chinese porcelain vase from the Harvard CAMLab collection, built as a teaching tool.

Live demo: https://evpng.github.io/CAMLab-western-chamber/

Scroll to zoom, drag to rotate, shift-drag to pan.

Context

The vase is decorated with painted narrative scenes in panels around its body. The physical object was 3D scanned, producing a high-resolution textured mesh: 1.3M triangles with a 4096 × 4096 texture atlas.

The goal is a teaching tool students can explore directly rather than a set of photographs. That puts a hard constraint on the work: the resolution has to survive, so you can zoom all the way in and still read the intricate drawings. Nothing here is decimated or downscaled for the web. The full triangle count and full texture dimensions ship to the browser, and the file sizes come down through compression only.

Implementation

Rendered with three.js (r123), adapted from the official PLYLoader example. Loading spinner adapted from SpinKit.

Performance

The viewer originally shipped the raw scan output straight to the browser, which meant about 54 MB on a cold load and a long blank wait. The current build:

Before Now
Mesh 31.3 MB (gzipped PLY) 2.1 MB (Draco-compressed glTF)
Texture 22.5 MB (PNG) 1.0 MB (WebP, JPEG fallback)
Total ~54 MB ~3.7 MB

Roughly 15x smaller, with every triangle and every texel preserved.

Alongside that:

  • A loading state. The stage renders immediately and a spinner sits over it while the model downloads, then the vase eases in once its geometry and texture have both arrived.
  • Removed computeVertexNormals(). It walked 3.9M vertices on the main thread, and the unlit material never reads normals.
  • Bake the shadow map once instead of re-rasterising 1.3M triangles into it every frame. Auto-rotation orbits the camera, not the object, so the shadow never changes.
  • Cap the pixel ratio at 2. On a 3x display the uncapped value costs 9x the fragments for no visible difference.
  • Draco decodes in a worker, so the page stays responsive while the geometry unpacks.

Rebuilding the assets

The archival originals are models/mesh.ply (57 MB) and models/texture.png (21 MB). They are the source of truth, but they are not on this branch: GitHub Pages publishes the entire tip of main, so keeping them here meant every visitor's deploy carried 78 MB the page never requests. They live on the archive/scan-source branch instead.

To rebuild the delivery assets, fetch the originals first:

git checkout origin/archive/scan-source -- models/mesh.ply models/texture.png
cd tools && npm install && npm run build

Then delete the two originals again before committing, so they do not come back to the published branch.

Running locally

Asset paths are absolute and rooted at the GitHub Pages base path, so serve from the parent directory of this repo:

python3 -m http.server 8000

Then open http://localhost:8000/CAMLab-western-chamber/. Opening index.html from the filesystem will not work, since ES module imports are blocked on the file:// origin.

Credits

3D scan and source object courtesy of Harvard CAMLab.

Releases

Packages

Contributors

Languages