Depth of field

피사계 심도

Blurring objects in front of and behind the camera’s focus distance to draw the eye to what’s in focus.

Also known as: DOFBokehPassFocus blurBokeh
···
js
import * as THREE from 'three';
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
import { BokehPass } from 'three/addons/postprocessing/BokehPass.js';
import { OutputPass } from 'three/addons/postprocessing/OutputPass.js';

const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(Math.min(devicePixelRatio, 2));
document.body.appendChild(renderer.domElement);
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x0a0a14);
const camera = new THREE.PerspectiveCamera(45, 1, 0.5, 30);
camera.position.set(0, 0.3, 1.6);
camera.lookAt(0, 0, -6);

scene.add(new THREE.AmbientLight(0x556080, 1.2));
const dLight = new THREE.DirectionalLight(0xffffff, 1.1);
dLight.position.set(3, 5, 2);
scene.add(dLight);

const meshes = [];
const N = 6;
for (let i = 0; i < N; i++) {
  const mesh = new THREE.Mesh(
    new THREE.IcosahedronGeometry(0.5, 0),
    new THREE.MeshStandardMaterial({ color: new THREE.Color().setHSL(i / N, 0.65, 0.6), roughness: 0.4 })
  );
  mesh.position.set((i % 2 === 0 ? -1 : 1) * 0.6, 0, -i * 1.7 - 1);
  scene.add(mesh);
  meshes.push(mesh);
}

const composer = new EffectComposer(renderer);
composer.addPass(new RenderPass(scene, camera));
const bokeh = new BokehPass(scene, camera, { focus: 3, aperture: 0.008, maxblur: 0.01 });
composer.addPass(bokeh);
composer.addPass(new OutputPass());

function resize() {
  renderer.setSize(innerWidth, innerHeight);
  camera.aspect = innerWidth / innerHeight;
  camera.updateProjectionMatrix();
  composer.setSize(innerWidth, innerHeight);
}
addEventListener('resize', resize); resize();
renderer.setAnimationLoop((t) => {
  const time = t * 0.001;
  bokeh.uniforms.focus.value = 5.5 + Math.sin(time * 0.6) * 4.0;
  meshes.forEach((m, i) => { m.rotation.y = time * 0.6 + i; m.rotation.x = time * 0.4; });
  composer.render();
});

A real camera lens stays sharp only near its focus distance, and blurs progressively in front of and behind it (bokeh). Three.js’s BokehPass(scene, camera, { focus, aperture, maxblur }) addon first renders the scene into a depth texture, then blends in blur for each pixel proportional to how far its depth is from the focus value.

focus is the distance from the camera that stays sharp, aperture is like an f-stop (bigger means blur ramps up faster), and maxblur caps how strong the blur can get. All three can change at runtime via, say, bokehPass.uniforms.focus.value — the demo oscillates focus with a sine wave, so which of five shapes reads as sharp keeps sweeping back and forth, as if the camera were racking focus.

Because the blur samples the full-screen texture repeatedly, it’s heavier than most other post-processing. Keep the camera’s near/far tight around the scene’s actual depth range so the depth texture has enough precision for a smooth blur instead of visible banding.

When to use

Product showcases, cinematic camera moves, or anywhere focus needs to pull the eye to one subject.