Renderer · interface

TranslucentMeshOptions

The two things a translucent draw can turn off. See Renderer.drawTranslucentMesh.

Explained in Hello world.

interface TranslucentMeshOptions
import type { TranslucentMeshOptions } from '@driftengine/core';

In depth

Both default to true, which is the world exactly as it drew before this existed: lit, fogged, shaded like everything else. An options object rather than a positional boolean — drawTranslucentMesh(mesh, model, opacity, false) reads as a flag on the call rather than as a description of what got drawn, which AGENTS.md rules out for the same reason a bare boolean is refused everywhere else in this file.

Properties

NameTypeDescription
reconstructedreadonlyoptionalbooleanDrawn into the picture a reconstruction resolves, rather than after it. For a surface that moves with what it lies on — a glow on a wall, a pane in a window — whose one motion is that surface's, so the resolve can carry it with the surface.
More

Late is the default, and it is right for anything else. A translucent surface writes no depth the motion pass could test and may move apart from what shows through it — a caption over a moving car — so a history can only smear it; after the upscale it is sharp and has none. What late gives up is the edge: drawn unjittered against a depth the jittered render covered, it meets a silhouette the render drew differently every frame, and a glow along an edge is let through on one frame and not the next. Reconstructed, it is resolved with the edge.

Only a reconstructing frame draws anything late, so this changes nothing on WebGL2 or with reconstruction off. An order-independent blended set replays where it replays.

additivereadonlyoptionalboolean
litreadonlyoptionalbooleanfalse draws the mesh exactly its own vertex colour times its own texture, with no ambient, sun, point lights, specular, reflectivity, grain or emissive touching it — three.js calls this meshBasicMaterial. For a glow shell, a flat backdrop plate or anything else whose art direction says "this colour, unconditionally."
fogreadonlyoptionalbooleanfalse keeps this draw out of the atmospheric haze and the underwater tint, both — see the shader's own comment on uFogEnabled for why the two travel together and what a draw that opts out of both gives up.
More

Independent of lit: an unlit marker at the edge of view range can still want to fade into the haze, so the two are separate switches rather than one covering both.

toneMappedreadonlyoptionalbooleanfalse skips the tone curve for this draw, keeping the colour-space conversion — which is exactly what three.js's toneMapped: false does and what it is for.
More

A meter is not a surface. ACES is a photographic response: it compresses highlights and desaturates as it goes, which is right for a world made of light and wrong for a swatch whose colour is the reading. A spectrum bar authored at #00d84a renders through the curve as (106, 213, 102) — a pale sage where the author wrote a pure green — and the error cannot be dialled out of the source colour either: the AP1 matrix mixes channels, so that stop's red is pinned at 113 of 255 even with the input's red at zero. There is no value a caller can author that comes out right, which is why this is a switch rather than a tuning problem.

Honoured where this pass grades itself, which is a renderer with no composite. With one, the frame is graded as a whole after every pass has written into it, and no per-draw flag can reach back through that; the draw is graded like everything else. That is a real limit of grading once at the end rather than per material, stated rather than hidden: three.js can honour it always because it tone maps inside every material's own fragment stage.

refractionreadonlyoptionalnumberHow far this surface bends what is behind it, in screen UV at the frame's own resolution.
More

0 is off and is the default, which is what every call that predates this means, so no existing draw and no published scene moves by a bit.

Translucent only, and that is a statement about what the branch reads rather than a restriction: it samples the colour drawn before this surface, and an opaque draw has already occluded it.

What it costs is one copy of the frame's colour, taken at the first refracting draw of a frame and reused by every later one. So glass does not refract other glass — which is right, a pane behind a pane should show the room — and opaque geometry drawn after the first pane is missing from what that pane shows. Draw the world, then the glass.

refractTintreadonlyoptionalVec3What survives one metre of this medium, per channel. White is clear glass and is the default.
More

Beer-Lambert, stated in the units a caller thinks in. The transmitted colour is pow(tint, pathLength), which is exp(-absorption * d) with absorption = -log(tint). What it costs is that a caller holding absorption coefficients from a reference converts them once; what it buys is that clear glass is (1, 1, 1) with no special case, and that there is no log(0) at the API to trap on.

Named apart from tint below, which is a different quantity on the same object. That one multiplies the surface's own colour; this one absorbs what passes through it. A draw wanting a coloured pane that does not bend already has the first, and one name for both would be a noun lying about what it does.

Does nothing without refraction, deliberately.

thicknessMreadonlyoptionalnumberMetres of medium at dot(N, V) = 1, multiplied by the per-vertex channel's .w lane.
More

The lane is optional and absent means 1.0, so a mesh carrying no channel refracts at exactly this thickness. An instanced draw cannot carry the lane at all — location 13 is the instance matrix, and InstancedMesh refuses a channelled mesh at construction — so an instanced refracting draw is uniform in thickness rather than wrong.

The path a ray takes is this divided by dot(N, V), so a pane seen edge-on absorbs more than the same pane seen face-on. That is what makes a glass edge go green while its middle stays clear, and it is the whole difference between this and a flat tint.

glassreadonlyoptionalGlassOptionsGlass: the pane shows what is behind it, by how much it lets through and how little it reflects at the view angle, blurred by how frosted it is, tinted, and glowing with the lights behind it. It keeps its own lighting and highlight, which refraction alone replaces. Absent, or letting nothing through, is not glass. See glass.ts; refraction still bends what a pane shows.
depthWritereadonlyoptionalbooleanWhether this draw writes depth. true, which is what it has always done, unless a caller says otherwise.
More

Writing depth is right for a piece and wrong for a set of them. A sign hung in the air has to occupy the depth buffer or the sky, drawn last over everything the world left untouched, paints straight over it — that is why this pass writes depth at all, and the reason is in drawTranslucentMesh's own docstring. But depth written by a blended surface rejects the blended surfaces behind it, so a model whose interior is blended draws the first of each overlapping pair and discards the rest, and which one is first is the order the caller happened to submit in.

So false is the tool for the second case: a set of blended surfaces that belong to one object and have to blend through each other. Measured on an imported vehicle, a quarter of whose materials declare a blend: 96 interior surfaces drawn against the shell they sit inside.

What it costs, and it is the whole reason this is not the default. Nothing in the depth buffer means nothing to sort by, so the caller owns the order — draw back to front, or accept that two surfaces overlapping in view blend in submission order. And a surface that writes no depth cannot occlude the sky. A caller wanting both wants the pieces sorted and this left alone.

And depth a blended surface writes is where the frame's depth-reading passes stop. The global medium marches to it on both backends, and on WebGPU ambient occlusion, the temporal resolve and motion blur take it for the surface too. Right for a pane that is most of a pixel's colour; wrong for a faint sheet. A bought courtyard's dirt decals stand a centimetre off their stone and overhang every corner they wrap, and the haze stopped at each overhang, a clear band down a pier's whole height. A decal lying on an opaque surface needs no depth to hold the sky off, since the surface under it already does, so false costs it only an order among decals.

depthLayerreadonlyoptionalnumberOrders geometry that occupies the same surface as other geometry, exactly as drawMesh's parameter of the same name and with the same ceiling.
More

A decal lying on the surface it decorates is coplanar with it, and coplanar surfaces do not merely tie: their interpolated depths are equal in exact arithmetic, so which one survives is decided per pixel by which way the rounding fell. drawMesh has had the answer since the defect turned up in six places in one session, and this call did not — so the same marking declared over the same slab was ordered when it was opaque and a coin toss when it blended.

A higher layer wins wherever two surfaces coincide. 0, the default, is the base world and takes no offset at all.

tintreadonlyoptionalVec3 | nullA per-draw colour multiplier, exactly as drawMesh's fourth argument.
More

Here rather than as a fifth positional parameter, because it belongs to the same set of per-draw decisions the rest of this interface holds and a fifth argument after an options bag reads as an afterthought.

It exists because the opaque and blended paths were not interchangeable for a caller that tints: a consumer fading a coloured model in — every surface translucent for the length of the fade — lost its colour for exactly as long as the fade ran and then snapped to it. Reported from a game whose cars arrive that way.