cast_shadow — 3D render op

• Data kinds: mesh × vector → image2d

• Call: import fullseye as fs; fs.ledger.cast_shadow(V, F, light, *, pose=None, intrinsics=None, width: 'int' = 256, height: 'int' = 256, directional: 'bool' = True, penumbra: 'float' = 0.0, samples: 'int' = 16, shadow_res: 'int' = 512, bias=None, pcf: 'int' = 0) -> 'np.ndarray' (to call the implementation directly, import render_shadow; render_shadow.cast_shadow(V, F, light, *, pose=None, intrinsics=None, width: 'int' = 256, height: 'int' = 256, directional: 'bool' = True, penumbra: 'float' = 0.0, samples: 'int' = 16, shadow_res: 'int' = 512, bias=None, pcf: 'int' = 0) -> 'np.ndarray'; from the registry, ops3d.get("cast_shadow"))

Usage

Compute a mesh's cast / soft shadows and return a visibility map (H,W) ∈ [0,1].

1=fully lit / 0=fully shadowed. Background pixels with no receiving surface are 1.0.

Args:

• V, F vertices (N,3) and triangles (M,3). An empty mesh cannot cast shadows, so it is rejected.

• light (3,) vector. If directional=True, the direction of parallel light (scene → light source); if False, the world position of a point light.

• pose/intrinsics camera. When omitted, filled in by render3d.auto_view.

• penumbra angular radius (degrees) of an area light. 0 gives hard shadows; the larger, the wider the penumbra.

• samples number of penumbra samples (used only when penumbra>0; Fibonacci disc).

• shadow_res resolution of 1 side of the shadow map.

• bias depth bias of the shadow test (world units). None sets it automatically from the texel size and the slope (suppresses acne / peter-panning).

• pcf radius [texel] of the neighbourhood mixed when sampling the shadow map. 0 (default) is the 1 nearest point = as before. With 1, the 3x3 decisions are averaged (it does not average depths —— averaging depths smooths near and far together and creates surfaces that do not exist). It mitigates the boundary being quantised to texels into a staircase without raising the shadow map resolution.

The method is shadow mapping (Williams 1978): take depth from the light source with render_mesh, project the receiving-surface points on the camera side into light space and compare depths. fail-closed: degenerate meshes, invalid light sources and non-positive sizes/resolutions raise ValueError.

Background guides (the physics and conventions behind this op)

• blender_interop — Using Blender alongside — build the shape, measure it with fullseye (pitfalls: axes, units, ground truth)

References (sample data, literature)

• Sample-data catalog (download URLs / licences) — 2-D uses skimage.data (BSD/public domain) plus synthetic images; 3-D lists download URLs for real data sources (Stanford, PDS, …).

• Operator provenance and references — the sources of the research/methods this op family came from.

Runnable examples (verified samples that actually call this op)

• render_beauty — py -3.11 examples_3d/render_beauty.py

• render_shadow — py -3.11 examples_3d/render_shadow.py

Ops the type connects to (they accept image2d as input)

fuse_to_voxel · fit_poly_surface · eval_poly_surface · surface_form_error · background_flatten · polar_unwrap · fit_zernike · matcap_shade

Same category (render)

project_points · render_point_depth · render_volume_projection · render_shaded · ambient_occlusion · phong_shade · matcap_shade · supersample_mesh


*Provenance: render_shadow.py — 3D operator registry. This per-op note is generated by tools/opdocs.py md (do not hand-edit).*

© 2026 Kazufumi Furuse — Fullseye operator documentation. Licensed under Apache-2.0.