@tinypoly/cpu-rendererv0.3.0MIT
CPU renderer for Three.js
An open source package that renders a THREE.Scene on the CPU, splitting the work across a pool of workers. It runs in the browser and in Node, and never creates a WebGL context. It is the renderer behind Tinypoly's render mode.
npm install @tinypoly/cpu-renderer threeImage rendered in this browser when the page opened.
Features
Features the renderer supports today, from materials and geometry to camera effects.
Materials
Standard and Physical, with clearcoat, sheen, transmission and anisotropy. Also Lambert, Phong, Toon and Basic.
GLSL Shaders
ShaderMaterial runs in a built-in interpreter that compiles GLSL to closures. It does not use eval.
Shadows
Shadows ray traced against a BVH, with penumbrae, and ambient occlusion.
Global Illumination
Diffuse indirect light with an irradiance cache, an SVGF-style denoiser and environment importance sampling.
Camera and Post-Processing
HDR or gradient environments, depth of field, fog, vignette, grain and ACES, AgX or Neutral tone mapping.
Progressive Output
Pixels arrive as each bucket finishes, ready to be painted on a canvas. A frame can be paused and resumed.
Browser and Node
No DOM dependency: it takes a size and hands back the pixels. In Node the workers run on worker_threads and share memory with no extra header; in the browser that needs cross-origin isolation.
Lines, Sprites and Points
Line, LineSegments, LineLoop, dashed lines, sprites and PointsMaterial, with a perspective or orthographic camera.
How it works
The main thread only coordinates. The computation happens in the workers.
- 01
Serialization
Geometry, materials, textures, lights and camera are copied into the renderer's own format, in the background.
- 02
Preparation
The first worker runs the vertex shaders and builds the triangles and the BVH. The others reuse that result through shared memory.
- 03
Buckets
With global illumination, the indirect light cache is computed first. Then the image is split into buckets, and each worker takes the next free one.
- 04
Finishing
Each bucket is handed over as it finishes, and the canvas adapter paints it. At the end, the denoiser is applied to the indirect light.
Usage
Pass the size, the objects and the camera, then call render(). It resolves with the finished pixels, and attachCanvas paints each bucket on a canvas as it finishes.
import * as THREE from "three";
import { CpuRenderer, attachCanvas } from "@tinypoly/cpu-renderer";
const scene = new THREE.Scene();
scene.add(new THREE.Mesh(
new THREE.SphereGeometry(1, 48, 24),
new THREE.MeshPhysicalMaterial({ color: "tomato" }),
));
const camera = new THREE.PerspectiveCamera(40, 1, 0.1, 100);
camera.position.set(0, 1, 5);
camera.lookAt(0, 0, 0);
const canvas = document.querySelector("canvas")!;
const renderer = new CpuRenderer({
width: canvas.clientWidth,
height: canvas.clientHeight,
pixelRatio: window.devicePixelRatio,
scene,
camera,
environment: { kind: "gradient", topColor: "#9cb8d8", bottomColor: "#2b2a28" },
settings: { globalIllumination: { enabled: true } },
});
attachCanvas(renderer, canvas);
renderer.on("progress", ({ completed, total }) => {
console.log(`${completed} / ${total}`);
});
const { width, height, data } = await renderer.render();In Tinypoly
This is the renderer used in Tinypoly's render mode.