@pixi/3d
    Preparing search index...

    Materials

    A Mesh3D's material decides how its surface looks: its colour, its textures, its opacity and how light shades it. Many meshes can share one material, such as every copy of a loaded model, and a change to it shows on all of them. Meshes shows how to change just one mesh, and Loading models shows how to give one model materials of its own.

    Material Lighting Suits
    Material3D Physically based: how metallic and how rough it is Most lit surfaces, and the lit materials of glTF model files
    PhongMaterial A soft shade, plus a highlight you size and tint by eye Lit surfaces that needn't reflect their surroundings
    FlatMaterial None UI panels, icons, video screens, textures with lighting painted in
    const steel = new Material3D({ baseColor: 0xc8c8c8, metallic: 1, roughness: 0.3 });
    const plastic = new PhongMaterial({ baseColor: 0x2f6f8b, shininess: 64 });
    const screen = new FlatMaterial({ baseColorTexture: screenTexture });

    Material3D is the usual choice. It's the only one of the three that reflects the view's environment, the sky and ground colours or the cube map that light the scene from all around, as Environment and IBL explains. PBR materials covers a Material3D's inputs and the light it needs. Physical extensions covers its option groups, each of which turns on one extra feature, such as clearcoat for a lacquer coat or transmission for glass.

    PhongMaterial does less work per pixel than Material3D. The view's environment gives it only soft light from all around, so it reflects nothing and its highlights come from direct lights alone. shininess sets the size of the highlight and specularColor sets its tint. PBR, Phong and flat puts the three materials side by side in one colour, and a slider in its pane sizes Phong's highlight.

    FlatMaterial does no lighting. It shows its colour and texture without any lights, and neither shadows nor the environment change it. Its mesh still casts a shadow, so set castShadow to false on a panel or screen that shouldn't cast one. The view's toneMapping, exposure and fog still reach it, so a tone-mapping curve shifts a flat material's colours too. A curve such as 'aces' squeezes bright light into the screen's range, as Tone mapping and exposure explains. To keep fog off a flat material, build it with fog set to false.

    @pixi/3d/extras adds ToonMaterial for cartoon shading. Toon and custom materials covers it and how to write a material of your own.

    baseColor takes any PixiJS ColorSource, as a 2D tint does. It multiplies the base colour texture, so leave it white to show a texture unchanged. The material ignores the colour's own alpha. alpha sets the opacity instead, when the alpha mode allows it.

    baseColor and the other colour options take colours as a colour picker shows them. The engine converts them to linear light, where doubling a value doubles the light. Numbers you pass to a shader yourself skip that step, so convert a picked colour with srgbToLinear first. Geometry does this for vertex colours.

    alphaMode decides what a material does with the alpha from alpha and from its textures:

    • 'opaque', the default for the three materials above, ignores alpha, so setting alpha alone does nothing. An image's transparent pixels still draw, as a solid surface rather than holes.
    • 'mask' throws away pixels whose alpha is below alphaCutoff and draws the rest solid. Use it for hard edges such as leaves, fences, grilles and cut-out sprites.
    • 'blend' mixes the surface with what's behind it, in proportion to its alpha. Use it for fades, ghosts and soft edges.
    const leaves = new Material3D({ baseColorTexture: leafTexture, alphaMode: 'mask', doubleSided: true });
    const ghost = new Material3D({ baseColor: 0x99ccff, alpha: 0.4, alphaMode: 'blend' });

    A masked material draws with the opaque meshes, so it hides what's behind it and needs no sorting. A masked mesh's shadow doesn't show its holes yet, so turn off castShadow on one whose solid shadow would look wrong.

    Blended meshes draw after the opaque ones. Every frame the renderer sorts them from back to front by the distance from the camera to each mesh's origin, not by child order. It sorts each mesh as a whole, so a large blended mesh, or two that pass through each other, can draw in the wrong order where they overlap. A blended Mesh3D casts no shadow, as Shadows explains.

    Transparency switches two wordmark cards between the three modes, in front of a blended glass logo. With the cards on 'blend', walk round behind them and the draw order flips, so the logo draws over the cards.

    A solid material can switch to 'blend' for a fade and back to 'opaque' when the fade ends. For glass and water that bend what's behind them, use transmission instead.

    By default a material draws only the front of each triangle, so an open surface such as a plane, a flag or a leaf card disappears when seen from behind. To draw both sides, build its material with doubleSided set to true, as the leaves above do. Lighting treats the back as if it faced the other way.

    A material reads its textures from named slots in material.textures. All three materials above have a baseColor slot, which the baseColorTexture option fills. PhongMaterial and Material3D add more, such as normal, and Material3DTextures lists a Material3D's slots. Assign to a slot to swap its texture:

    brickMaterial.textures.baseColor = await Assets.load('bricks-wet.png');
    

    Every mesh that uses the material shows the new texture. On a PlaneGeometry or a CubeGeometry an image appears upside down until you flip it. Geometry shows how.

    Each slot uses one of the GPU's texture inputs. Some devices allow only 16 per shader, and the engine uses a few of them itself. Most option groups take their slots whether or not you give them a texture, so leave out the groups a material doesn't use.

    These options can't change once a material exists:

    • On every material: doubleSided, flatShading, fog, topology, extraBits, and the per-pass overrides in its passes option.
    • On a Material3D: which option groups it has, such as clearcoat, and whether its coat has a normal map or its anisotropy has a texture.
    • On a PhongMaterial: whether it has a specularTexture or an emissive group.

    To change one, clone the material with the new value and assign the copy to the mesh's material. The copy keeps every other setting.

    mesh.material = mesh.material.clone({ doubleSided: true });
    

    A clone can add a feature, such as an option group or an extra bit, but can't take one away. An option set to undefined keeps the material's value, and extraBits adds to the bits the material already has. To drop a feature, build a new material.

    A mesh picks up most changes to its material on the next frame: values such as baseColor and alpha, a texture swapped into a slot, and a switch to or from 'blend'. A few settings take effect only after you call invalidate on each mesh that uses the material. One is a field of state, which holds the material's depth, blending and culling settings. BaseMaterial3D lists the rest.

    // 'blend' draws the marker after the opaque walls, so it can draw over them
    const marker = new Mesh3D({ geometry, material: new FlatMaterial({ baseColor: 0xffcc00, alphaMode: 'blend' }) });

    view3d.root.addChild(marker);

    // Later: show the marker through walls
    marker.material.state.depthTest = false;
    marker.invalidate();

    A BatchedMesh3D slot is one of the meshes a batch draws. It needs its own invalidate call after more kinds of change, including a texture swap. Batched meshes shows which. A switch to or from 'blend' also needs setPassesAt.

    destroy frees a material for good. Other materials may share its textures, so it leaves them alone unless you pass true. Resources and cleanup says when passing true is safe. unload instead frees texture memory for a while, as Unloading explains.