---
title: "Reflections"
description: "Part of the rendering guide (guides { path = \"topics/rendering\" }), which lists every part."
section: "Topics"
slug: "topics-rendering-reflections"
canonical: "https://origozero.ai/docs/topics-rendering-reflections"
updated: "2026-10-15T11:08:40.241036774+00:00"
tags: ["documentation", "guide", "rendering"]
---

# Reflections

## Reflections — the sky, probes, and the screen

Every standard-PBR surface reflects its surroundings through the environment
term: a metal mirrors them at its own colour, a dielectric takes them at a
Fresnel weight that is a few percent head-on and rises toward a grazing angle,
and the surface's roughness picks how blurred the reflection is. What "the
surroundings" are comes from three sources, and a scene picks up the first one
with nothing set up.

**The sky, by default.** The scene's sky is captured once into the environment
and follows the sky from there, so a chrome ball reflects the sky it stands
under and a wet floor reflects the horizon at a grazing angle. A scene with no
probe reflects this everywhere. `renderer.reflectionEnvironment()` reports it
as `sky` / `skyCaptured`.

**A reflection probe, where a surface should reflect the room.** A probe bakes
the scene around one point into a cube; surfaces within its `radius` reflect
that cube instead of the sky, at a weight that falls from full at the probe to
zero at the radius, and beyond every probe's radius a surface reflects the sky
again. Place one per room, size `radius` to the room, and give it a `box`
proxy sized to the walls so the reflection stays anchored as the camera moves:

```lua
entity.find("lobby").component.add("ReflectionProbe", {
    radius = 12, proxy = "box", proxyExtentX = 6, proxyExtentY = 3, proxyExtentZ = 6,
    probeId = "lobby",       -- the baked cube's stable identity across reloads
})
reflectionProbe.bakeAll()    -- bake every probe once the scene is built
```

Every field is live in the inspector. Two probes that overlap crossfade by
proximity; a small probe ranked above the large one it sits inside (`priority`)
wins outright where it reaches full weight. The `baking` toolbox's
**reflections** tool places and bakes a covering set across the scene in one
call, and its **clear** tool removes them. Up to eight probes are seated at
once; `reflectionProbe.list()` names them. A probe reflects once it holds a
baked cube: one that is placed and never baked adds nothing to the frame, reads
`baked = false` in `reflectionProbe.list()` and in `lighting.get`'s
`environment`, and the engine log names it with the call that bakes it.

**Screen-space reflections, for what moves.** A probe records the room as it
was baked; a character walking across a polished floor is not in it. The
`@builtin::systems.reflections.ssr` render feature reflects whatever the camera
can see this frame, on every surface below its `roughnessCutoff`, with nothing
authored per surface. List it on the scene's `RenderFeatures` entity:

```lua
entity(entity.spawn("render features").id).component.add("RenderFeatures", {
    features = {
        { feature = "@builtin::systems.reflections.ssr", settings = { intensity = 1.0, maxDistance = 40, quality = "high" } },
    },
})
```

Only what is on screen can be reflected, so reflections fade toward the frame
edge, and where the ray finds nothing the surface keeps the probe or sky it
reflected already. A hit stands in for the environment inside the material's
own shading — the trace writes the scene's reflection channel at the
`afterDepthPrepass` seam, once the visibility raster has laid this frame's depth, and the material's environment
term reads it the same frame — so a floor's roughness blurs it, a metal's
colour tints it and a dielectric shows it by its angle, each by the rule the
material states, the reflection stands where the camera is now, and the
`reflection` capture pass shows it. The
package's guide covers every knob: `guides { path = "systems/reflections" }`.

Which to reach for: the sky is already there; add probes when a room's walls
should show in its floor; add the component when moving things should.

**Seeing what a surface reflects.** `capture { pass = "reflection" }` draws
every surface as the environment it reflects — the probes whose radius
reaches it and the sky under them, along its reflection vector at its own
roughness mip, and the screen-space reflection traced for it where one was —
before Fresnel and albedo weigh it into the lit frame. A mirror
reads as the room it mirrors, a rough surface as that room blurred, a point no
probe reaches as the sky, and with the sky fallback off as black. It answers
whether a probe reaches a surface, whether its proxy anchors the room as the
camera moves, and how far a roughness blurs it, without the lit pixel in the
way.
