Skip to content

Shadow

Workbench supports casting a single shadow from an arbitrary shadow direction. The shadow is artificial as it is not connected to any of the built-in lights. It only darken the overall intensity of the shading in shadowed regions.

This directional shadow is rendered using shadow volumes.

We implement both the depth-fail and depth-pass variants and switch between them depending on camera position. Note that depth-pass do not need to render the volume caps and thus are faster.

Also note that winding order for generated geometry matters, as the stencil operation is not the same for front and back-faces.

Manifold Meshes

For manifold meshes, every face backfacing the light will always be occluded by front faces that are closer to the light. This is because the mesh is closed. This mean we can skip extruding them.

To generate the shadow volume, we extrude each patch of faces that faces the light, along the light direction.

Diagram of a cross-section of manifold shadow caster and its associated shadow volumes

  • Each edge where adjacent faces have different facing state is extruded into a quad, to form one of the volume sides.
  • Each face facing the light is duplicated and positioned at both ends of the volume, creating the volume caps.

Non-Manifold Meshes

For non-manifold meshes, the previous assumption about backfaces doesn't hold. So we have to extrude all surfaces.

We split the surface into patch of faces that has the same facing state. This is because shadow volumes have to be all manifold.

Diagram of a cross-section of non-manifold shadow caster and its associated shadow volumes

  • Each edge where adjacent faces have different facing state is extruded twice into two quad, as it belongs to 2 different volumes.
  • Each edge with no neighbor (border edge) is also extruded but only once, as it belongs to 1 volume.
  • All faces are duplicated and positioned at both ends of the volume, to create the volume caps. Light back-facing faces have their winding reversed to have consistent winding per volume.

Implementation Detail

Transparent surfaces do not cast shadows.

The detph-fail method is forced for non-manifold as it is incompatible with them.

The depth-pass and depth-fail render passes are both populated for manifold objects, with the GPU culling selecting between both.

The volume extrusion is done directly on the GPU using the position vertex buffer. The drawcall uses the primitive expansion API to generate a number of primitives for each input primitive. This is alike to a geometry shader but is faster and is compatible cross graphic API. See the documentation for more detail.