ReadonlyidStable identity (§53), assigned at construction from a monotonic counter
and formatted geometry-<n>. Unique within a process, ascending in
construction order, never reused — and, crucially, never copied: a
clone is a different geometry and gets the next id (see
Geometry.clone).
This geometry's local BoundingVolume — §53's bounds field,
spelled as a getter so that it cannot go stale.
Identical to calling BufferGeometry.computeBounds, down to the identity of the returned object: reading the property recomputes exactly when the method would.
Bytes this geometry holds (§83, §84's bufferMemory) — the sum of the
byteLengths of positions and whichever of normals, uvs, colors,
joints, weights, positions1, normals1, and indices are present, and therefore exactly what
a backend uploads for it.
// 3 vertices × 3 floats × 4 bytes
new BufferGeometry({ positions: new Float32Array(9) }).byteLength; // 36
0 once disposed, because a disposed geometry holds nothing — that is
the same fact positions reports by becoming empty, stated as a single
rule so that a write into a disposed geometry (already a §83 "disposed
resource still in use" mistake) cannot resurrect its bytes in the
process-wide totals.
Derived on every read rather than cached: it is five property reads and an addition, nothing on the draw path calls it, and a cached copy would be one more thing an in-place edit could invalidate.
Optional per-vertex straight RGBA colors, or undefined for a geometry
that carries none (§53, §60a). Held by reference, like
BufferGeometry.positions, and subject to the same rules: assigning
validates (four floats per vertex, index-aligned, finite, §85) and bumps
the version; in-place edits are invisible and need
BufferGeometry.markDirty — which is the fast path a debug-draw
overlay rewriting its segment colors every frame takes. Assigning
undefined drops the attribute; a vertexColors material drawing a
color-less geometry then multiplies by GL's constant default
(0, 0, 0, 1), i.e. renders black.
Replacing positions with an array of a different vertex count while
colors are present therefore throws: drop or replace the colors first.
Whether BufferGeometry.dispose has run.
Number of elements one draw call issues: the index count when indexed, the vertex count otherwise. Always a whole number of primitives.
Optional index buffer, or undefined for sequential vertices. Assigning
validates against the current positions and mode and bumps the version;
assigning undefined drops indexing (and then requires a vertex count that
divides into whole primitives).
Optional per-vertex joint indices as quadruplets, or undefined for a
geometry no skin influences (§53, §54; RFC 0003). Held by reference, like
BufferGeometry.positions, and subject to the same rules: assigning
validates (four entries per vertex, index-aligned, §85) and bumps the
version; in-place edits are invisible and need
BufferGeometry.markDirty. Assigning undefined drops the
attribute — the geometry then never draws skinned, whatever skeleton its
mesh carries (the render list warns about the mismatch in a development
build).
Each entry indexes Skeleton.bones (§33: insertion order is the ABI) and
is deliberately not range-checked here — see the module header.
Primitive assembly. Assigning re-validates the buffers against the new
mode — switching a triangle geometry to "lines" fails unless the counts
divide by 2 — and bumps the version.
Optional per-vertex normals, or undefined for an attribute-free layout
(§53, §68). Held by reference, like BufferGeometry.positions, and
subject to the same rules: assigning validates (index-aligned with
positions, finite, §85) and bumps the version; in-place edits need
BufferGeometry.markDirty. Assigning undefined drops the
attribute — the geometry draws unlit-only from then on (a lit draw of a
normal-less geometry shades from its ambient term alone; see
@fourjs/render-webgl).
Replacing positions with an array of a different vertex count while
normals are present therefore throws: drop or replace the normals first.
Optional first morph-target normals, or undefined (§54 GPU morph).
Location 7. Same assignment rules as BufferGeometry.normals.
Vertex positions as xyz triplets. The array is held by reference, not copied — a builder that generated it hands over ownership, and a renderer may upload straight from it.
Assigning a new array validates it (§85) and bumps BufferGeometry.version. Editing the existing array in place is legal and cheap, but invisible here: call BufferGeometry.markDirty afterwards.
Optional first morph-target positions, or undefined (§54 GPU morph).
Location 6. Same assignment rules as BufferGeometry.normals.
Optional per-vertex texture coordinates as uv pairs, or undefined for a
geometry that carries none (§53, §55). Held by reference, like
BufferGeometry.positions, and subject to the same rules: assigning
validates (two floats per vertex, index-aligned, finite, §85) and bumps the
version; in-place edits are invisible and need
BufferGeometry.markDirty. Assigning undefined drops the
attribute — a textured draw of a uv-less geometry then samples the texel at
(0, 0) for every fragment, because GL's constant attribute default is
(0, 0, 0, 1).
Replacing positions with an array of a different vertex count while uvs
are present therefore throws: drop or replace the uvs first, exactly as for
BufferGeometry.normals.
Counter incremented on every mutation (§53). Backends cache GPU buffers
against it; treat it as opaque and compare for inequality, exactly like
Transform.version. Monotonic, never wraps in a realistic session.
Number of vertices — positions.length / 3.
Optional per-vertex joint weights as quadruplets, index-parallel with
BufferGeometry.joints, or undefined (§53, §54; RFC 0003). Held
by reference and subject to the same rules as every attribute: assigning
validates (four finite floats per vertex, §85) and bumps the version;
in-place edits need BufferGeometry.markDirty. A per-vertex sum of
1 is the author's contract, not validated — see the module header.
An independent copy of this geometry — same vertex data, same mode,
a new BufferGeometry.id, version 0 (§53).
const wobbly = geometry.clone();
wobbly.positions[1] += 0.5; // does not touch `geometry`
wobbly.markDirty();
Every typed array is copied, not shared. That is the only choice that survives contact with this class's own fast path: attributes are held by reference and the documented way to edit them is an in-place write followed by BufferGeometry.markDirty. A shallow clone would therefore give two geometries one buffer and two independent version counters — an in-place edit through either handle would silently change what the other draws while leaving the other's version (and so every backend cache keyed on it) untouched. That is not a cheaper clone; it is a cache-coherence bug with a convenient name.
There is nothing else in a geometry to copy: the bounds are derived (the clone recomputes them on first use, to the same values), the id is deliberately not copied, and the geometry holds no references to nodes, materials, or backends.
The cost is honest and worth stating: clone() allocates and copies
byteLength bytes, and reports them to the §83 totals as a second live
geometry. Cloning is for forking data — a procedural mesh about to be
deformed per instance. Sharing one geometry between many renderables needs
no clone at all (§83: geometries are shared, not owned by nodes).
Returns this geometry's local BoundingVolume, recomputing it only when BufferGeometry.version has advanced since the last call (§53: bounds are computed, then cached against the version).
Allocates nothing — the returned volume and its three vectors are owned by the geometry and rewritten in place on the next recompute, so callers that keep the values must copy them.
A geometry with no vertices returns the empty box min = +Infinity,
max = -Infinity (decision, WP-3.3): that is the identity element of
bounds union, so an empty geometry folded into a scene bound contributes
nothing, whereas a zero-sized box at the origin would drag the scene bound
to include a point that has no geometry in it. Its center and radius
are NaN for the same reason stated positively — the volume of no points
is not a point at the origin (R-21).
Releases this geometry's CPU-side data (§83). Idempotent.
The typed arrays are dropped — positions becomes empty, normals,
uvs, colors, joints, weights, and
indices become undefined — so a large mesh's memory is reclaimable the moment
its owner is done with it, and the version is bumped so any backend cache
keyed on it re-reads (and finds nothing to draw). Nothing throws
afterwards: BufferGeometry.disposed is the flag renderers and the
§83 "disposed resource still in use" diagnostic check.
Disposing does not notify the renderables pointing at this geometry; ownership is explicit and upwards (§83), so whoever created the geometry decides when nothing needs it any more.
It does remove this geometry and its bytes from the process-wide §83
totals (geometryMemoryBytes, liveGeometryCount), exactly once: the
idempotence guard above is what makes a double dispose() subtract once
rather than twice.
Announces a mutation the geometry could not see — an in-place write into
positions, normals, uvs, colors, or indices. Bumps
BufferGeometry.version by one, which invalidates the cached bounds
and every backend buffer keyed on the version.
Calling it after a setter is harmless, only wasteful: the version advances again and the bounds recompute once more.
Vertex positions plus optional indices — the geometry every MVP-tier renderable draws (§53).
Geometries are shared, not owned by nodes: any number of
Renderables may point at one, and disposing it is the job of whoever created it (§83).