Advanced guide: Reflection probes¶
Time: ~15 minutes Level: Intermediate What you'll build: A scene with zone-based environment reflections on metallic objects
Overview¶
ReflectionProbeNode lets you override the scene's image-based lighting (IBL) for specific
zones. This is essential for realistic metallic or glossy materials — a chrome sphere should
reflect the environment around it, not a generic sky.
Step 1 — Global reflection probe¶
The simplest use: replace the scene's default IBL with a specific environment.
@Composable
fun ReflectionScreen() {
val engine = rememberEngine()
val modelLoader = rememberModelLoader(engine)
val environmentLoader = rememberEnvironmentLoader(engine)
val environment = rememberEnvironment(environmentLoader) {
environmentLoader.createHDREnvironment("environments/studio.hdr")!!
}
var cameraPosition by remember { mutableStateOf(Position()) }
val cameraNode = rememberCameraNode(engine) {
position = Position(z = 3f)
}
Scene(
engine = engine,
modelLoader = modelLoader,
cameraNode = cameraNode,
environment = environment,
onFrame = { cameraPosition = cameraNode.worldPosition }
) {
// Global probe — always active (radius = 0)
ReflectionProbeNode(
filamentScene = scene,
environment = environment,
cameraPosition = cameraPosition
)
rememberModelInstance(modelLoader, "models/metallic_sphere.glb")?.let {
ModelNode(modelInstance = it)
}
}
}
Step 2 — Local zone probes¶
Use radius to create zones with different reflections — e.g., indoor vs outdoor:
val outdoorEnv = rememberEnvironment(environmentLoader) {
environmentLoader.createHDREnvironment("environments/sky.hdr")!!
}
val indoorEnv = rememberEnvironment(environmentLoader) {
environmentLoader.createHDREnvironment("environments/office.hdr")!!
}
Scene(
engine = engine,
modelLoader = modelLoader,
environment = outdoorEnv,
onFrame = { cameraPosition = cameraNode.worldPosition }
) {
// Outdoor — global fallback
ReflectionProbeNode(
filamentScene = scene,
environment = outdoorEnv,
cameraPosition = cameraPosition
)
// Indoor zone — active within 3m of (0, 1, -5)
ReflectionProbeNode(
filamentScene = scene,
environment = indoorEnv,
position = Position(x = 0f, y = 1f, z = -5f),
radius = 3f,
priority = 1, // wins over global when camera is inside
cameraPosition = cameraPosition
)
}
How zone priority works¶
When the camera is inside multiple probe zones, the one with the highest priority wins.
If priorities are equal, the last one in composition order wins.
Step 3 — Toggle probes reactively¶
Since probes are composables, toggling is just an if statement:
var probeEnabled by remember { mutableStateOf(true) }
Scene(...) {
if (probeEnabled) {
ReflectionProbeNode(
filamentScene = scene,
environment = studioEnv,
cameraPosition = cameraPosition
)
}
}
Parameters reference¶
| Parameter | Effect |
|---|---|
filamentScene |
The Filament Scene whose indirect light is overridden |
environment |
Environment containing the IndirectLight to apply |
position |
Centre of the reflection zone in world space |
radius |
Zone radius in metres. 0 = always active (global) |
priority |
Higher value wins when zones overlap |
cameraPosition |
Updated each frame from onFrame callback |
What's next¶
- See the
reflection-probesample for material switching (Chrome, Gold, Copper, Rough) - Combine with
FogNodeandDynamicSkyNodefor complete atmospheric scenes