Skip to main content

ANARI Cameras, Renderers, and Frames

ExperimentalFrom 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 feature comparison​

This table describes the built-in @luma.gl/anari runtimes. Fallback means that deferred renders the whole scene through the shared forward renderer when it cannot represent the scene in its G-buffer. It does not mean that the deferred lighting pass implements that feature. Registered custom renderers define their own support.

FeaturedefaultdeferredraytracedebugNormals / debugDepth
BackendWebGPU, WebGL 2WebGPUWebGPU compute; no hardware ray tracingWebGPU, WebGL 2
Perspective and orthographic camerasYesYesYesYes
Retained meshes and instancingYesYesTriangle meshes; analytic spheresYes
Matte and scalar metallic-roughness materialsYesYesYes; diffuse or opaque GGX transportDiagnostic output
Material image mapsCanonical PBR maps and UV transformsBase color, normal, metallic-roughness, emissive, occlusion; advanced materials use fallbackNoShared raster surface inputs; diagnostic output
Alpha maskingScalar and texture alphaScalar and texture alphaScalar alpha only, including shadows and queriesShared raster mask behavior
Alpha blendingYes; sorted forward drawsFallbackNoShared raster blend behavior
Transmission and advanced PBR extensionsYes; supported extensions and captured opaque-scene transmissionFallbackNoDiagnostic output, not physical transport
Skeletal skinning and morph targetsYesYes through shared raster geometryNoYes through shared raster geometry
Ambient, directional and point lightsYesYes; one directional and up to 64 point lights, otherwise fallbackYesNo lighting; normals or depth
Spot lightsYesFallbackYesNo lighting
Caller-provided image-based lightingYesFallbackNo; background is not an environment lightNo lighting
Emissive surface appearanceYesYesYesDiagnostic output
Emissive geometry illuminates other surfacesNoNoOpt-in emitterSampling; also secondary emission gatheringNo
Ray-traced direct-light shadowsNoNoYesNo
Indirect diffuse and specular transportNoNoOpt-in diffuse or opaque PBR bounces, up to 8; no MISNo
Progressive sampling and adaptive ray resolutionNoNoYesNo
Temporal antialiasing / historyRaster temporal AA on WebGPURaster temporal AAProgressive history and primary-hit reprojection; indirect/PBR changes can reset historyNo temporal AA
Guided spatial denoisingNoNoYes, optionalNo
FogYesYesPer-hit approximationDiagnostic output
BloomYes, optionalYes through shared scene runtimeNoDisabled
HDR outputCompatible floating-point targetsCompatible floating-point targetsCompatible floating-point targetsCompatible targets; diagnostic values
frame.pick() and captureChannels()NoNo, including fallbackYes; output-resolution identity, distance, normals and projected depthNo

Backend availability does not guarantee every device, texture format, imported asset, or material extension is supported. The ray runtime exposes getRayTracingSceneCapabilities(device) from @luma.gl/anari for implementation support; it does not report per-scene capacity or allocations. Frame query support belongs to the runtime that last rendered the frame.

Progressive accumulation does not automatically stop rendering at the history sample limit. Applications control scheduling. The Chart Lighting playground demonstrates bounded idle refinement and stopping at the limit; it retains half resolution rather than automatically switching to full resolution when idle.

Renderer parameters​

type ANARIRendererParameters = {
background?: ANARIVector4;
ambientRadiance?: number;
exposure?: number;
toneMapMode?: 0 | 1 | 2 | 3;
outputColorSpace?: 'linear' | 'srgb';
samplesPerPixel?: number;
maxBounces?: number;
emitterSampling?: boolean;
emitterSelection?: 'uniform' | 'power';
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.
maxBounces0Secondary diffuse bounce budget, clamped to 0–8. Zero preserves direct lighting. Changing it resets accumulation.
emitterSamplingfalseSample emissive geometry with direct shadow-tested connections.
emitterSelection'uniform'Select emitters uniformly or by 'power' (area × luminance), with PDF compensation.
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​

See the Forward renderer reference.

Deferred renderer​

See the Deferred renderer reference.

Ray-tracing renderer​

See the Ray-tracing renderer reference.

Debug normals​

See the Debug normals renderer reference.

Debug depth​

See the Debug depth renderer reference.

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.

pick(x, y)​

frame.render();
graphicsDevice.submit();
const hit = await frame.pick(x, y);
if (hit) {
console.log(hit.surface, hit.instance, hit.position, hit.normal);
}

The built-in WebGPU raytrace renderer traces one centered camera ray at the requested output pixel. Coordinates use the frame's drawing-buffer size, with the origin at the top left; convert CSS pointer coordinates before calling. Picking uses full output resolution even when rendering uses reduced resolution or sparse temporal sampling. Submit the rendered frame before picking. The query submits its own command buffer and reads back only 32 bytes; it does not flush pending application commands.

type ANARIPickResult = {
surface: ANARISurface;
instance?: ANARIInstance;
placementId: string;
position: ANARIVector3;
normal: ANARIVector3;
distance: number;
};

surface and optional instance are the original retained objects. placementId identifies their placement and stays stable when the world is reordered. Position and normal are in world space; distance is measured from the camera ray origin, which is on the near plane for orthographic cameras. Queries capture identity mappings before asynchronous readback, so later scene edits cannot reassign a pending result.

Picking uses the runtime that last rendered the frame, even if a different renderer has since been committed. Background, out-of-bounds or non-finite coordinates, unrendered/destroyed frames, and frames last rendered by a built-in raster renderer return null. Intersections use the ray renderer's opaque geometry semantics. Scalar alpha masks exclude below-cutoff surfaces; alpha blending and transmission remain unsupported. The experimental SelectionOutline overlay draws visible selected placement boundaries. Projected-depth transfer for raster overlays is available through DepthTextureCopy.

captureChannels()​

frame.render();
graphicsDevice.submit();
const channels = frame.captureChannels();
if (channels) {
// Bind the textures to a GPU effect or use Texture.readBuffer() for explicit readback.
// Identifier texel value n > 0 resolves to channels.identifiers[n - 1].
// Release the snapshot after submitting its final GPU use.
graphicsDevice.submit();
channels.destroy();
}

The built-in WebGPU raytrace runtime traces one centered primary ray for every output pixel and returns a caller-owned GPU snapshot. Its size matches the drawing-buffer frame size, independently of resolution scaling, jitter, progressive accumulation, or sparse sampling. Texture coordinates use a top-left origin, matching pick(). The capture submits its own command buffer, performs no CPU readback, and does not flush application commands. Render and submit the scene before capturing it.

PropertyFormat / meaning
identifierTexturer32uint: exact integer placement identifier; zero denotes background.
distanceTexturer32float: distance from the camera ray origin in world units; zero denotes background. Orthographic origins lie on the near plane. This is not projected device depth.
normalTexturergba32float: world-space normal in xyz, hit validity in alpha. Background is all zero.
projectedDepthTexturer32float: projected WebGPU depth in zero-to-one range, from the last rendered camera; background is one.
identifiersArray mapping nonzero texel value n to index n - 1, containing the original surface, optional instance, and stable placementId.
destroy()Releases all four snapshot textures.

Identifiers are local to each snapshot: retain its identity table with its textures. Placement IDs remain stable when scene extraction reorders packed primitives. Snapshots are independent of subsequent renders, resizing, and frame destruction; the application must submit commands using the textures before releasing them, while the graphics device is still alive. Each capture allocates 28 bytes per output pixel and performs an additional full-frame traversal, so capture only when needed. Float textures require unfilterable texture bindings; identifiers require unsigned integer bindings. All four support texture sampling and explicit texture-to-buffer copies.

Like picking, capture uses the runtime that last rendered the frame. Unrendered or destroyed frames and frames last rendered by the built-in raster runtime return null. Channels use scalar alpha-mask intersection semantics. Texture alpha, blending and transmission remain separate work. Use DepthTextureCopy to transfer projectedDepthTexture into a color-preserving render pass with a depth attachment before drawing raster overlays with matching camera and viewport conventions.

Selection outlines​

Use SelectionOutline to draw an inward border over a selected visible placement. Resolve a pick() placement ID against the current snapshot identity table, rather than reusing an integer ID from an older snapshot. The JSON playground performs this lookup each frame while a mark is selected.

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' | 'hexPrism' | 'torus' | 'ring';
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.

Sampling and quality​

raytrace accepts samplingSeed (uint32, default zero) for deterministic primary and diffuse sample rotations. A changed seed resets accumulation; centered picking and hit channels are unaffected. Use the same seed and frame count on the same backend for comparisons. getRayTracingQualityPreset returns explicit interactive/still renderer settings without modifying exposure or seed.

Emissive lighting and scalar alpha masks​

emitterSampling: true enables explicit emissive-geometry connections with both diffuse and PBR transport, including at zero material bounces. It defaults to false. Scalar alphaMode: 'mask' compares committed opacity against alphaCutoff for color, secondary/shadow rays, picking and channels. Masked emitters are excluded from the sampling table. See the ray quality reference for sampling semantics and current limitations. emitterSelection: 'power' enables area/luminance-weighted emitter selection; uniform selection remains the default.