AdvancedThe extra bits, inferred from extraBits; they decide what
ParticleContainer3D.setParticle accepts. On the bare ParticleContainer3D type,
setParticle type-checks only the built-in attributes.
Creates a particle container; add it under a View3D's root to draw it
The extra bits, inferred from extraBits; they decide what
ParticleContainer3D.setParticle accepts. On the bare ParticleContainer3D type,
setParticle type-checks only the built-in attributes.
Construction options; see ParticleContainer3DOptions.
A fixed local-space box measured in place of this container and its subtree, or null to
measure the geometry
Set one on a large subtree whose extent you already know, such as a level chunk, to skip walking
it. getLocalBounds and the size members read it. It's pixi's
boundsArea; it doesn't change culling.
ReadonlycapacityHow many particles the pool holds, fixed at construction
Child nodes
Their order doesn't decide what draws first. Read the array, but change it through addChild and removeChild. To visit the whole subtree, use traverse.
CSS cursor shown while this node is the pointer's target
Only the target's own cursor counts, as in 2D: a hit on a 'passive' child shows its
interactive ancestor's cursor, so set it on the node with the listeners. null shows the
View3D's own cursor. Any CSS cursor value works, url(...) included.
button.cursor = 'pointer';
handle.cursor = 'grab';
blade.cursor = 'url("crosshair.png") 8 8, crosshair'; // custom, with a hotspot
https://developer.mozilla.org/en-US/docs/Web/CSS/cursor MDN Cursor Documentation
ReadonlydataTyped-array views over the vertex buffer; see ParticleContainerViews
Whether destroy has run, as in pixi's Container
How this node takes part in pointer events, as on a pixi.js Container
'none': never picked, and neither is anything below it. The subtree costs nothing per
pointer event.'passive' (default): fires no listeners and is never the target. Under an interactive
ancestor it is still picked, and the hit goes to that ancestor with this node's surface
data. So one 'static' group makes its whole subtree clickable, with the group as target.'auto': as 'passive', but ray-tested even with no interactive ancestor, which costs time
and finds no target. Prefer 'passive'.'static': picked against its hitVolume, and fires
listeners.'dynamic': as 'static', and the View3D also picks again while a mouse or pen is
still, so a node that moves under it gets its enter and leave events.The renderer's eventMode option only sets the default for 2D containers, and the View warns
once when it isn't 'passive'. Picking costs time for each node that takes part, so set the
mode on the nodes and groups that need it.
Shape the pointer ray is tested against when picking this node, like hitArea in 2D
Setting it doesn't make the node interactive; eventMode
does that. Left null, a Mesh3D uses its geometry's bounding box and a plain
Container3D has no shape, so it only hears events from its children.
A shape you set also clips the node's descendants, as hitArea does in 2D: a descendant only
hits where the hit point is inside every such shape above it, whatever those nodes'
eventMode. A clipped hit doesn't block what is behind it. A Geometry3D clips by its bounding
box, an IHitVolume3D only through its optional containsPoint, and the default
bounding box never clips. A ray that misses a Box or Sphere shape, or a Geometry3D's
bounding box, skips the exact test of every descendant under it.
mesh.interactive = true; // picked by its bounding box
mesh.hitVolume = 'geometry'; // picked per triangle
mesh.hitVolume = new Sphere(center, 0.4); // a cheaper or tighter shape
mesh.hitVolume = null; // back to the bounding box
// Children of the porthole only pick inside its sphere
porthole.hitVolume = new Sphere(new Vector3(), 1);
HitVolume3DInput For what each accepted value resolves to.
Shorthand for eventMode, as on a pixi.js Container
true sets 'static' and false sets 'passive'. It reads true for 'static' and
'dynamic'. false doesn't stop picking: under an interactive ancestor, a 'passive' node is
still picked on that ancestor's behalf. Set eventMode = 'none' to take a node and its
subtree out of picking.
Whether this node's descendants can be picked, as on a pixi.js Container
false takes the whole subtree out of picking: descendants neither hit nor block what is
behind them, and cost nothing per pointer event. The node itself still picks by its own
eventMode and volume, so it can answer for the subtree.
menu.interactiveChildren = false; // nothing in the menu can be picked
menu.interactiveChildren = true; // every button picks again, eventMode intact
// One sphere answers for the whole robot: one ray test instead of one per mesh
robot.eventMode = 'static';
robot.hitVolume = new Sphere(new Vector3(), 2);
robot.interactiveChildren = false;
Name to find the node by, with getChildByLabel
Animation tracks find their target by it too. A plain Container3D starts with null;
built-in subclasses such as Mesh3D start with their class name.
Local transform matrix, built from the position, rotation, scale and origin
It catches up with changes in the view's transform pass, or when you call updateLocalTransform. Read it, but change the components instead: the next rebuild overwrites it.
Property-based handler for the click event
Fired when a mouse click on this node completes, with any button but the right one.
mesh.eventMode = 'static';
mesh.onclick = (e) => {
if (e.hit3D) marker.position.copyFrom(e.hit3D.point);
};
IFederatedContainer3D#onpointertap For the equivalent for every pointer type.
Property-based handler for the contextmenu event
Fired when the browser is about to open its context menu over this node; call
preventDefault() to keep it closed.
Property-based handler for the globalmousemove event
Fired on every mouse move, wherever the pointer is on the page.
IFederatedContainer3D#onglobalpointermove For the equivalent for every pointer type.
Property-based handler for the globalpointermove event
Fired on every pointer move on the page, whether or not the pointer is over this node. The
node still needs eventMode 'static' or 'dynamic' to hear it.
Property-based handler for the globaltouchmove event
Fired on every touch move, wherever the touch is on the page.
IFederatedContainer3D#onglobalpointermove For the equivalent for every pointer type.
Property-based handler for the mousedown event
Fired when a mouse button other than the right one goes down over this node.
IFederatedContainer3D#onpointerdown For the equivalent for every pointer type.
Property-based handler for the mouseenter event
Fired when the mouse enters this node. Doesn't bubble.
IFederatedContainer3D#onpointerenter For the equivalent for every pointer type.
Property-based handler for the mouseleave event
Fired when the mouse leaves this node. Doesn't bubble.
IFederatedContainer3D#onpointerleave For the equivalent for every pointer type.
Property-based handler for the mousemove event
Fired while the mouse moves across this node.
IFederatedContainer3D#onpointermove For the equivalent for every pointer type.
Property-based handler for the mouseout event
Fired when the mouse moves off this node. Bubbles, unlike mouseleave.
IFederatedContainer3D#onpointerout For the equivalent for every pointer type.
Property-based handler for the mouseover event
Fired when the mouse moves onto this node. Bubbles, unlike mouseenter.
// One handler on the shelf hears every item on it
shelf.onmouseover = (e) => highlight(e.target3D);
IFederatedContainer3D#onpointerover For the equivalent for every pointer type.
Property-based handler for the mouseup event
Fired when a mouse button other than the right one is released over this node.
IFederatedContainer3D#onpointerup For the equivalent for every pointer type.
Property-based handler for the mouseupoutside event
Fired when a mouse button that went down on this node is released anywhere else.
IFederatedContainer3D#onpointerupoutside For the equivalent for every pointer type.
Property-based handler for the pointercancel event
Never called: pixi delivers no pointer cancellation, in 2D either.
Property-based handler for the pointerdown event
Fired when a pointer goes down on this node: mouse, touch or pen alike.
Property-based handler for the pointerenter event
Fired when a pointer enters this node. Doesn't bubble, so an ancestor hears it only when the pointer enters the ancestor itself.
Property-based handler for the pointerleave event
Fired when a pointer leaves this node. Doesn't bubble.
Property-based handler for the pointermove event
Fired while a pointer moves across this node.
Property-based handler for the pointerout event
Fired when a pointer moves off this node. Bubbles, unlike pointerleave.
Property-based handler for the pointerover event
Fired when a pointer moves onto this node. Bubbles, unlike pointerenter.
Property-based handler for the pointertap event
Fired when a pointer completes a tap on this node, for any pointer type and any button, right clicks included.
Property-based handler for the pointerup event
Fired when a pointer is released over this node.
Property-based handler for the pointerupoutside event
Fired when a pointer that went down on this node is released anywhere else. The event's
target3D is the node that was pressed, and hit3D is what the pointer was released over.
Property-based handler for the rightclick event
Fired when a right click completes on this node.
Property-based handler for the rightdown event
Fired when the right mouse button goes down over this node.
Property-based handler for the rightup event
Fired when the right mouse button is released over this node.
Property-based handler for the rightupoutside event
Fired when the right mouse button that went down on this node is released anywhere else.
Property-based handler for the tap event
Fired when a touch completes a tap on this node. Chrome gives each touch a new pointerId, and
detail only counts repeat taps by the same one, so it stays 1 there; time a double tap yourself.
let lastTap = 0;
mesh.ontap = (e) => {
if (e.timeStamp - lastTap < 300) focusOn(mesh); // double tap
lastTap = e.timeStamp;
};
IFederatedContainer3D#onpointertap For the equivalent for every pointer type.
Property-based handler for the touchcancel event
Never called: pixi delivers no touch cancellation, in 2D either.
Property-based handler for the touchend event
Fired when a touch lifts off this node.
IFederatedContainer3D#onpointerup For the equivalent for every pointer type.
Property-based handler for the touchendoutside event
Fired when a touch that started on this node lifts off anywhere else.
IFederatedContainer3D#onpointerupoutside For the equivalent for every pointer type.
Property-based handler for the touchmove event
Fired while a touch moves across this node.
canvasMesh.hitVolume = 'geometry'; // per triangle, so hits carry a uv
canvasMesh.ontouchmove = (e) => {
if (e.hit3D) paintAt(e.hit3D.uv);
};
IFederatedContainer3D#onpointermove For the equivalent for every pointer type.
Property-based handler for the touchstart event
Fired when a touch lands on this node.
IFederatedContainer3D#onpointerdown For the equivalent for every pointer type.
Property-based handler for the wheel event
Fired when the wheel turns while the pointer is over this node.
Parent node, or null for a node with none, such as a view's root
Whether this mesh is shadowed by lights that cast shadows
Only lit materials take shadows. After changing it at runtime, call invalidate.
Optional ReadonlyskeletonSkeleton that deforms this mesh; undefined for a mesh that doesn't bend
Fixed at construction: to change it, build a new mesh.
ReadonlyspaceWhether particle positions are in world space or this node's, fixed at construction
ReadonlytexturesThe flipbook frames, in frame order; one entry for a single sprite
A ParticleSystem3D with frameMode 'animate' or 'overLife' holds one texture over the
whole sheet here instead.
Readonly AdvanceduidUnique id, assigned at construction
World transform: the parent's world transform times this node's localTransform
The view updates it once per frame, before drawing, for visible nodes only, and not at all while the view holds no mesh. So it can be out of date after a change this frame or while the node or an ancestor is hidden, and a node outside any view keeps the identity matrix. getGlobalTransform always works out a current one.
StaticdefaultDefaults for every new ParticleContainer3D; an option passed as undefined keeps its default
rotation in degrees, as in pixi.js
It reads and writes rotation, so the two always agree. Reading converts back from radians, so
a value can come back a hair off, such as 30 as 29.999999999999996; compare with a tolerance.
Sets the Euler rotation and makes it the rotation in use, even when the values are unchanged
The new Euler angles, in degrees
Always 'none'; particles face the camera through the billboard option instead
How particles blend over the scene; see ParticleBlendMode
Ignored unless alphaMode is 'blend'. A change rebuilds the draw state, so prefer setting it
once at construction. Fog reaches the particles only if the blend mode was 'normal' at
construction; a later change doesn't turn it on or off.
Sets the blend mode
How particles blend over the scene.
This mesh's bounding Sphere in world space, large enough for morph weights from 0 to 1
Cached until the world transform or geometry changes, so reading it often is cheap. It follows
worldTransform, so it can be out of date after a change
this frame. Dynamic geometry gives an empty sphere (radius < 0). The sphere is shared: don't
change it, and clone() it to keep a copy.
Sets whether the mesh casts shadows, from the next render
Whether the mesh casts shadows.
Depth along local z: |scale.z| × local bounds depth
Assigning writes scale.z only; see width.
Scales along z so the depth becomes value
Target depth along z
The geometry this mesh draws; Geometry3D.EMPTY until it's given one
Swaps the geometry, refitting a hitVolume given as 'box' or 'geometry'
A geometry with as many morph targets as there are Mesh3D#weights keeps them; one with
a different count gets new weights, all 0; one with none leaves weights undefined.
Geometry to draw.
Height along local y: |scale.y| × local bounds height
Assigning writes scale.y only; see width.
Scales along y so the height becomes value
Target height along y
The material this mesh draws with; BaseMaterial3D.EMPTY until it's given one
Many meshes can draw one material, and a value written to it shows on all of them. A
Model3D's meshes draw its source's materials, shared with every model built from that
source; Model3D#materials gives one model copies of its own. For one mesh alone, assign
mesh.material.clone({ baseColor: 0xff0000 }), and destroy the copy when you're done with it.
Swaps the material
Material to draw the geometry with.
Point in local space that rotation and scale happen around, as in pixi.js
Unlike a pivot, it leaves an unrotated, unscaled node where it is: the origin sits at
position + origin in the parent. Assigning copies the values in, and a single number sets
all three axes.
Sets the origin; a number sets all three axes
The new origin, in local space
Local position
Assigning copies the values in; the object itself never changes.
Local rotation as a unit quaternion; see rotation for which of the two is in use
Assigning copies the values in, so node.quaternion = other.quaternion doesn't link the two.
Sets the quaternion and makes it the rotation in use, even when the values are unchanged
The new rotation, as a unit quaternion
Advanced
The RenderPassBit flags of the passes that draw this mesh: its material's passes, plus
SHADOW while it casts shadows, or none while it holds Geometry3D.EMPTY or
BaseMaterial3D.EMPTY
The mesh's own Mesh3D#enablePass and Mesh3D#disablePass win over its material's, and a blended or transmissive material casts no shadow.
Local rotation as Euler angles in radians: turns around Z, then Y, then X, each about the parent's axes
The node keeps both this and quaternion, and whichever you
set last is the rotation in use. Assigning copies the values in. Writing unchanged values to
either through a component, set or copyFrom doesn't switch which one is in use; assign it
whole.
Sets the Euler rotation and makes it the rotation in use, even when the values are unchanged
The new Euler angles, in radians
Local scale
Assigning copies the values in, and a single number scales all three axes; the object itself never changes.
Sets the local scale; a number sets all three axes
The new scale
The uniforms the composed bits declare in their material bindings, by name
Assigning one uploads it, so particles.uniforms.uParticleTime = t is a whole per-frame update.
A vector takes an array, such as uGravity = [0, -9.8, 0]; a { x, y, z } object is silently
ignored. A vector reads back as a Float32Array, and writing one of its elements isn't
uploaded until you call particles.material.update().
The View3D this node is in, or null when it isn't in a scene
Whether this container and its descendants draw
Hiding is cheap, and a hidden node stays in the scene; to take it out, remove it with removeChild. Emits visibleChanged when the value changes.
Shows or hides this container and its descendants
Whether they draw
Morph target weights, one per target; undefined when the geometry has no morph targets
Change its values at any time rather than assigning a new array: a playing animation keeps writing the old one, and the parts a model node's mesh splits into share one array, so a new array cuts this mesh loose from both.
Replaces the weights array; does nothing when the geometry has no morph targets or value is
undefined
New weights, one per morph target.
Width along local x: |scale.x| × local bounds width
Assigning writes scale.x only. To set several axes, setSize
measures the bounds once instead of once per axis.
Scales along x so the width becomes value
Target width along x
1 when this node and every ancestor are visible, otherwise 0
The view works it out once per frame, so it lags a visible change until the next render.
Sets position.x
The new x position
Sets position.y
The new y position
Sets position.z
The new z position
Adds one or more children to the end of this container's child list
A child with another parent leaves it first. A child that is already here moves to the end, without events.
The children to add
The first added child
Adds child at index, or moves it there when it is already a child of this container
A move within this container emits no events.
The child to add or move
The destination index
The added child
Empties every slot, from the next upload on
It costs up to the highest slot written since the last clear, not the whole capacity.
Destroys the container and the geometry and material it built
children works as for any node. texture frees a single sprite's texture but leaves a
flipbook's frames; add textureSource to free the sheet behind them.
Optionaloptions: Destroy3DOptions
Teardown flags; see Destroy3DOptions.
Takes this mesh out of a render pass, whatever its material says
The mesh leaves the pass on the next render, and other meshes sharing the material stay in it.
disablePass('opaque') draws nothing of the mesh while it still casts its shadow. Only the
named pass is left, so a material that later turns 'blend' brings the mesh into the
transparent pass. Mesh3D#enablePass undoes it. Does nothing for a pass name nothing
has used yet.
The pass's name, such as 'opaque'.
Adds this mesh to a render pass, whatever its material says
BaseMaterial3D#enablePass for one mesh: the pass draws this mesh from the next render,
and other meshes sharing the material don't follow. It undoes this mesh's own disablePass
for the pass. 'shadow' is the same as setting castShadow.
The pass's name, such as 'outline'.
Gets the child at index
Index of the child to fetch
The child at index
Returns the first child whose label matches, or null
Each container checks its direct children before searching inside them. An unlabelled node never matches, even a pattern.
Exact label, or a pattern to test labels against
Whether to search the whole subtree, not only direct children
The first match, or null when nothing matches
Gets the index of child within this container
The child to look up
The child's index
Collects every child whose label matches, in the order Container3D.getChildByLabel visits them
Exact label, or a pattern to test labels against
Whether to search the whole subtree, not only direct children
Array the matches are appended to; a new one when omitted
out
Returns this container's position in world space: parent.toGlobal(this.position), or a copy
of position with no parent
Point the result is written into. Defaults to a new Vector3.
true to use the parent's cached world transform (see
Container3D.getGlobalTransform); this node's own position is always read as it stands.
Works out this container's current world transform into out
It walks up the parent chain, so the result is right even before the view's transform pass
has run this frame. With skipUpdate it copies the cached
worldTransform instead, which is cheaper but can be stale.
Matrix the result is written into. Defaults to a new Matrix4.
true to copy the cached world transform instead of recomputing.
Measures the bounding box of this container and its descendants, in this container's local space
A subtree with a boundsVolume counts as that box. Hidden descendants are left out; this container counts whether or not it is visible. An empty subtree measures as a zero box at the origin. Each call walks the subtree, so cache the result if you need it every frame.
Box to write into; a new one when omitted
out
Makes the mesh rebuild its shader and draw state on the next frame
Assigning geometry, material or billboardMode does this for you, and so do most material
changes; BaseMaterial3D lists the ones that need this call. Call it too after changing
receiveShadow. It doesn't re-read vertex data edited in place;
call Geometry3D.unload for that.
Turns this node so its forward axis, local +Z, points at a world-space target
Cameras and lights aim local -Z instead. The node aims from position + origin, and uses the
parent's current world transform, so a move earlier in the frame counts.
World-space point to face
World-space up reference; defaults to (0, 1, 0)
Marks particles lo to hi, inclusive, for the next upload
Only needed after writing through data directly; the setters mark what they write. The upload is one range spanning everything marked, so two far-apart particles send all the slots between them. A range given the wrong way round marks the whole pool, and one past either end is clamped to it.
First particle in the range.
Last particle in the range, inclusive.
Removes one or more children from this container; a node that isn't a child is ignored
The children to remove
The first child passed in
Removes the child at index
Index of the child to remove
The removed child
Removes the children from beginIndex up to, but not including, endIndex
First index to remove
OptionalendIndex: number
End of the range, exclusive; defaults to the child count
The removed children, last child first
Moves one or more nodes under this container without moving them in the world; see reparentChildAt
The children to reparent
The first reparented child
Moves child under this container at index without moving it in the world
Its local position, rotation and scale change so that it renders where it did, and it keeps its origin. Unlike pixi, it uses current world transforms, so a move earlier in the frame counts. A child that is already here only changes index.
The child to reparent
The destination index
The reparented child
Replaces oldChild with newChild at the same index, copying oldChild's local position,
rotation and scale onto newChild
newChild keeps its own origin, and its position is solved so it
sits exactly where oldChild did.
Moves an existing child to index within this container
The child to move
The destination index
Writes any of a particle's attributes by name, to go out with the next upload
Every float32 to float32x4, unorm8x4 and unorm16x4 attribute the composed bits declare
can be written, built-ins included, so a bit that declares aVel makes { aVel: { x, y, z } }
valid here; other formats throw, so write them through data. Attributes not named keep
their values. Each value takes the shape of its format; see ParticleValues. Declare your
bits with satisfies ShaderBit, not : ShaderBit, or their names and shapes aren't
type-checked.
It looks each name up, so it's slower than setParticleAt: use it to spawn a particle, not to rewrite every particle every frame.
Slot to write, 0 to capacity - 1.
Attribute name to value. An undeclared name throws.
Writes one particle, to go out with the next upload
Positions are in world space unless the container was built with space: 'local'. A size
of 0 empties the slot. To write many particles with one tint, writePacked skips
packing the colour on every call.
Slot to write, 0 to capacity - 1.
Particle centre x.
Particle centre y.
Particle centre z.
World-space diameter.
Spin in the quad's plane, in radians.
0xRRGGBB tint, in display (sRGB) space.
Opacity, 0 to 1.
Flipbook frame index, wrapping past the last frame; ignored with one frame.
Rescales this container so its size matches the given width, height and depth
A missing height or depth takes the width. An axis whose local extent is zero, such as a
flat plane's depth, keeps a unit scale. The sign of each scale axis is kept, so a mirrored node
stays mirrored.
Swaps the places of two children in this container's list
Converts a point from this container's local space to world space
Pass the result to View3D.worldToScreen to go on to 2D screen coordinates.
The local-space point to convert.
Optionalout: T
Point the result is written into. Defaults to a new Vector3.
true to use the cached world transform (see Container3D.getGlobalTransform).
Container3D.getGlobalPosition For this container's own world position.
Converts a point into this container's local space
The point to convert.
Optionalfrom: Container3D
Container whose local space position is in. Defaults to world space.
Optionalout: T
Point the result is written into. Defaults to a new Vector3.
true to use cached world transforms (see Container3D.getGlobalTransform).
Calls callback with this container, then with every container under it, depth first
Each container comes before its children, and hidden ones are visited too. A Skeleton's bones and a BatchedMesh3D's items aren't containers, so the walk doesn't reach them. It can't stop early or skip a subtree.
The callback may remove, destroy or replace the container it's given. A container it adds with addChild is visited only if its new parent hasn't been visited yet. Other changes to the tree during the walk can skip a container or visit one twice.
Called once with each container, this one first
Unloads this mesh's geometry now
The vertex data stays on the CPU, so the next frame that draws the mesh uploads it again. Remove the mesh from the scene first, or that happens straight away. The material is left alone, since it's usually shared: call BaseMaterial3D.unload for that, or Model3D.unload to free a model's geometry and textures together.
view.root.removeChild(mesh);
mesh.unload(); // adding it back re-uploads and re-packs the geometry
Advanced
Rebuilds localTransform from the position, rotation, scale and origin
The view calls it for each node that changed, so you only need it to read a current
localTransform before the next frame. When rotation is the
rotation in use, it updates the quaternion to match.
Sends the particles written since the last upload to the GPU; call it after each frame's writes
setParticleAt with a colour already packed by packParticleColor
Use it when a tint is fixed, or changes less often than you write particles: pack it once, then write many.
Slot to write, 0 to capacity - 1.
Particle centre x.
Particle centre y.
Particle centre z.
World-space diameter.
Spin in the quad's plane, in radians.
Tint and opacity as packParticleColor returns them.
Flipbook frame index, wrapping past the last frame; ignored with one frame.
A fixed pool of camera-facing quads drawn in one call, which you move yourself
Use it to draw a simulation you already have, such as a physics solver or a replayed recording. For particles that move on their own, use
ParticleSystem3Dfrom@pixi/3d/extras, which extends this class.Write particles with setParticleAt, which allocates nothing, then call upload. A slot with a size of 0 draws nothing.
Example
See
ParticleContainer3DOptions for the constructor options.