ShadowCatcherMaterial class Materials
An invisible ground surface that receives shadows and ambient occlusion.
Assign it to a plane under a model and the plane itself never shows; it
writes only the darkening that grounds the model, so a product scene
composites over a transparent Flutter background (or any backdrop) with a
believable contact to the ground. The output is
(shadowColor * alpha, alpha) where
alpha = saturate(shadowIntensity * (1 - shadow visibility) + aoStrength * (1 - occlusion)) * radial fade.
The shadow term samples the same aggregate the lit path shades with, the
directional light's cascades, every shadow-casting spot's atlas tile, and
the sun contact term marched by the occlusion chain, so the catcher's
shadow always matches what lit geometry receives. The occlusion term
samples the screen-space ambient-occlusion chain and therefore needs the
scene's ambient occlusion enabled to contribute (the contact term needs
DirectionalLight.contactShadows); with both off, only the mapped shadow
term draws.
The catcher draws into the linear HDR scene color as ordinary translucent geometry, before the resolve pass applies exposure, tone mapping, and the display transform. That staging is load-bearing: the overlay rides the same exposure and tone curve as the geometry that casts onto it, so the shadow neither over-darkens nor washes out as the scene's exposure moves.
Unlike other translucent materials, the catcher also joins the camera depth prepass, so the screen-space chain evaluates occlusion, contact shadows, and depth effects at the plane's own depth rather than the backdrop behind it. The plane therefore acts like a ground surface for every screen-space effect (a model standing on it gains ambient occlusion from it, and depth of field focuses on it), which is the behavior a real ground plane would have.
mode selects how the atlas shadow term is evaluated. The default ShadowCatcherMode.live samples the atlas per frame and stays correct as lights and casters move. ShadowCatcherMode.baked renders the footprint shadow once into a low-resolution cache (blurred by softness) and samples that instead, cheaper and right for a static product scene, but stale until markBakedShadowsDirty is called after the lights or casters change. Baked mode assumes a ground-plane-like mesh lying in its local XZ plane (the cache is a top-down footprint).
shadowIntensity doubles as the enable switch. At exactly 0 the
catcher registers no draws in any pass at all, a true early-out.
Construct only after Scene.initializeStaticResources() has completed
(the Scene constructor starts it); the material draws with the engine's
bundled catcher shader, which loads there.
Constructors
- ShadowCatcherMaterial({Color shadowColor = const Color(0xFF000000), double shadowIntensity = 0.8, double aoStrength = 0.5, double softness = 0.0, double fadeStart = 0.0, double fadeEnd = 0.0, ShadowCatcherMode mode = ShadowCatcherMode.live})
- Creates a shadow catcher. All parameters can be reassigned later.
Properties
- aoStrength ↔ double
-
How strongly screen-space ambient occlusion darkens the surface,
0to1. Contributes only while the scene's ambient occlusion is enabled.getter/setter pair - depthBias ↔ double
-
World-space offset toward the camera used for coplanar surface details.
Positive values keep an overlay in front of its supporting surface
without modifying its node transform. Zero and negative values leave the
draw position unchanged. A fixed world offset provides fewer depth-buffer
units as camera distance grows, so distant coplanar surfaces may need a
larger value.
getter/setter pairinherited
- depthPrepassParticipates → bool
-
Whether this material's geometry joins the camera depth prepass that
feeds the screen-space chain (ambient occlusion, contact shadows,
reflections, depth of field).
no setter
- doubleSided ↔ bool
-
Whether to render both faces of triangles drawn with this material
(glTF's
material.doubleSided). When true, bind disables back-face culling so the geometry is visible from both sides; otherwise back faces are culled. Defaults to false. The runtime importer sets it from the glTF material.getter/setter pairinherited - drawsNothing → bool
-
Whether this material currently draws nothing at all, keeping its render
items out of every pass (color, depth prepass, shadows).
no setter
- fadeEnd ↔ double
-
Radial distance from the mesh origin, in the mesh's local units, where
the overlay reaches zero, so the plane has no hard visible edge.
getter/setter pair
- fadeStart ↔ double
-
Radial distance from the mesh origin, in the mesh's local units, where
the overlay starts fading out. See fadeEnd.
getter/setter pair
- fragmentShader → Shader
-
The fragment shader used when rendering geometry with this material.
no setteroverride
- hashCode → int
-
The hash code for this object.
no setterinherited
- mode ↔ ShadowCatcherMode
-
How the shadow term is evaluated; see ShadowCatcherMode.
getter/setter pair
- name ↔ String
-
The name of this material, used for identification.
getter/setter pairinherited
- runtimeType → Type
-
A representation of the runtime type of the object.
no setterinherited
-
sceneInputs
→ Set<
RenderInput> -
Per-frame engine inputs this material samples, produced only when a
visible material asks for them: RenderInput.depth binds the linear
scene depth of the opaque geometry (forcing the depth prepass), and
RenderInput.opaqueSceneColor binds the accumulated scene color behind
the current draw, and RenderInput.filteredSceneColor adds its
roughness-filtered atlas.
Together they enable refraction, depth-fade absorption, shoreline
foam, and soft-particle style effects on translucent surfaces. The
base material requests nothing; a
.fmatmaterial declares these withengine_inputs:.no setterinherited - shadowColor ↔ Color
-
The color the surface darkens toward where it is shadowed or occluded.
getter/setter pair
- shadowIntensity ↔ double
-
How strongly aggregate shadow visibility darkens the surface,
0to1.getter/setter pair - softness ↔ double
-
World-space penumbra radius for this catcher's shadow, decoupled from
the scene's shadow settings.
getter/setter pair
Methods
-
bind(
RenderPass pass, TransientWriter transientsBuffer, Lighting lighting) → void -
Binds this material's render-pass state, uniforms, and textures.
override
-
bindVertexStage(
RenderPass pass, Shader vertexShader, TransientWriter transientsBuffer) → void -
Binds this material's vertex-stage uniforms to
vertexShader, called by the encoder only when it used a material-supplied vertex shader (see materialVertexShader). The base implementation is a no-op; a material with vertex-stage parameters binds them here. -
fragmentShaderForLighting(
Lighting lighting) → Shader - Selects this material's fragment shader for the frame lighting state.
-
isOpaque(
) → bool -
Whether geometry rendered with this material is fully opaque.
override
-
markBakedShadowsDirty(
) → void - Schedules a re-bake of the cached footprint shadow.
-
materialVertexShader(
String variant) → Shader? -
The vertex shader this material supplies for a geometry's
variant('unskinned'/'skinned'for the color pass,'depth'for the position-only depth/shadow pass; seeGeometry.materialVertexVariant), or null to use the engine's standard vertex shader for the geometry. -
noSuchMethod(
Invocation invocation) → dynamic -
Invoked when a nonexistent method or property is accessed.
inherited
-
setFragmentShader(
Shader shader) → void -
Assigns the fragment
shaderused when this material is drawn.inherited -
setFragmentShaderName(
String name, {String? cubeName, String? noShadowName, String? noShadowCubeName}) → void -
Assigns the fragment shader by
namefrom baseShaderLibrary.inherited -
setRadianceCubeFragmentShader(
Shader? shader) → void -
Assigns the already-loaded variant built with
FLUTTER_SCENE_RADIANCE_CUBE, the counterpart of setFragmentShader for a material that samples the environment.inherited -
toString(
) → String -
A string representation of this object.
inherited
Operators
-
operator ==(
Object other) → bool -
The equality operator.
inherited