DepthOfFieldPlugin (Depth of Field Plugin)
Depth of Field (DOF) Plugin adds realistic camera focus effects by blurring areas that are closer or farther than the focal point, simulating the behavior of physical camera lenses and drawing attention to specific subjects.
The DepthOfFieldPlugin implements a high-quality multi-pass depth of field algorithm that computes circle of confusion (CoC) based on distance from the focal plane, applies sophisticated blur using Poisson disk sampling, and composites the result for photorealistic bokeh effects.
Features
- Interactive Focal Point: Click on objects to set focus (with edit mode enabled)
- Configurable Depth Range: Adjust the depth of field falloff
- Separate Near/Far Blur: Independent control for foreground and background blur
- High-Quality Poisson Blur: Uses disk sampling for realistic bokeh
- Visual Focus Indicator: Shows focal point with crosshair overlay
- Smooth Transitions: Automatic cross-fade when changing focus
- GBuffer Integration: Leverages depth data for accurate CoC calculation
- Half-Resolution Processing: Efficient blur computation at lower resolution
- Progressive Rendering Support: Works with temporal accumulation
- Programmatic Control: Set focal point via API or user interaction
Installation
This plugin is part of the @threepipe/webgi-plugins package:
npm install @threepipe/webgi-pluginsBasic Setup
import {ThreeViewer, PickingPlugin} from 'threepipe'
import {DepthOfFieldPlugin} from '@threepipe/webgi-plugins'
const viewer = new ThreeViewer({
canvas: document.getElementById('canvas'),
msaa: true,
plugins: [PickingPlugin] // For interactive focus
})
// Add DOF plugin
const dof = viewer.addPluginSync(new DepthOfFieldPlugin())
// Enable interactive editing (click to focus)
dof.enableEdit = true
// Load model
await viewer.load('model.glb')
// Set initial focal point
dof.setFocalPoint(new Vector3(0, 1, 0), false, true)With this setup, users can click on objects to change the focal point, and areas outside the focal range will be blurred.
Configuration
Depth Range
Control the depth of field range (how quickly blur increases with distance):
const dofPass = dof.pass
// Depth range: controls DoF falloff (0.25-3)
dofPass.depthRange = 1.5 // Default, moderate DoF
dofPass.depthRange = 0.5 // Shallow DoF (tight focus)
dofPass.depthRange = 2.5 // Deep DoF (wider focus range)Smaller values create a tighter focus with stronger blur, similar to a wide aperture lens (f/1.4). Larger values create a wider focus range with gentler blur, like a narrow aperture (f/16).
Near and Far Blur Scale
Independently control foreground and background blur strength:
const dofPass = dof.pass
// Near blur scale: blur strength for objects closer than focal point (0-1)
dofPass.nearBlurScale = 0.25 // Default, subtle foreground blur
dofPass.nearBlurScale = 0.5 // Stronger foreground blur
dofPass.nearBlurScale = 0.0 // No foreground blur
// Far blur scale: blur strength for objects farther than focal point (0-1)
dofPass.farBlurScale = 0.25 // Default, subtle background blur
dofPass.farBlurScale = 0.8 // Strong background blur
dofPass.farBlurScale = 0.0 // No background blurYou can create effects like:
- Portrait mode: High far blur, low near blur
- Macro photography: High near and far blur
- Selective focus: Different blur strengths for artistic control
Interactive Focus
Enable or disable interactive focal point selection:
// Enable clicking to set focus
dof.enableEdit = true
// Disable interactive focus
dof.enableEdit = false
// Users can now click on objects to change the focal point
// A crosshair indicator shows where focus is setWhen enabled, clicking on objects automatically sets the focal point to the clicked location with smooth transitions.
Transition Settings
Control the fade animation when changing focus:
// Cross-fade time in milliseconds (default: 200ms)
dof.crossFadeTime = 200 // Quick transition
dof.crossFadeTime = 500 // Slower, cinematic transition
dof.crossFadeTime = 1000 // Very slow transition
// The focal point indicator shows during transitionsLonger transition times create smoother, more cinematic focus changes.
Advanced Usage
Programmatic Focus Control
Set focal point via code with full control:
import {Vector3} from 'threepipe'
// Set focal point to specific world position
const focalPoint = new Vector3(5, 2, 0)
// With smooth transition and visual indicator
dof.setFocalPoint(focalPoint, true, true)
// Without transition (instant)
dof.setFocalPoint(focalPoint, false, false)
// Get current focal point
const currentFocus = dof.getFocalPoint()
console.log('Focus at:', currentFocus)The three parameters of setFocalPoint are:
- point: World-space position (Vector3)
- fade: Enable smooth cross-fade transition (boolean)
- showGizmo: Show crosshair indicator (boolean)
Camera-Relative Focus
Focus on objects relative to camera:
// Get object position
const objectPos = model.position.clone()
// Set focus with transition
dof.setFocalPoint(objectPos, true, true)
// Update camera to look at the same point
viewer.scene.mainCamera.target.copy(objectPos)
viewer.scene.mainCamera.setDirty()Focus Animation
Animate focus changes over time:
import {PopmotionPlugin, EasingFunctions, Vector3} from 'threepipe'
const popmotion = viewer.getOrAddPluginSync(PopmotionPlugin)
const startPos = new Vector3(0, 0, 0)
const endPos = new Vector3(5, 0, 0)
const tempPos = new Vector3()
popmotion.animate({
from: 0,
to: 1,
duration: 3000,
ease: EasingFunctions.easeInOutQuad,
onUpdate: (v) => {
// Interpolate between positions
tempPos.lerpVectors(startPos, endPos, v)
dof.setFocalPoint(tempPos, false, false)
},
})This creates a smooth focus pull effect between two points.
Combining with Bloom
DOF and Bloom work together for cinematic effects:
import {DepthOfFieldPlugin, BloomPlugin} from '@threepipe/webgi-plugins'
const viewer = new ThreeViewer({
canvas: document.getElementById('canvas'),
msaa: true,
maxHDRIntensity: 8
})
// Add both effects
const dof = viewer.addPluginSync(new DepthOfFieldPlugin())
const bloom = viewer.addPluginSync(new BloomPlugin())
// Configure for bokeh effect with bright highlights
bloom.pass.intensity = 1.5
bloom.pass.threshold = 1.0
dof.pass.depthRange = 1.0
dof.pass.farBlurScale = 0.6Bright areas in blurred regions create realistic bokeh with glowing highlights.
Rack Focus Effect
Create a focus pull between two objects:
// Start focused on object A
const objectA = scene.getObjectByName('objectA')
dof.setFocalPoint(objectA.position, false, true)
// After delay, pull focus to object B
setTimeout(() => {
const objectB = scene.getObjectByName('objectB')
dof.setFocalPoint(objectB.position, true, true)
}, 2000)
// The smooth transition creates a cinematic rack focusCustom Focal Distance
Set focus at specific distance from camera:
const camera = viewer.scene.mainCamera
// Get camera position and direction
const camPos = camera.position.clone()
const camDir = camera.getWorldDirection(new Vector3())
// Set focal point 5 units ahead of camera
const focalPoint = camPos.add(camDir.multiplyScalar(5))
dof.setFocalPoint(focalPoint, true, false)Disable Transitions with FrameFadePlugin
Control frame fade behavior:
import {FrameFadePlugin} from 'threepipe'
const frameFade = viewer.getPluginSync(FrameFadePlugin)
if (frameFade) {
// Disable automatic frame fades during DOF transitions
frameFade.enabled = false
}
// Or adjust the fade duration via crossFadeTime
dof.crossFadeTime = 100 // Faster, less noticeable fadeHow It Works
The DepthOfFieldPlugin operates through a multi-pass rendering pipeline:
Depth Sampling: Read depth buffer from GBufferPlugin
- Gets per-pixel depth information
- Camera near/far values from scene
Circle of Confusion (CoC) Computation: Calculate blur amount per pixel
- Computes distance from focal plane
- Applies depth range formula
- Separate CoC for near and far regions
- Outputs to half-resolution render target
CoC Expansion: Blur the near-field CoC
- Two-pass separable blur (horizontal + vertical)
- Spreads foreground blur into background
- Prevents sharp edges on near-field blur
Poisson Disk Blur: Apply high-quality blur
- Uses Poisson disk sampling pattern
- Multiple samples distributed in disk shape
- Weighted by CoC value
- Creates realistic bokeh effect
- Operates at half-resolution for efficiency
Final Composition: Blend sharp and blurred images
- Uses CoC as blend factor
- Composites near and far blur
- Adds optional crosshair indicator
- Outputs final depth-of-field result
The multi-pass approach provides high-quality results while maintaining good performance through half-resolution blur processing.
Performance Considerations
- Half-Resolution Blur: DOF processes blur at 50% resolution for efficiency
- Multi-Pass Overhead: Requires 5+ render passes (CoC, expand, blur, composite)
- Poisson Sampling: High-quality but more expensive than box blur
- GBuffer Dependency: Requires depth buffer (minimal extra cost)
- Memory Usage: Multiple half-resolution render targets
Tips for optimization:
- Reduce
depthRangefor simpler blur calculations - Lower blur scales reduce blur intensity and sampling
- Consider disabling during camera motion on lower-end devices
- Half-resolution processing already provides good performance balance
Use Cases
The DepthOfFieldPlugin is ideal for:
- Product Visualization: Focus attention on specific product features
- Cinematic Presentations: Create film-like focus effects
- Character Portraits: Blur background for subject emphasis
- Interactive Stories: Guide viewer attention through focus changes
- Photography Simulation: Realistic camera depth of field
- Macro Visualization: Simulate close-up photography effects
- Focus Reveals: Dramatically change scene focus for impact
Common Patterns
Portrait Photography Effect
For subject isolation with blurred background:
dof.pass.depthRange = 1.0
dof.pass.nearBlurScale = 0.15
dof.pass.farBlurScale = 0.6
dof.enableEdit = true
// Focus on subject's face
dof.setFocalPoint(facePosition, true, false)Macro Photography Effect
For extreme close-ups with strong blur:
dof.pass.depthRange = 0.5
dof.pass.nearBlurScale = 0.7
dof.pass.farBlurScale = 0.7
// Very shallow depth of fieldCinematic Rack Focus
For dramatic focus pulls between subjects:
dof.crossFadeTime = 800 // Slow, cinematic
dof.pass.depthRange = 1.2
dof.pass.farBlurScale = 0.5
// Pull focus between objects with smooth transitionSubtle Product Focus
For gentle emphasis without distraction:
dof.pass.depthRange = 2.0
dof.pass.nearBlurScale = 0.15
dof.pass.farBlurScale = 0.25
// Subtle blur, maintains contextDependencies
- GBufferPlugin (required): Provides depth buffer for CoC calculation
- PickingPlugin (optional): Enables interactive focus selection
- FrameFadePlugin (optional): Provides smooth transitions between focus changes
Troubleshooting
DOF not visible:
- Check that depth range is appropriate for scene scale
- Increase blur scale values (near/far)
- Ensure focal point is set (visible with showGizmo)
- Verify GBufferPlugin is loaded
Interactive focus not working:
- Enable with
dof.enableEdit = true - Ensure PickingPlugin is added
- Check that objects have geometry to click on
- Verify objects are not marked as non-pickable
Blur too strong or weak:
- Adjust
depthRange(smaller = stronger blur) - Modify blur scales (
nearBlurScale,farBlurScale) - Check focal point distance from objects
- Scene scale affects blur perception
Artifacts or harsh edges:
- Increase
depthRangefor gentler falloff - Reduce blur scale values if over-blurred
- Ensure proper depth buffer in GBufferPlugin
- Check for depth discontinuities in geometry
Performance issues:
- DOF is relatively expensive (5+ passes)
- Consider disabling during camera motion
- Reduce canvas resolution if needed
- Half-resolution processing already optimized
- Check if other heavy effects are combined
Focus transitions too fast/slow:
- Adjust
crossFadeTimeproperty (milliseconds) - Shorter times = snappier focus changes
- Longer times = smoother, cinematic pulls
- Default 200ms is generally good
Examples
Check out these examples to see the plugin in action:
- Depth of Field Plugin - Interactive DOF with focus selection
- Bloom Plugin - DOF combined with bloom for bokeh
See Also
- BloomPlugin - Creates bokeh highlights in blurred areas
- SSReflectionPlugin - Screen-space reflections
- GBufferPlugin - Required depth buffer
- PickingPlugin - Enables interactive focus selection
- FrameFadePlugin - Smooth transition effects
- ProgressivePlugin - Frame accumulation support
