# WebGPUPathTracer

class in `three-gpu-pathtracer/webgpu`

```js
import { WebGPUPathTracer } from 'three-gpu-pathtracer/webgpu';
```

Progressive path tracer running on WebGPU. Call `WebGPUPathTracer#setScene` once,
then `WebGPUPathTracer#renderSample` every frame to accumulate samples into the canvas.

The scene is captured when `setScene` is called, so changes to geometry, materials, lights, or
the environment afterward require the matching `update*` function. Any change that invalidates
the accumulated image restarts it.

Example: Path tracing a model lit by an environment map

```js
import { ACESFilmicToneMapping, Color, EquirectangularReflectionMapping } from 'three/webgpu';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';
import { HDRLoader } from 'three/addons/loaders/HDRLoader.js';
import { createFloor } from './floor.js';
import { WebGPUPathTracer } from 'three-gpu-pathtracer/webgpu';

// scene, camera and renderer are initialized here

const URL = 'https://raw.githubusercontent.com/gkjohnson/3d-demo-data/main/models/nasa-m2020/Perseverance.glb';
const ENV_URL = 'https://raw.githubusercontent.com/gkjohnson/3d-demo-data/main/hdri/chinese_garden_1k.hdr';

const { scene: model } = await new GLTFLoader()
	.setDRACOLoader( new DRACOLoader() )
	.loadAsync( URL );
const environment = await new HDRLoader().loadAsync( ENV_URL );

environment.mapping = EquirectangularReflectionMapping;
scene.environment = environment;
scene.background = new Color( 0xeeeeee );
renderer.toneMapping = ACESFilmicToneMapping;

model.position.z = - 0.32;
scene.add( model, createFloor() );

camera.position.set( - 3.2, 2.2, 4.6 );
controls.target.set( 0, 0.9, 0 );
controls.update();

const pathTracer = new WebGPUPathTracer( renderer );

// mobile GPUs are slower: fewer paths per frame keep frames fast, and fewer pixels converge sooner
if ( matchMedia( '(pointer: coarse)' ).matches ) {

	pathTracer.frameBudget = 50000;
	renderer.setPixelRatio( window.devicePixelRatio / 2 );

}
pathTracer.maxSamples = 32;
pathTracer.setScene( scene, camera );
controls.addEventListener( 'change', () => pathTracer.updateCamera() );
window.addEventListener( 'resize', () => pathTracer.updateCamera() );
renderer.setAnimationLoop( () => pathTracer.renderSample() );
```

## Constructor

```js
new WebGPUPathTracer( renderer: WebGPURenderer )
```

- `renderer`, `WebGPURenderer`

## Properties

### .maxBounces: number

default `15`

Maximum number of times a ray can scatter before the path is terminated. Higher values
resolve more indirect light at the cost of speed.

### .frameBudget: number

default `250000`

Number of path slots dispatched per `WebGPUPathTracer#renderSample` call,
independent of resolution. Raising it trades frame rate for convergence speed.

### .maxTransparentBounces: number

default `5`

Maximum number of alpha tested surfaces a ray can pass through. Counted separately from
`WebGPUPathTracer#maxBounces` so foliage and cutouts cannot exhaust the bounce budget.

### .maxSamples: number

default `0`

Stops accumulating once every pixel reaches this many samples. A denoiser only runs once the
render has stopped, so it has no effect while this is `0`.

> **Note:** `0` renders indefinitely.

### .transmissiveBackground: number

default `TRANSMISSIVE_BACKGROUND_OVERLAY`

How the background is treated behind transmissive surfaces. One of
`TRANSMISSIVE_BACKGROUND_OVERLAY`, `TRANSMISSIVE_BACKGROUND_ENVIRONMENT`, or
`TRANSMISSIVE_BACKGROUND_TRANSPARENT`.

### .filterGlossyFactor: number

default `1`

Blurs sharp reflections seen through rough surfaces to suppress fireflies. Higher values
remove more noise and more detail.

> **Note:** `0` disables the filter.

### .multipleImportanceSampling: boolean

default `true`

Whether to combine light sampling and bsdf sampling with MIS. Disabling it makes lights
noticeably noisier.

### .clampDirect: number

default `0`

Upper bound on the contribution of a directly lit path segment, for suppressing fireflies.

> **Note:** `0` disables the clamp. Clamping darkens the image and biases the result.

### .clampIndirect: number

default `10`

Upper bound on the contribution of an indirectly lit path segment, for suppressing
fireflies.

> **Note:** `0` disables the clamp. Clamping darkens the image and biases the result.

### .target: Texture | null

readonly

The render target the accumulated samples are written into.

### .fadeState: number

readonly

Progress of the fade from the low resolution preview to the full render, from 0 to 1.

### .lowResTarget: Texture

readonly

The low resolution preview rendered while `WebGPUPathTracer#renderDelay` elapses.

### .lowResMode: boolean

readonly

Whether the tracer is currently rendering the low resolution preview.

### .textureAtlas: AtlasTexture

readonly

The atlas every scene texture is packed into for the kernels to sample.

### .minSamples: number

default `1`

Samples every pixel must reach before the full resolution render is faded in.

### .renderDelay: number

default `500`

Milliseconds to show the low resolution preview for after a reset.

### .fadeDuration: number

default `500`

Milliseconds taken to cross fade from the preview to the full render.

### .dynamicLowRes: boolean

default `true`

Whether to render a low resolution preview while the camera is moving.

### .lowResScale: number

default `0.1`

Resolution of the low resolution preview, as a fraction of the render size.

### .renderScale: number

default `1`

Resolution the path tracer renders at, as a fraction of the canvas size. Lowering it
converges faster at the cost of detail, and pairs with an upscaler.

### .synchronizeRenderSize: boolean

default `true`

Whether to track the canvas size automatically. Set to `false` to drive the render
size with `WebGPUPathTracer#setSize`.

### .generateMissingAttributes: boolean

default `true`

Whether to generate the attributes in `WebGPUPathTracer#commonAttributes` on
geometry that is missing them when the scene is set.

### .commonAttributes: Array<string>

default `[ 'normal', 'tangent' ]`

Vertex attributes every geometry is expected to provide.

### .stableNoise: boolean

default `true`

Whether to restart the random sequence on reset so a given camera always produces the
same image.

### .pause: boolean

default `false`

Whether to stop accumulating samples. The last image keeps being presented.

## Methods

### .getSampleCountsAsync

```js
async .getSampleCountsAsync(  ): Promise<SampleCounts>
```

Measures the per pixel sample counts. Use `min` for convergence checks and `avg` to display.

> **Note:** The wavefront backend reduces the counts on the GPU and reads them back, so only call
  this when the numbers are needed.

### .setMultipleImportanceSampling

```js
.setMultipleImportanceSampling( value: boolean )
```

- `value`, `boolean`

### .setDenoiser

```js
.setDenoiser( denoiser: OIDNDenoiser | null )
```

Attaches a denoiser, run once the render settles and displayed in place of the raw image.
Settings live on the instance. Pass null to remove it.

- `denoiser`, `OIDNDenoiser | null`

### .setUpscaler

```js
.setUpscaler( upscaler: FSRUpscaler | null )
```

Attaches an upscaler, run before the image is presented so the render can happen below the
canvas resolution. Settings live on the instance. Pass null to remove it.

- `upscaler`, `FSRUpscaler | null`

### .setScene

```js
.setScene( scene: Scene, camera: Camera )
```

Captures the scene and camera and builds the acceleration structures the kernels trace
against. Call this once, then use the `update*` functions for later changes.

- `scene`, `Scene`
- `camera`, `Camera`

> **Note:** Geometry BVHs are built synchronously, so this blocks for large scenes.

### .setRandom

```js
.setRandom( random: Object )
```

Replaces the random number generator and recompiles the kernels.

- `random`, `Object`: One of the Random Strategies constants, such as `RANDOM_BLUE_DITHER`.

### .setCamera

```js
.setCamera( camera: Camera )
```

Replaces the camera the rays are generated from. Cameras with a `getCameraRayFn`, such as
`PhysicalCamera` and `EquirectCamera`, provide their own ray generation.

- `camera`, `Camera`

### .updateMaterials

```js
.updateMaterials(  )
```

Re-reads the material properties and textures from the scene. Call after changing any
material.

### .updateTransforms

```js
.updateTransforms(  )
```

Re-reads the world matrices from the scene. Call after moving any object.

> **Note:** Changing geometry requires `WebGPUPathTracer#setScene` instead, since the BVH
  must be rebuilt.

### .updateCamera

```js
.updateCamera(  )
```

Re-reads the camera transform and projection. Call after moving the camera.

### .updateEnvironment

```js
.updateEnvironment(  )
```

Re-reads `scene.environment` and `scene.background`, along with their intensity, rotation,
and blur.

### .updateLights

```js
.updateLights(  )
```

Re-collects the lights in the scene. Call after adding, removing, or changing one.

### .setSize

```js
.setSize( x: number, y: number )
```

Sets the resolution the path tracer renders at. Only used when
`WebGPUPathTracer#synchronizeRenderSize` is `false`.

- `x`, `number`
- `y`, `number`

### .reset

```js
.reset(  )
```

Discards the accumulated image and starts over. The `update*` functions call this for you.

### .renderSample

```js
.renderSample(  )
```

Accumulates one round of samples and presents the result to the canvas. Call once per frame.

### .renderDebugBounds

```js
.renderDebugBounds( options?: Object )
```

Draws a heatmap of how many BVH bounding boxes each camera ray intersects, for diagnosing
box overlap and traversal cost. Hotter pixels traverse more nodes.

- `options`, `Object`, optional
  - `displayTLAS`, `boolean`, optional, default `true`: Count the top level object bounding boxes.
  - `displayBLAS`, `boolean`, optional, default `true`: Count the per object geometry bounding boxes.
  - `stopAtSurface`, `boolean`, optional, default `false`: Only count boxes in front of the nearest
  hit, so occluded boxes do not contribute. Culling and material transparency are honored.
  - `saturationCount`, `number`, optional, default `64`: Node count that saturates to full heat.

### .renderTextureAtlas

```js
.renderTextureAtlas( layer?: number )
```

Draws one layer of the texture atlas to the canvas, for debugging texture packing.

- `layer`, `number`, optional, default `0`

### .renderSampleDensity

```js
.renderSampleDensity(  )
```

Draws a heatmap of the per pixel sample counts, for spotting pixels that converge slowly.

> **Note:** Measures on every call and draws with the previous result, since the readback lands a
  frame later.

### .dispose

```js
.dispose(  )
```

Frees every GPU resource held by the tracer, including any attached denoiser and upscaler.

### .getRenderTime

```js
.getRenderTime(  ): number
```

Milliseconds elapsed since the last reset.
