Skip to content

SSReflectionPlugin (Screen Space Reflection Plugin)

ExampleAPI Reference

Screen Space Reflection (SSR) Plugin adds real-time reflections to reflective surfaces by ray-tracing against the rendered screen buffer, creating realistic mirror-like reflections of visible scene elements.

The SSReflectionPlugin implements an advanced screen-space ray-tracing algorithm that traces reflection rays through the depth buffer to find intersection points, enabling highly realistic reflections on metallic and glossy surfaces without the computational cost of traditional ray-tracing or the memory requirements of reflection probes.

Features

  • Real-Time Screen-Space Ray-Tracing: Traces reflection rays through depth buffer for accurate reflections
  • Inline or Post-Process Mode: Choose between inline shader integration or separate render pass
  • Roughness-Based Reflections: Automatic roughness-aware reflection intensity
  • Temporal Reprojection: Uses previous frames to enhance quality and reduce noise
  • Multi-Ray Sampling: Configurable ray count for smoother reflections on rough surfaces
  • Per-Material Control: Enable or disable SSR for individual materials
  • Non-Physical Mode: Optional artistic control over reflection behavior
  • Adaptive Quality: Lower quality during camera motion for better performance
  • Front Ray Masking: Avoids self-reflections and artifacts
  • GBuffer Integration: Leverages depth and normal data for accurate ray-tracing
  • Velocity Buffer Support: Works with motion vectors for temporal stability
  • Debug Split View: Compare SSR on/off side-by-side

Installation

This plugin is part of the @threepipe/webgi-plugins package:

bash
npm install @threepipe/webgi-plugins

Basic Setup

typescript
import {ThreeViewer, GBufferPlugin, SSAAPlugin} from 'threepipe'
import {SSReflectionPlugin} from '@threepipe/webgi-plugins'

const viewer = new ThreeViewer({
    canvas: document.getElementById('canvas'),
    msaa: false,
    plugins: [GBufferPlugin, SSAAPlugin]
})

// Add SSR plugin (inline mode - recommended)
const ssr = viewer.addPluginSync(new SSReflectionPlugin(true))

// Load a scene with reflective materials
await viewer.load('model.glb')

With this setup, all physically-based materials (PhysicalMaterial) with metallic or reflective properties will automatically show screen-space reflections.

Configuration

Reflection Quality

Control the quality and accuracy of reflections:

typescript
const ssrPass = ssr.pass

// Step count: ray-marching steps per ray (1-32)
ssrPass.stepCount = 16 // Balanced (default)
ssrPass.stepCount = 24 // Higher quality
ssrPass.stepCount = 8  // Better performance

// Ray count: number of rays per pixel (1-8)
ssrPass.rayCount = 1 // Sharp reflections (default)
ssrPass.rayCount = 4 // Smoother rough reflections

// Ray blend mode
ssrPass.rayBlendMax = false // Average rays (default)
ssrPass.rayBlendMax = true  // Use maximum value

Higher step counts improve accuracy but reduce performance. More rays create smoother reflections on rough surfaces but multiply the cost.

Reflection Intensity & Appearance

Adjust the strength and look of reflections:

typescript
const ssrPass = ssr.pass

// Intensity: overall reflection strength (0-4)
ssrPass.intensity = 1.0 // Default
ssrPass.intensity = 0.5 // Subtle reflections
ssrPass.intensity = 2.0 // Strong reflections

// Power: controls falloff with roughness (0-3)
ssrPass.power = 1.1 // Default
ssrPass.power = 2.0 // Stronger on smooth surfaces

// Boost: color multiplier per channel
ssrPass.boost.set(1, 1, 1) // No boost (default)
ssrPass.boost.set(1.2, 1.1, 1.0) // Slightly warm

// Roughness factor: scales material roughness (0.1-1.25)
ssrPass.roughnessFactor = 1.0 // Use material roughness
ssrPass.roughnessFactor = 0.8 // Reduce roughness effect

Ray-Tracing Parameters

Fine-tune the ray-tracing algorithm:

typescript
const ssrPass = ssr.pass

// Object radius: scene scale for ray stepping (0.01-2)
ssrPass.objectRadius = 1.0 // Default, adjust based on scene size

// Auto radius: automatically calculate from scene bounds
ssrPass.autoRadius = true // Automatic (default)
ssrPass.autoRadius = false // Use manual objectRadius

// Tolerance: intersection threshold (0.1-5)
ssrPass.tolerance = 0.5 // Default
ssrPass.tolerance = 0.2 // Tighter (fewer artifacts, may miss hits)
ssrPass.tolerance = 1.0 // Looser (more hits, may have artifacts)

Front Ray Masking

Control reflections of surfaces facing the camera:

typescript
const ssrPass = ssr.pass

// Mask front-facing rays to reduce self-reflections
ssrPass.maskFrontRays = true // Enabled (default)
ssrPass.maskFrontRays = false // Show all reflections

// Mask factor: threshold for front-facing test (-1 to 1)
ssrPass.maskFrontFactor = -0.2 // Default
ssrPass.maskFrontFactor = 0.0  // More aggressive masking
ssrPass.maskFrontFactor = -0.5 // Less masking

Performance Optimization

Reduce quality during motion for better performance:

typescript
const ssrPass = ssr.pass

// Low quality frames: reduce quality for N frames after movement (0-4)
ssrPass.lowQualityFrames = 0 // Always full quality (default)
ssrPass.lowQualityFrames = 2 // Reduced quality during motion

This temporarily reduces step and ray counts when the camera moves, improving responsiveness.

Per-Material Control

Enable or disable SSR for specific materials:

typescript
import {SSReflectionPlugin} from '@threepipe/webgi-plugins'

// Disable SSR for a material
material.userData.ssreflDisabled = true

// Enable non-physical mode (artistic control)
material.userData.ssreflNonPhysical = true

// Changes require material update
material.setDirty()

Non-physical mode ignores PBR rules and reflects based on intensity alone, useful for artistic effects.

Advanced Usage

Inline vs Post-Process Mode

Choose the rendering mode based on your needs:

typescript
// Inline mode (recommended): SSR calculated during main render
const ssr = new SSReflectionPlugin(true)

// Post-process mode: SSR calculated in separate pass
const ssr = new SSReflectionPlugin(
    false,                // inline = false
    UnsignedByteType,     // buffer type
    1.0                   // buffer size multiplier
)

Inline mode (default):

  • Better performance (single render pass)
  • Direct integration with material shading
  • No separate buffer required
  • Recommended for most use cases

Post-process mode:

  • Separate SSR buffer for debugging
  • Can apply additional processing to reflections
  • More memory usage
  • Useful for advanced effects

Temporal Stability

Combine with TAA for temporally stable reflections:

typescript
import {
    SSReflectionPlugin,
    TemporalAAPlugin,
    VelocityBufferPlugin
} from '@threepipe/webgi-plugins'

// Add plugins in order
const ssr = viewer.addPluginSync(new SSReflectionPlugin(true))
const velocityBuffer = viewer.addPluginSync(new VelocityBufferPlugin())
const taa = viewer.addPluginSync(new TemporalAAPlugin())

// SSR automatically uses velocity data for temporal reprojection
// This reduces flickering and improves quality over multiple frames

The velocity buffer helps SSR reproject previous frame data correctly when objects or camera move.

Integration with Ground Plane

SSR works well with ground planes for floor reflections:

typescript
import {BaseGroundPlugin} from 'threepipe'

const ssr = viewer.addPluginSync(new SSReflectionPlugin(true))

// Important: Add ground AFTER SSR to avoid z-fighting issues
const ground = viewer.addPluginSync(new BaseGroundPlugin())

// Configure ground for reflections
ground.material.roughness = 0.2
ground.material.metalness = 0.0
ground.material.color.set(0x1B1B1F)

The ground plane will show reflections of objects above it.

Debug Split View

Compare SSR effect side-by-side:

typescript
// Enable split view
ssr.pass.split = 0.5

// Values from 0-1 control the split position
// Left side shows without SSR, right side with SSR
// Set to 0 to disable split mode

Perfect for tuning parameters and demonstrating the effect.

Combining with Bloom

SSR and Bloom work together for realistic bright reflections:

typescript
import {SSReflectionPlugin, BloomPlugin} from '@threepipe/webgi-plugins'

const viewer = new ThreeViewer({
    canvas: document.getElementById('canvas'),
    msaa: false,
    maxHDRIntensity: 8, // Enable HDR for bloom
    plugins: [GBufferPlugin, BloomPlugin, SSAAPlugin]
})

const ssr = viewer.addPluginSync(new SSReflectionPlugin(true))
const bloom = viewer.addPluginSync(new BloomPlugin())

// Bright areas reflect with bloom glow
bloom.pass.intensity = 1.0
bloom.pass.threshold = 1.5

Visualizing the SSR Buffer (Post-Process Mode)

In post-process mode, visualize the SSR buffer:

typescript
import {RenderTargetPreviewPlugin} from 'threepipe'

const ssr = new SSReflectionPlugin(false) // Post-process mode
viewer.addPluginSync(ssr)

// Add preview plugin
const preview = viewer.addPluginSync(new RenderTargetPreviewPlugin())
preview.addTarget(
    () => ssr.target,
    'ssrefl',
    true // show in UI
)

How It Works

The SSReflectionPlugin implements a sophisticated screen-space ray-tracing algorithm:

  1. Ray Generation: For each pixel, generates reflection rays based on surface normal and view direction

    • Multiple rays for rough surfaces (distributed around reflection vector)
    • Ray direction influenced by material roughness
  2. Ray Marching: Traces rays through the depth buffer

    • Steps along ray direction in screen space
    • Compares ray depth to scene depth at each step
    • Configurable step count and tolerance
  3. Intersection Testing: Detects when ray intersects scene geometry

    • Depth comparison with tolerance threshold
    • Front-ray masking to avoid self-intersections
    • Object radius affects step size
  4. Reflection Lookup: Samples color at intersection point

    • Reads from current or previous frame buffer
    • Applies roughness-based filtering
    • Blends multiple ray samples
  5. Temporal Reprojection: Uses velocity buffer for stability

    • Reprojects previous frame reflections
    • Reduces noise and flickering
    • Maintains quality during motion
  6. Material Integration: Composites reflections with material

    • Modulates by material properties (metalness, roughness)
    • Physical or non-physical blending modes
    • Respects material enable/disable flags

The inline mode integrates steps 1-6 directly into the material shader, while post-process mode renders to a separate buffer first.

Performance Considerations

  • Step Count: Primary performance factor - directly multiplies ray-marching cost
  • Ray Count: Secondary performance factor - multiplies per-pixel cost
  • Resolution: Full-resolution ray-tracing is expensive
  • Inline Mode: Better performance than post-process mode
  • Scene Complexity: More depth variance = more ray-marching work

Tips for optimization:

  • Start with stepCount: 16 and rayCount: 1
  • Use lowQualityFrames: 2 for responsive camera movement
  • Disable SSR on non-reflective materials
  • Consider lower roughnessFactor to reduce multi-ray needs
  • Use TAA to improve quality without increasing ray count

Use Cases

The SSReflectionPlugin is ideal for:

  1. Product Visualization: Showcasing metallic, glossy, or polished products
  2. Automotive Rendering: Reflections on car paint, chrome, and glass
  3. Architectural Visualization: Reflective floors, glass, and polished surfaces
  4. Jewelry & Watches: Realistic metallic reflections on precious materials
  5. Interior Design: Mirror and glossy furniture reflections
  6. Game Environments: Real-time reflections in interactive scenes
  7. Technical Demos: Showcasing advanced rendering capabilities

Limitations

SSR has inherent screen-space limitations:

  • Off-Screen Objects: Cannot reflect objects not visible on screen
  • Edge Artifacts: Reflections may fade at screen edges
  • Occluded Surfaces: Cannot reflect surfaces behind other geometry
  • Depth Discontinuities: May show artifacts at sharp depth changes

For complete reflections, consider combining with:

  • Environment maps for distant/off-screen reflections
  • Reflection probes for local reflections
  • SSGIPlugin for indirect lighting

Common Patterns

Glossy Product Showcase

For product visualization with strong reflections:

typescript
ssr.pass.stepCount = 20
ssr.pass.rayCount = 1
ssr.pass.intensity = 1.5
ssr.pass.power = 1.5
ssr.pass.roughnessFactor = 0.9

Subtle Architectural Reflections

For realistic architectural scenes:

typescript
ssr.pass.stepCount = 16
ssr.pass.rayCount = 1
ssr.pass.intensity = 0.8
ssr.pass.power = 1.0
ssr.pass.roughnessFactor = 1.0
ssr.pass.maskFrontRays = true

Performance-Optimized Mobile

For mobile devices:

typescript
ssr.pass.stepCount = 8
ssr.pass.rayCount = 1
ssr.pass.intensity = 1.0
ssr.pass.lowQualityFrames = 3
ssr.pass.tolerance = 0.8

Dependencies

Troubleshooting

Reflections not visible:

  • Ensure materials have metalness > 0 or roughness < 1
  • Check that GBufferPlugin is added before SSReflectionPlugin
  • Verify material is PhysicalMaterial (not compatible with other material types)
  • Make sure intensity > 0

Flickering or noisy reflections:

  • Add TemporalAAPlugin for temporal stability
  • Add VelocityBufferPlugin for better reprojection
  • Increase stepCount for more accurate ray-marching
  • Adjust tolerance for better intersection detection

Self-reflections or artifacts:

  • Enable maskFrontRays (default: true)
  • Adjust maskFrontFactor (try values between -0.5 and 0.0)
  • Increase tolerance slightly
  • Check objectRadius matches scene scale

Performance issues:

  • Reduce stepCount (try 8-12)
  • Use rayCount: 1 for sharp reflections
  • Enable lowQualityFrames for motion
  • Disable SSR on non-metallic materials
  • Consider reducing canvas resolution

Reflections cut off at edges:

  • This is a limitation of screen-space techniques
  • Combine with environment map for background reflections
  • Adjust camera framing to keep reflected objects on screen

Examples

Check out these examples to see the plugin in action:

See Also

Threepipe - Next generation 3D toolkit for the web