top of page

INVERSED HULL

I use HDRP Custom Passes plus a inversed hull shader to draw a stylized outline around selected objects.

Grow a “hull” mesh in Shader Graph by offsetting Position (Object) along the vertex normals and rendering only this inflated shell as a transparent overlay.

Use HDRP Custom Passes to render the hull after the opaque pass, so the outline always sits on top of the scene.

BREAKDOWN

PART 1

This section follows the actual production order I would use to build the effect from scratch, and ties each step back to the underlying rendering logic.

Building the Interior Volume

I start by constructing the interior as a simple box made from six planes: The front plane faces outward toward the camera and acts as the visible “paper wall” / portal surface. The other five planes (back, left, right, top, bottom) have their normals flipped inward, forming a closed room that is only meant to be seen from inside.

This separation is important: the front plane belongs to the outer scene and participates in normal opaque rendering, while the other five planes belong to the interior volume that will be injected later through a custom pass. Conceptually, the effect is:

  • Render the world as usual, including the front plane.

  • Use the front plane to write a stencil mask.

  • In a later pass, draw the interior room only where that mask is present.

Layers and Camera Culling

To drive this separation, I organize the scene into layers:

  • Default / regular layers – walls, ground, lighting, and any non-portal geometry stay in their usual layers and render in the standard HDRP opaque pass.

  • Interior layer (e.g., StencilR2) – all five inward-facing planes and any props inside the room are moved onto a dedicated layer.

  • The main camera’s culling mask is configured to exclude this interior layer, so the room never appears in the normal forward path.

At this point, if I press Play, the camera only sees the outer environment plus the front plane; the interior volume is completely invisible because it is culled. This prepares the scene so that only a Custom Pass can bring the interior back.

Stencil Front Plane Marking the Portal Region

To drive this separation, I first organize the scene into layers and then give the front plane a dedicated portal material.

  • The front plane is still a simple quad, but its material is a transparent HDRP Shader Graph that samples Scene Color and applies a noise-driven UV offset. Two scrolling Gradient Noise textures are combined and scaled by controllable parameters (tiling, scroll speed, distortion strength, IOR scale X/Y), then used to distort the screen-space UVs before reading Scene Color. This creates a refractive, shimmering surface that feels like a “window” into another space rather than a flat cutout.

  • Inside this Shader Graph (or via a material stencil override), the front plane also writes to a chosen User Bit in the stencil buffer (for example, User Bit 0).

  • During the normal opaque pass, the front plane shades with this distortion effect and simultaneously tags its pixels in the stencil buffer.

Visually, the result is a stylized, refractive rectangle sitting on an otherwise flat wall. In GPU state, however, every pixel that belongs to the portal opening now carries a unique stencil value that I can test against later in Custom Passes.

Custom Pass – Re-Drawing the Interior with Stencil + Depth

The core of the effect is a DrawRenderers Custom Pass that re-introduces the interior volume after the standard opaque pass:

  • The Custom Pass Volume is set to Global with injection point “After Opaque and Sky”.

  • Inside it, a DrawRenderers entry targets the interior layer (e.g., StencilR2).

Logic-wise, this pass does two combined tests for every interior pixel:

  • Depth test (LessEqual) against the already-rendered scene, so interior geometry only appears where it is not behind existing walls.

  • Stencil test reading the same user bit that the front plane wrote. Only fragments whose screen position overlaps the portal’s stencil mask are allowed to render.

Because the main camera never draws the interior in the regular path, the only place it can show up is where the stencil mask is set by the portal front. From oblique angles, where the portal surface is no longer covering the room, the depth test and culling ensure the room remains fully hidden behind the exterior wall.

In practice, this means I am re-ordering the render pipeline only for a specific subset of objects (the interior layer), without touching HDRP code:

  • Standard HDRP renders sky and opaque geometry (including the front plane).

  • My Custom Pass then “patches” the frame by drawing additional pixels wherever the stencil + depth conditions are satisfied, effectively compositing a 3D room onto a flat plane.

To avoid artifacts and give the depth test a proper background, I keep a simple background object on the Default layer behind the portal volume. This ensures the room always has something to compare against in the depth buffer, avoiding undefined regions when the interior extends beyond the outer shell.

View-Based Portal Activation (Preventing Overlaps)

In more complex scenes with multiple portals, simply relying on stencil can cause overlapping volumes to “black out” when several stencil portals intersect on screen. To keep control over visibility, I add a view-based activator script:

  • Each portal registers a set of renderers / GameObjects that represent its front cap and any helper meshes.

  • Every few frames, the script measures the angle between the portal’s forward axis and the camera and performs a raycast / spherecast from the camera to the portal’s bounds.

  • When the camera is in front of the portal and has a clear line of sight, the script hides the front cap and enables the interior targets; when the camera moves outside a configurable exit angle or occlusion is detected, it restores the cap and disables the associated interior objects.

This add-on keeps the stencil portal robust in real gameplay: portals do not leak, do not create black voids when stacked, and only reveal their interior room when the player is truly looking through them.

bottom of page