Skip to main content

ANARI Cameras, Renderers, and Frames

ExperimentalPrivate workspaceFrom-v10

An ANARICamera describes the view, an ANARIRenderer selects shading and presentation settings, and an ANARIFrame combines both with a world to produce an image.

ANARICamera

new ANARICamera(
device: ANARIDevice,
subtype: ANARICameraSubtype,
parameters?: ANARICameraParameters
);

newCamera(
subtype: 'perspective' | 'orthographic',
parameters?: ANARICameraParameters
): ANARICamera;

Camera parameters

type ANARICameraParameters = {
position?: ANARIVector3;
direction?: ANARIVector3;
up?: ANARIVector3;
aspect?: number;
fovy?: number;
height?: number;
near?: number;
far?: number;
};
ParameterDefaultMeaning
position[0, 0, 5]World-space camera position.
direction[0, 0, -1]World-space viewing direction. The look-at target is position + direction.
up[0, 1, 0]World-space up direction.
aspectFrame width divided by frame heightExplicit projection aspect ratio.
fovyMath.PI / 3Perspective vertical field of view, in radians.
height12Orthographic vertical viewing extent.
near0.05Near clipping plane.
far500Far clipping plane.

Perspective camera

const camera = anariDevice.newCamera('perspective', {
position: [5, 3, 8],
direction: [-5, -2, -8],
fovy: Math.PI / 4,
near: 0.05,
far: 200
});

Orthographic camera

const camera = anariDevice.newCamera('orthographic', {
position: [0, 6, 12],
direction: [0, -4, -12],
height: 10,
near: 0.05,
far: 100
});

The horizontal extent is height * aspect. Update camera position or direction with setParameters(...).commitParameters() before the next render.

ANARIRenderer

new ANARIRenderer(
device: ANARIDevice,
subtype: ANARIRendererSubtype,
parameters?: ANARIRendererParameters
);

newRenderer(
subtype?: ANARIRendererSubtype,
parameters?: ANARIRendererParameters
): ANARIRenderer;

Omitting the subtype selects default.

Renderer parameters

type ANARIRendererParameters = {
background?: ANARIVector4;
ambientRadiance?: number;
exposure?: number;
toneMapMode?: 0 | 1 | 2 | 3;
outputColorSpace?: 'linear' | 'srgb';
samplesPerPixel?: number;
maxBounces?: number;
progressive?: boolean;
shadows?: boolean;
resolutionScale?: number;
minimumResolutionScale?: number;
adaptiveResolution?: boolean;
targetFrameTimeMilliseconds?: number;
temporalReprojection?: boolean;
shadowSamplesPerFrame?: number;
bloomIntensity?: number;
bloomThreshold?: number;
bloomRadius?: number;
fogColor?: ANARIVector3;
fogDensity?: number;
};
ParameterDefaultMeaning
background[0.015, 0.018, 0.038, 1]RGBA clear color.
ambientRadiance0.12Base white ambient light added before explicit world/group lights.
exposure1.35Final lighting exposure.
toneMapModeTarget-dependent0 disables tone mapping, 1 selects Reinhard, 2 selects Khronos PBR Neutral, and 3 selects ACES. Floating-point targets default to 0; normalized targets default to 2.
outputColorSpaceTarget-dependentExplicitly selects 'linear' or 'srgb' output. Floating-point and hardware-sRGB targets default to linear output; other normalized targets default to software sRGB encoding.
samplesPerPixel1Primary-ray samples per frame in the raytrace renderer.
maxBouncesNot appliedReserved ray-tracing bounce limit; the current implementation evaluates direct lighting only.
progressivetrueAccumulate ray-traced samples across unchanged frames.
shadowstrueTrace hard shadow rays toward direct lights in the raytrace renderer.
resolutionScale0.5Initial ray-tracing width and height as a fraction of the display resolution.
minimumResolutionScale0.25Lowest internal resolution scale available to adaptive ray tracing.
adaptiveResolutiontrueAdjust internal resolution and sampled-pixel coverage toward the target frame budget.
targetFrameTimeMilliseconds33.3Target animation-frame interval used by adaptive ray-tracing quality.
temporalReprojectiontrueReuse compatible retained history while the camera or stable scene instances move.
shadowSamplesPerFrame1Maximum rotating direct-light shadow samples evaluated per pixel in one frame; 0 evaluates all direct lights.
bloomIntensity0Bloom amount; positive values allocate and run the bloom postprocessing path.
bloomThreshold0.62Brightness threshold for bloom extraction.
bloomRadius7Bloom blur radius.
fogColor[0.025, 0.035, 0.075]RGB atmospheric fog color.
fogDensity0Distance-based fog density.

Default renderer

const renderer = anariDevice.newRenderer('default', {
background: [0.012, 0.016, 0.04, 1],
ambientRadiance: 0.16,
exposure: 1.5,
bloomIntensity: 0.7,
bloomThreshold: 0.65,
bloomRadius: 8,
fogColor: [0.03, 0.04, 0.09],
fogDensity: 0.0004
});

Bloom renders into a temporary frame-sized texture before composing the result to the canvas. The intermediate texture uses the underlying device's preferred presentation format, preserving HDR values when the canvas uses rgba16float.

Deferred renderer

const renderer = anariDevice.newRenderer('deferred', {
ambientRadiance: 0.08,
background: [0.006, 0.008, 0.018, 1]
});

deferred is a WebGPU-only alternate renderer that writes committed ANARI surfaces into a shared GBuffer, then resolves opaque PBR lighting with the experimental deferredLighting shader pass. It currently supports base color, normal, metallic-roughness, emissive, and occlusion maps, plus ambient, directional, point, and spot lights. Spot lights are mapped onto deferred point lights in this first implementation.

Its compact G-buffer uses four color attachments: HDR scene color (rgba16float), normal and roughness (rgba8unorm), base color and metallic (rgba8unorm), and HDR emissive color with occlusion (rgba16float). WebGPU charges eight render-target bytes for each format, totaling the default CORE limit of 32 bytes per sample. No elevated device limits or featureLevel: 'max' are required. The omitted velocity target previously contained only zeroes; HDR, physically based material channels, direct lighting, and emissive output remain intact.

The deferred path is intended as an architecture baseline for richer ANARI renderers. It does not yet include the full Deferred Illumination Lab chain such as clustered light bins, GTAO, SSGI, SSR, velocity history, or bloom.

Ray-tracing renderer

const renderer = anariDevice.newRenderer('raytrace', {
background: [0.012, 0.016, 0.04, 1],
samplesPerPixel: 1,
maxBounces: 1,
progressive: true,
shadows: true,
resolutionScale: 0.5,
minimumResolutionScale: 0.25,
adaptiveResolution: true,
targetFrameTimeMilliseconds: 33.3,
temporalReprojection: true,
shadowSamplesPerFrame: 1
});

frame.setParameter('renderer', renderer).commitParameters();

raytrace requires WebGPU. The ANARI adapter translates committed scene objects into descriptors for the shared RayTracingSceneRenderer in @luma.gl/experimental. Its GPU compute graph derives world-space object bounds, Morton-sorts active object/instance leaves into an explicit retained permutation, builds and refits a graph-owned complete-binary TLAS, and traverses that hierarchy for nearest-hit rays and early-exit hard shadows. Transform-only animation gathers updated bounds through the retained permutation and refits without sorting; topology changes and periodic spatial refreshes rebuild the Morton order. A topology-only graph Morton-sorts each mesh's triangles into GPU-built BLASes, which transform-only updates reuse. It traces transformed analytic spheres and triangle meshes, including tessellated quads, cylinders, and cones; evaluates ambient, directional, point, and spot lights; and presents the result through a fullscreen pass. An rgba16float canvas or caller-owned framebuffer preserves HDR radiance; ordinary targets use the same configurable tone-mapping and exact sRGB transfer as forward rendering. Scalar metallic-roughness materials use GGX distribution, Smith visibility, Schlick Fresnel, and energy-balanced diffuse lighting. The trace pass uses exactly eight storage buffers, and every TLAS or BLAS construction pass remains within the default WebGPU CORE limit of eight storage buffers.

The default half-resolution internal target traces one quarter as many pixels as the output canvas. When adaptive quality is enabled, the renderer can reduce scale to 0.25, spread interleaved pixel coverage across frames, and rotate one shadowed direct light per frame. It approaches the configured frame budget using smoothed animation-frame intervals; no GPU timestamp feature is required. The fullscreen presentation pass upsamples the internal HDR result.

Progressive history is reprojected through previous camera matrices and stable ANARI instance/group/ surface identities. Depth and normal validation plus bounded neighborhood color clamping reject incompatible history; camera cuts, changed topology/materials, changed light counts, and target resizing invalidate it. GPU acceleration updates are encoded only for changed geometry or transforms, while camera-only and lighting-only frames reuse the retained TLAS. Transform-only frames use the retained-permutation gather/refit graph; topology changes and periodic refreshes use the full Morton build graph.

The Morton-sorted TLAS accelerates object and instance selection, while intersected meshes traverse GPU-built Morton-sorted triangle BLASes. Hardware ray tracing and SAH/Karras hierarchy topology are not implemented. Skeletal skinning, morph-target displacement, material textures, alpha/ transmission, and advanced PBR material extensions remain on the forward/deferred renderer paths. Indirect multi-bounce path tracing, denoising, and volumes are also unsupported. maxBounces is accepted for forward compatibility but does not enable indirect bounces.

For the rationale behind the TLAS/BLAS split, Morton ordering, refit policy, megakernel execution, and temporal reconstruction roadmap, see ray-tracing technique background and tradeoffs.

Applications can also register custom renderer runtimes.

Debug normals

const normals = anariDevice.newRenderer('debugNormals');
frame.setParameter('renderer', normals).commitParameters();

debugNormals visualizes world-space surface normals as RGB values. Bloom is disabled automatically in this renderer mode.

Debug depth

const depth = anariDevice.newRenderer('debugDepth');
frame.setParameter('renderer', depth).commitParameters();

debugDepth visualizes scene depth. Bloom is disabled automatically in this renderer mode.

Updating renderer settings

renderer
.setParameters({exposure: 1.8, bloomIntensity: 0.9, fogDensity: 0.001})
.commitParameters();

Committed renderer settings apply on the next frame. Set bloomIntensity to 0 to bypass the bloom pass.

ANARIFrame

new ANARIFrame(device: ANARIDevice, parameters: ANARIFrameParameters);
newFrame(parameters: ANARIFrameParameters): ANARIFrame;

type ANARIFrameParameters = {
world: ANARIWorld;
camera: ANARICamera;
renderer: ANARIRenderer;
size?: readonly [number, number];
};
ParameterRequiredMeaning
worldYesCommitted scene hierarchy.
cameraYesCommitted perspective or orthographic camera.
rendererYesCommitted renderer and presentation controls.
sizeNoExplicit width and height in drawing-buffer pixels. Defaults to the device canvas drawing-buffer size.
const frame = anariDevice.newFrame({
world,
camera,
renderer,
size: [1280, 720]
});

render()

render(): ANARIFrameStatistics;

Compiles committed scene objects as necessary, updates transforms and material/light uniforms, draws the world, optionally runs bloom, and returns render statistics:

const statistics = frame.render();
graphicsDevice.submit();

If required world, camera, or renderer parameters are absent from committed frame state, the implementation returns zero-valued statistics without rendering.

statistics

frame.statistics: ANARIFrameStatistics;

type ANARIFrameStatistics = {
surfaceCount: number;
instanceCount: number;
drawCount: number;
triangleCount: number;
rayTracing?: {
internalWidth: number;
internalHeight: number;
resolutionScale: number;
sampledPixelCoverage: number;
frameTimeMilliseconds: number;
accumulatedSamples: number;
graph?: {
nodeCount: number;
computePassCount: number;
coalescedComputeNodeCount: number;
cpuEncodeTimeMilliseconds: number;
topology?: ANARIRayTracingGraphStageStatistics;
acceleration?: ANARIRayTracingGraphStageStatistics;
refit?: ANARIRayTracingGraphStageStatistics;
trace: ANARIRayTracingGraphStageStatistics;
};
};
};
StatisticMeaning
surfaceCountNumber of distinct retained surface identities visible in the world.
instanceCountNumber of direct and instanced surface placements.
drawCountNumber of successful model draws, normally one per distinct raster surface or one ray-tracing presentation draw.
triangleCountSum of mesh triangles across all placements; analytic ray-traced spheres contribute zero.
rayTracingOptional internal resolution, effective scale, sampled-pixel coverage, smoothed frame time, accumulated samples, and synchronous graph-stage diagnostics; present only for the raytrace renderer.
rayTracing.graphLogical node counts, physical compute-pass counts, coalesced compute-node counts, and CPU encoding time for the stages actually recorded during this frame.

frame.statistics is initialized with zeroes and updated by each frame.render() call.

The trace graph stage is always present. topology appears only when mesh hierarchies are rebuilt, and acceleration and refit are mutually exclusive full-build and transform-only TLAS stages. These counters describe synchronous encoding only: collecting them does not submit the application's encoder, wait for the GPU, or read a buffer back to the CPU.

Resizing

frame.setParameter('size', [canvas.width, canvas.height]).commitParameters();

Omit size to follow the canvas drawing-buffer size. Changing an explicit frame size resizes bloom's temporary framebuffer on the next render.

Replacing world, camera, or renderer

frame.setParameters({
world: nextWorld,
camera: nextCamera,
renderer: nextRenderer
}).commitParameters();

Each replacement must be committed on the frame. Scene objects referenced by the previous world can still be reused elsewhere.

destroy()

destroy(): void;

Releases the frame's cached models, instance buffers, intermediate textures/framebuffers, and bloom renderer. Call it before disposing of the parent ANARI or graphics device.

Shared exported types

type ANARIVector3 = readonly [number, number, number];
type ANARIVector4 = readonly [number, number, number, number];
type ANARIMatrix4 = readonly number[];

type ANARIGeometrySubtype = 'triangle' | 'sphere' | 'cylinder' | 'cone' | 'quad';
type ANARIMaterialSubtype = 'matte' | 'physicallyBased';
type ANARILightSubtype = 'ambient' | 'directional' | 'point' | 'spot';
type ANARICameraSubtype = 'perspective' | 'orthographic';
type ANARIRendererSubtype =
| 'default'
| 'deferred'
| 'debugNormals'
| 'debugDepth'
| 'raytrace'
| (string & Record<never, never>);

All parameter interfaces, object classes, subtype aliases, object metadata, and frame statistics are exported from @luma.gl/anari.