Renderer · class

Mesh

Explained in Hello world.

class Mesh
import { Mesh } from '@driftengine/core';

Constructor

new

constructor(gl: WebGL2RenderingContext, data: MeshData, dynamic?: boolean, spread?: boolean)
ParameterTypeDescription
glWebGL2RenderingContext
dataMeshData
dynamic?boolean
spread?booleanAllocate the buffers now and fill them from uploads later. Off by default, and the default is the fast path: filling a buffer with bufferData in one call skips the zero-fill that bufferData(size) then bufferSubData pays for, and every mesh in the engine that does not need to be spread should keep skipping it.

Properties

NameTypeDescription
indexCountreadonlynumberIndices one draw of it issues; the batch-size rule reads it (cullsInstances). At zero the mesh has nothing to draw and no verb draws it, as on WebGPU (GpuMesh.indexCount): a draw of nothing is silent here but is still a call and a counted draw, and the two backends count the same frame.
boundsreadonlyBoundsHow big this mesh is, in its own space.
More

Measured here because the positions are already in hand: the upload walks them anyway, so a caller gets bounds for nothing and no MeshData producer has to supply them. Everything that wants to know whether this is on screen starts from this object.

isSkinnedreadonlybooleanWhether this mesh carries a rig, which decides which flat program draws it.
isSkinnedEightreadonlybooleanWhether its rig moves a vertex by eight influences rather than four, which decides whether the skinned program it takes is built with SKIN_EIGHT on. See skinning.ts.
hasUvsreadonlybooleanWhether it has texture coordinates, without which a material's maps read one texel.
hasGrainreadonlybooleanWhether it carries a grain lane, which is where second coordinates ride (lightmap.ts): what a bone animation reads each vertex's bone from.
vertexCountreadonlynumberHow many vertices it has, which a cloth binding is checked against.
morphreadonlyMorphTexture | nullThis mesh's morph deltas, or null for geometry that does not deform.
More

Owned by the mesh rather than set per draw, which is the difference between this and the joint palette: a palette belongs to a pose and changes every frame, where deltas are geometry and never change. Uploaded once with the vertex buffers; only the weights are per-draw state.

hasTangentsreadonlybooleanWhether this mesh carries a tangent frame, for the shader that has to be told.
More

The attribute cannot say so itself: vertexDefaults.ts supplies [1, 0, 0, 1] when it is absent — a usable frame rather than a sentinel, because a zero tangent normalises to a NaN. Read off the same branch below that chooses between the buffer and that constant.

Accessors

NameTypeDescription
completegetbooleanWhether all of this mesh's geometry has reached the device.
More

False only between the steps of an incremental upload. drawMesh refuses to draw an incomplete mesh, and that refusal is the contract: the buffers are allocated and zeroed from the first frame, so drawing one would be a fan of degenerate triangles through the origin. Drawing what has landed was the other option and is worse — a mesh whose triangle count grows over several frames is a stranger artefact than a square that is briefly absent.

Methods

draw

draw(gl: WebGL2RenderingContext): void

Caller is responsible for having the flat program + uniforms bound.

ParameterTypeDescription
glWebGL2RenderingContext

createInstanceArray

createInstanceArray(gl: WebGL2RenderingContext, instances: WebGLBuffer, stride: number): WebGLVertexArrayObject

A vertex array for one instanced batch: every attribute this mesh binds from a buffer, its index buffer, and the batch's instance columns — the model matrix at 11 to 14, the tint at 15.

ParameterTypeDescription
glWebGL2RenderingContext
instancesWebGLBuffer
stridenumber
More

A batch owns its own array, which is what lets a mesh have more than one batch: a prop drawn once per region is one mesh and a batch per region. With one array a mesh had one batch, since a second would rebind the columns the first draws through and place one batch's instances by the other's matrices. The arrays share every buffer, so a batch costs its instances and nothing of the geometry. The caller deletes what this returns.

drawInstancesThrough

drawInstancesThrough(gl: WebGL2RenderingContext, vao: WebGLVertexArrayObject, count: number): void

Draw count instances through a batch's own vertex array. See createInstanceArray.

ParameterTypeDescription
glWebGL2RenderingContext
vaoWebGLVertexArrayObject
countnumber

dispose

dispose(gl: WebGL2RenderingContext): void
ParameterTypeDescription
glWebGL2RenderingContext

update

update(gl: WebGL2RenderingContext, positions: Float32Array, normals?: Float32Array): void

Rewrite this mesh's positions, and its normals where the caller has them.

ParameterTypeDescription
glWebGL2RenderingContext
positionsFloat32Array
normals?Float32Array
More

Only the two attributes that move. Colour, emissive and the rest describe what a surface is and do not change because it bent; rewriting them would be uploading unchanged bytes every frame. A caller with genuinely changing colour wants a second mesh or a tint.

The bounds are recomputed, because everything that decides whether this is on screen starts from them — a cloth that blew sideways out of its original box would be culled while still visible, which is the kind of bug that only shows up at the edge of the frame.

uploads

uploads(gl: WebGL2RenderingContext): Generator<void, void, void>

Fill the buffers, a bounded step at a time. Done when it returns done.

ParameterTypeDescription
glWebGL2RenderingContext
More

A step is one attribute, or a slice of one where the attribute is bigger than UPLOAD_BYTES_PER_STEP. There is still no interleave here — this backend's three tight buffers are the reason a consumer measured the same drive as smooth on WebGL2 and hitching on the other one, and dividing an upload is not a reason to give that up.

The call that returns done is the one that does the last step's work, so a mesh of n chunks takes exactly n calls.

The vertex array object is bound around each step because one of these writes an index buffer, and an ELEMENT_ARRAY_BUFFER binding belongs to whichever array object is current — writing it with somebody else's bound would quietly repoint their indices at this mesh.