# Octahedral impostors in TSL: 10,957 trees in 3 draw calls

> How to turn a mesh into an atlas of views and draw thousands of it as flat cards in WebGPU and TSL, with the demo and the source open under the MIT license.

Canonical page: https://andersonmancini.dev/blog/octahedral-impostors

Published: 2026-10-11 · 3 min read · Tags: three.js, webgpu, tsl, performance, impostors

A tree with 778 triangles is cheap. Ten thousand of them is 8.5 million triangles, and nothing is cheap anymore. Games solved this a long time ago: from a distance, you do not draw the tree, you draw a **picture of it**, and you pick the picture that matches where the camera is.

That is an **octahedral impostor**. I built a demo of it in WebGPU and TSL for the Three.js Conference in Paris, where it was part of my talk, and I have now open sourced it: [the repository](https://github.com/ektogamat/octahedral-impostor-component), the [live demo](https://webgpu-octahedral-impostor.vercel.app/) and this post.

![The demo with 10,957 impostors on the right, the capture rig and the atlas on the left](https://andersonmancini.dev/blog/octahedral-impostors/demo.webp)

In that screenshot there are **10,957 trees**. The panel in the corner says 22,692 triangles and 3 draw calls. Drawn as meshes, the same field would be 8,524,546 triangles.

## Three steps

The whole technique is three steps, each one in a small piece of code.

**1. Bake.** The source mesh is rendered once from a grid of directions on a hemisphere, and every view goes into a cell of one atlas texture. The demo offers 8, 16 or 32 cells per side, in a 4096 pixel atlas. The bake uses a temporary WebGL renderer, because it needs to read pixels back.

**2. Sample.** On every frame, the direction from the camera to the object is mapped to an octahedral coordinate, which gives a grid cell, plus its two neighbors and barycentric weights for the three of them.

**3. Draw.** A TSL material blends those three atlas cells on a plane that faces the camera. The plane is a flat quad, two triangles, which is why 10,957 of them cost 21,914 triangles.

The octahedral part is the mapping in step 2. A classic billboard keeps one fixed frame, the horizon view of the tree, so when you look from above the whole forest looks like it is lying down. The demo has a **Billboard** switch for you to see that. With the octahedral layout the card changes with the viewing angle, and a tree seen from above looks like a tree seen from above.

## What to know before using it

- **Use hemispherical grids for things that stand on the ground**, like trees and characters. You never see them from below, so half the sphere is wasted.
- **A bigger grid and atlas means sharper angles, a slower bake and more VRAM.** The bake runs once per source, grid and atlas size, and changing any of them triggers a new one.
- **Lit materials bake with scene-like lights.** Unlit sources, like the tree, bake as plain albedo. A PBR source, like the fox in the demo, is baked with lights so the card matches the lit mesh. Tone mapping is applied at runtime, not during the bake.
- **It is a demo, not a package.** The reusable pieces are in `src/impostor/`: copy them into your project. A single card is `OctahedralImpostor`, and the field in the demo is a separate component tied to the demo's state.

## Why I care

This is a technique from games that is easy to bring to the web. It was part of how my [WebGPU Archiviz](https://andersonmancini.dev/projects/webgpu-archiviz.md) project stays under 6 MB with a lot of vegetation, and I talked about it, and about keeping a strict technical budget in general, in my [Three.js Conference talk](https://andersonmancini.dev/blog/three-js-conf-paris-2026.md).

The bake is inspired by the [Shaderbits article on octahedral impostors](https://shaderbits.com/blog/octahedral-impostors), which is where I would start reading if you want the math in detail.

## Try it

The demo is at [webgpu-octahedral-impostor.vercel.app](https://webgpu-octahedral-impostor.vercel.app/) and needs a browser with WebGPU. Drag the impostors slider from a couple of cards to thousands and watch the draw calls. The code is MIT licensed, and the project page here has more: [Octahedral Impostors](https://andersonmancini.dev/projects/octahedral-impostors.md).

## Related projects

- [Octahedral Impostors](https://andersonmancini.dev/projects/octahedral-impostors.md) — WebGPU direction-atlas impostors for cheap distant meshes
- [WebGPU Archiviz](https://andersonmancini.dev/projects/webgpu-archiviz.md) — 6MB Architecture Visualization
