@pixi/3d/extras has a few tools that show what a scene holds and how a view draws it. Use them while you work on a scene, and leave them out of what you ship.
logHierarchy prints a container and everything under it to the console, one line each, with its class and label. Use it to see what a loaded model holds. Loading models says how a file's names become labels, and Parents and children shows how getChildByLabel finds one.
If you load PixiJS 3D from the CDN, map dist/pixijs-3d.mjs and dist/pixijs-3d-extras.mjs while you debug. Class names then print in full, both in the console and in the overlay below.
WireframePass is a pass, one of the steps a view takes to draw a frame. It draws meshes a second time as lines, over their shading, so you can see how many triangles a mesh has and where they go.
Add the pass to the view, then opt meshes in by its name, 'wireframe', as with any mesh pass. Use a material's passes option, or enablePass to opt in one mesh at a time, as Passes per mesh does with outlines. A Model3D has no enablePass, so walk a loaded model with traverse to reach its meshes:
import { Mesh3D } from '@pixi/3d';
import { WireframePass } from '@pixi/3d/extras';
view3d.passes = [...view3d.passes, new WireframePass({ color: 0x00ff88 })];
model.traverse((node) => {
if (node instanceof Mesh3D) node.enablePass('wireframe');
});
Outlines and wireframes turns the pass on and off over a puck, a sphere and a torus.
The lines show through whatever is in front of them, including the far side of the mesh. They aren't an exact wireframe. Some edges are missing, and some lines aren't edges at all.
Leave out meshes whose geometry has no normals, the direction each vertex faces, such as the fox from the Quick start. Rendering throws on them, and the app stops drawing.
GraphDebugOverlay is an HTML panel that records how a view draws each frame. Create it with the view and the renderer:
import { GraphDebugOverlay } from '@pixi/3d/extras';
new GraphDebugOverlay({ view: view3d, renderer: app.renderer });
The panel sits in the top-right corner of the page. Once the view has rendered, press Record, use your app, then press Stop. A recording also stops by itself after maxRecordedFrames frames. Recording adds CPU time to each frame, so stop it before you measure frame times.
After you press Stop, the panel fills most of the window, with a slider that steps through the recorded frames. Hide shrinks it to a button. The panel has two tabs:
The Inspector lists a draw's meshes by label, so give your meshes one.
Three things to look for in Workload:
order changed while the camera moves. Meshes with alphaMode: 'blend' draw back to front, so the view sorts them again.mesh added or mesh removed on every frame. Adding or removing a mesh repacks or rebuilds the draws. Hide the mesh with visible instead, and the view reuses the draws.Copy Frame copies the frame you're looking at to the clipboard as JSON. Copy Recording copies every recorded frame, in the shape GraphDebugRecording#toJSON returns. destroy removes the panel.
VelocityViewer replaces the picture with how far each pixel's surface moved on screen since the last frame. That motion is what MotionBlurEffect blurs by. The hue shows the direction and the brightness shows the speed, and the class reference lists the colours. Like the blur, it sees only the camera's motion, so with the camera still the picture is black, even where objects move.
import { VelocityViewer } from '@pixi/3d/extras';
const viewer = new VelocityViewer({ scale: 0.6 });
view3d.passes = [...view3d.passes, viewer]; // it replaces the picture, so it goes last
window.addEventListener('keydown', (e) => {
if (e.key === 'v') viewer.enabled = !viewer.enabled;
});
Raise scale to brighten slow motion. In Motion blur, an inset shows the orbiting scene through a VelocityViewer, beside the blur that follows the same motion.