Skip to main content

ANARI Arrays and Geometry

ExperimentalFrom v10

ANARIArray describes shared application data, and ANARIGeometry describes one reusable geometric primitive. Geometry becomes visible when paired with a material in an ANARISurface.

ANARIArray​

new ANARIArray(device: ANARIDevice, parameters: ANARIArrayParameters);

Applications normally call the equivalent anariDevice.newArray(parameters) factory:

const positions = new Float32Array([
-1, 0, 0,
1, 0, 0,
0, 1, 0
]);

const positionArray = anariDevice.newArray({
data: positions,
elementType: 'float32x3',
dimensions: [3]
});

Parameters​

type ANARIArrayParameters = {
data: ANARIArrayData;
elementType?: string;
dimensions?: readonly number[];
};

type ANARIArrayData = TypedArray | readonly ANARIObjectReference[];
ParameterRequiredMeaning
dataYesA typed array or an array of retained ANARI object references.
elementTypeNoApplication-provided element metadata, for example float32x3.
dimensionsNoApplication-provided dimension metadata.

The current implementation preserves the original typed array without copying. elementType and dimensions are retained metadata; the renderer does not currently validate or reinterpret them.

Properties​

array.data: ANARIArrayData;
array.length: number;

length is the JavaScript data.length. For new Float32Array(9), the result is 9 scalar values, not three vector elements. For an object-reference array, it is the number of objects.

Mutating the original typed array mutates the retained storage:

positions[0] = -2;
positionArray.data === positions; // true

When geometry data changes after its first render, commit the owning geometry so its cached GPU representation is rebuilt:

positions[0] = -2;
geometry.commitParameters();

Object-reference arrays​

const surfaces = anariDevice.newArray({data: [firstSurface, secondSurface]});
const group = anariDevice.newGroup({surface: surfaces});

const instances = anariDevice.newArray({data: [leftInstance, rightInstance]});
const world = anariDevice.newWorld({instance: instances});

The exported ANARIObjectReference union contains geometries, materials, surfaces, groups, instances, and lights. Use actual scene objects when an API expects an object-reference array; typed arrays in scene collection slots do not produce scene objects.

ANARIGeometry​

new ANARIGeometry(
device: ANARIDevice,
subtype: ANARIGeometrySubtype,
parameters?: ANARIGeometryParameters
);

newGeometry(
subtype: 'triangle' | 'sphere' | 'cylinder' | 'cone' | 'quad' | 'hexPrism' | 'torus' | 'ring',
parameters?: ANARIGeometryParameters
): ANARIGeometry;

All geometry objects expose type === 'geometry', their declared subtype, and the common staged-parameter lifecycle.

Geometry parameters​

type ANARIGeometryParameters = {
'vertex.position'?: Float32Array | ANARIArray;
'vertex.normal'?: Float32Array | ANARIArray;
'vertex.tangent'?: Float32Array | ANARIArray;
'vertex.joint'?: Uint8Array | Uint16Array | Uint32Array | ANARIArray;
'vertex.weight'?: Float32Array | ANARIArray;
'vertex.attribute0'?: Float32Array | ANARIArray;
'vertex.attribute1'?: Float32Array | ANARIArray;
'vertex.attribute2'?: Float32Array | ANARIArray;
'primitive.index'?: Uint16Array | Uint32Array | ANARIArray;
morphTargets?: readonly ANARIMorphTargetParameters[];
morphWeights?: readonly number[];
radius?: number;
height?: number;
width?: number;
segments?: number;
majorRadius?: number;
minorRadius?: number;
majorSegments?: number;
minorSegments?: number;
arc?: number;
};
ParameterUsed byDefaultMeaning
'vertex.position'triangleRequiredPacked XYZ positions as Float32Array or an ANARIArray wrapping one.
'vertex.normal'triangleGeneratedPacked XYZ normals as Float32Array or an ANARIArray wrapping one.
'vertex.tangent'triangleOmittedPacked XYZW tangent vectors; W stores tangent handedness.
'vertex.joint'triangleOmittedFour integer skin-joint indices per vertex.
'vertex.weight'triangleOmittedFour normalized floating-point joint weights per vertex.
'vertex.attribute0'triangleWhitePacked linear RGB or RGBA vertex colors multiplied by the material base color.
'vertex.attribute1'triangle[0, 0]Packed TEXCOORD_0 UV pairs sampled by material image samplers.
'vertex.attribute2'triangleOmittedPacked TEXCOORD_1 UV pairs selected by textureCoordinateSet: 1.
'primitive.index'triangleNo index bufferOptional Uint16Array, Uint32Array, or wrapped ANARI array.
morphTargetstriangleOmittedAuthored position, normal, and tangent displacement attributes per target.
morphWeightstriangle[]Current blend weight for each retained morph target.
radiussphere, cylinder, cone1Primitive radius.
heightcylinder, cone, quad1Cylinder/cone height, or quad Z extent.
widthquad1Quad X extent and fallback Z extent.
segmentssphere, cylinder, cone32Primitive tessellation resolution.

Triangle geometry​

const geometry = anariDevice.newGeometry('triangle', {
'vertex.position': new Float32Array([
-1, 0, 0,
1, 0, 0,
0, 1, 0
]),
'vertex.normal': new Float32Array([
0, 0, 1,
0, 0, 1,
0, 0, 1
]),
'primitive.index': new Uint16Array([0, 1, 2])
});

'vertex.position' must resolve to a Float32Array; otherwise the first render throws. Positions and normals use three scalar values per vertex.

If normals are omitted, the renderer generates flat normals by reading each consecutive group of three positions as one triangle. For indexed meshes with shared vertices, supply explicit normals rather than relying on that non-indexed fallback.

Secondary UV coordinates and vertex colors​

const geometry = anariDevice.newGeometry('triangle', {
'vertex.position': positions,
'vertex.attribute0': new Float32Array([
1, 0, 0, 0.5,
0, 1, 0, 1,
0, 0, 1, 1
]),
'vertex.attribute1': new Float32Array([0, 0, 1, 0, 0, 1]),
'vertex.attribute2': new Float32Array([0.5, 0.5, 1, 0.5, 0.5, 1])
});

const sampler = anariDevice.newSampler('image2D', {
image: texture,
textureCoordinateSet: 1
});

RGB and RGBA vertex-color layouts are detected from the vertex count. The additional alpha component is retained when COLOR_0 contains four channels. Texture-coordinate sets beyond TEXCOORD_1 are not supported.

Skin attributes and joint palettes​

const geometry = anariDevice.newGeometry('triangle', {
'vertex.position': positions,
'vertex.joint': jointIndices,
'vertex.weight': normalizedJointWeights
});

const surface = anariDevice.newSurface({
geometry,
material,
skin: {jointMatrices}
});

jointMatrices is a Float32Array or numeric array containing column-major joint matrices. The existing shared skinning module currently supports up to 64 joints. The glTF showcase importer preserves source joint indices and converts normalized integer WEIGHTS_0 values to floats, but does not automatically create or animate the surface joint palette; applications must supply and update that palette explicitly.

Morph targets​

const geometry = anariDevice.newGeometry('triangle', {
'vertex.position': positions,
'vertex.normal': normals,
'vertex.tangent': tangents,
morphTargets: [
{
POSITION: positionDisplacements,
NORMAL: normalDisplacements,
TANGENT: tangentDisplacements
}
],
morphWeights: [0]
});

geometry.setParameter('morphWeights', [0.65]).commitParameters();
frame.render();

Position, normal, and tangent target attributes contain XYZ displacements; base tangent W remains unchanged. Changing only morphWeights updates the existing GPU vertex data instead of rebuilding the geometry/model. The optional retained-animation adapter maps glTF node weight tracks to these parameters; see ANARI animation and glTF integration.

Sphere geometry​

const sphere = anariDevice.newGeometry('sphere', {
radius: 1.25,
segments: 24
});

The runtime creates a luma.gl SphereGeometry with segments latitude subdivisions and segments * 2 longitude subdivisions.

Cylinder geometry​

const cylinder = anariDevice.newGeometry('cylinder', {
radius: 0.35,
height: 2,
segments: 32
});

Cylinders include top and bottom caps and one vertical subdivision.

Cone geometry​

const cone = anariDevice.newGeometry('cone', {
radius: 0.8,
height: 1.6,
segments: 32
});

Cones include their base cap and one vertical subdivision.

Quad geometry​

const floor = anariDevice.newGeometry('quad', {
width: 12,
height: 8
});

Quads lie in the XZ plane. width controls X extent; height controls Z extent and defaults to width when omitted.

Rebuilding committed geometry​

sphere.setParameters({radius: 1.6, segments: 48}).commitParameters();
frame.render();

The renderer tracks committed geometry versions and recreates cached luma.gl geometry/models when structural parameters change. Updates containing only new morphWeights retain the existing geometry and update its vertex data in place. Reuse immutable geometry and surface objects whenever possible; repeatedly changing tessellation or instance counts reallocates GPU resources.

Mesh-backed chart shapes​

hexPrism is a capped six-sided prism centered at the origin along Y. Its radius is the circumradius (default 1), height defaults to 1, and side normals are flat. torus is a ring around Y: majorRadius defaults to 1, minorRadius to 0.3, majorSegments to 48, and minorSegments to 24. The minor radius must be less than the major radius. arc is a positive sweep in radians up to 2 * Math.PI (the default). Partial sweeps have open ends, starting at +X and sweeping toward −Z. They are surfaces, not closed solids.

Both shapes use shared math.gl tessellation for raster and ray rendering. They retain the same placement IDs for picking, snapshots and selection outlines. These are luma.gl subtypes; no ANARI KHR extension is advertised for them. Dimension changes take effect after commitParameters() and rebuild the mesh.

const segment = anariDevice.newGeometry('torus', {
majorRadius: 1,
minorRadius: 0.2,
arc: Math.PI * 1.5
});

Choose Chart Shapes in the JSON playground, or use playground.html?preset=chart-shapes&renderer=raytrace. Switch to renderer=default for the same raster scene. Click a visible mark in ray mode to inspect its datum identity and selection outline.

Annular prisms and ring segments​

ring constructs a closed annular prism around Y from shared math.gl lathe and plane tessellation. innerRadius defaults to 0.5 (zero creates a disk), outerRadius to 1, height to 0.2, and segments to 48. The outer radius must exceed the nonnegative inner radius. startAngle defaults to zero and angle to 2 * Math.PI; a partial sweep includes both radial caps. Angles are radians, starting at +X and sweeping toward −Z. Walls and caps retain distinct normals and POSITION/NORMAL/TEXCOORD_0 semantics. Dimension changes rebuild the mesh after commit. The engine exports the same adapter as RingGeometry.

const segment = anariDevice.newGeometry('ring', {
innerRadius: 0.5, outerRadius: 1, height: 0.4,
startAngle: 0.2, angle: Math.PI * 1.5
});