Skip to content

The renderer

Everything here comes from package:orblit_filament/orblit_filament.dart. A scene is stated whole, every frame. See stating a scene for why.

Field What it is
camera Where the view is, and its exposure. Required.
objects Individually tracked things, each keyed and compared against last frame. Required.
populations Bulk instanced things: a buffer of transforms, drawn 64 to a call
splats Gaussian splat clouds, from a capture file or from memory. See splats
sprites Layers of flat pictures, drawn after the solid scene. See 2D
lights Directional, point, spot and area (a rectangle), in photometric units
materials Shared material definitions, referred to by key from an object
videos Video playing onto a surface
sky The procedural sky
fog Distance fog
precipitation Rain and snow
environment Image-based lighting and an HDRI skybox, baked or filtered from an .hdr or .exr while it runs
pipeline Shadows, resolution, lighting, sampling, culling, refraction and the texture budget
post Bloom, depth of field, grading, occlusion, screen-space reflections, vignette, tone mapping, anti-aliasing
graph The passes, their targets, and the order they run in
probes Reflections captured at points in the scene. The one the camera is inside lights the scene in place of environment
field Light kept in the world rather than on the screen, as a lattice of probes. Off by default, and it lights nothing on the slim surface
volumes Regions that look different from the rest, such as a dim hall or a foggy cave, resolved against the camera before the scene is sent
decals Pictures projected onto surfaces. The first 32 are painted, and the rest are reported
outline Which objects have a line drawn round them. None by default
godRays Shafts of light from the directional light. Off by default
distortions Air that bends the light: shockwaves, heat haze, a lens. None by default
batching On by default. Four or more placeholder cubes with the same material, colour and flags are drawn together, sixty-four to a draw. Named meshes aren’t merged yet
depthPrepass Off by default. Draws opaque placeholder cubes into depth before shading them
Field Default
key required Stable across frames, unique within the scene
transform required A Matrix4
colour required A Vector3, used when no material is named
mesh null A path or resource name for a .gltf, .glb, .fbx or .obj. Null is the built-in cube.
material null The key of an entry in OrblitScene.materials
castShadows true
receiveShadows true
visible true Hidden is not deleted. The key and the loaded mesh are kept
layer 0 Which render layer it belongs to
animation null One of the file’s own clips, and where it is. See models
variant null Which of the file’s material variants it wears, by position
joints null Skin joints set by hand, after any clip
morphWeights null How far each of the file’s morph targets is dialled in, 0 to 1

A mesh path that cannot be read is drawn as the cube, and the reason comes back through OrblitView.onSceneNotes. What a file holds once it has loaded, meaning its clips, skins, variants, lights and cameras, comes back through OrblitView.onAssetInfo.

Field Default
position, target required Vector3
fieldOfView 50 Degrees. Ignored when orthographic.
orthographic false
viewHeight 10 World units, when orthographic
aperture 16 f-stop
shutterSpeed 1/125 Seconds
sensitivity 100 ISO

The last three are a real exposure. Defaults are “sunny 16”, correct for a scene lit at 100,000 lux.

Field Default
key, kind, intensity required Lux for directional, lumens otherwise
colour white Vector3
position the origin Point, spot and area
direction straight down Directional and spot, and the face an area light emits from
falloffRadius 10 Metres. Also what lets a light be culled.
innerConeAngle 0.5 Radians. Spot. Full brightness inside.
outerConeAngle 0.6 Radians. Spot. Zero outside; the gap is the soft edge.
sunAngularRadius 0.263 Degrees. The sun’s apparent size, so how soft its shadows are.
sourceRadius 0.1 Metres. A larger source casts softer shadows.
haloSize, haloFalloff 10, 80 Directional. The glow round the sun’s disk in the sky, and how quickly it fades.
castShadows true
width, height 1, 1 Metres. Area. The rectangle’s size, which spreads its light rather than adding to it.
tangent (1, 0, 0) Area. The edge width is measured along.

Filament honours one directional light per scene. A second is reported back rather than quietly ignored.

Field
key Required
transforms Float32List, 16 floats each
colours Float32List, 3 floats each
minimum, maximum The bounds the whole population sits inside, so the lot can be culled at once
mesh Optional; the built-in cube otherwise
range Metres past which a member isn’t drawn. Default 0, which draws all of them
fade How a member goes once it’s past range. Default OrblitFade.sink
revision Bump it when the buffers change, so unchanged frames cost nothing
castShadows Default false, since a hundred thousand shadow casters is rarely what anyone meant
receiveShadows Default true
layer Default 0. The whole population is on one layer
final cost = await OrblitView.gpuMilliseconds(textureId);

Milliseconds, not a frame rate. How often a frame is presented is the display’s business, and a renderer with twice the headroom it needs looks identical there. The value is the median of the last handful rather than the mean, because a mean is dragged about by the one frame in thirty that hits a hitch.

textureId comes from OrblitView.onViewport, which is called once with the view’s own number.

Per-pass costs are available too, through OrblitView.capture(textureId, scene.passNames). That’s the point of declaring passes rather than hard-coding them: which passes ran, in what order, and what each cost are the three questions asked of a renderer that is too slow, and a fixed pipeline cannot answer any of them without being instrumented by hand every time somebody asks.