Outline pass

아웃라인 패스

Post-processing that detects a selected object’s silhouette in screen space and highlights it with a glowing outline.

Also known as: OutlinePassSelection glowEdge detection
···
js
import * as THREE from 'three';
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
import { OutlinePass } from 'three/addons/postprocessing/OutlinePass.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(0x0c0c16);
const camera = new THREE.PerspectiveCamera(42, 1, 0.1, 100);
camera.position.set(0, 1.2, 5.2);
camera.lookAt(0, 0, 0);

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

const shapes = [
  new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), new THREE.MeshStandardMaterial({ color: 0x5b7bff, roughness: 0.5 })),
  new THREE.Mesh(new THREE.SphereGeometry(0.65, 32, 32), new THREE.MeshStandardMaterial({ color: 0xff6a8a, roughness: 0.5 })),
  new THREE.Mesh(new THREE.ConeGeometry(0.65, 1.2, 32), new THREE.MeshStandardMaterial({ color: 0x4de3b0, roughness: 0.5 })),
];
shapes[0].position.x = -1.7;
shapes[2].position.x = 1.7;
shapes.forEach((s) => scene.add(s));

const composer = new EffectComposer(renderer);
composer.addPass(new RenderPass(scene, camera));
const outlinePass = new OutlinePass(new THREE.Vector2(innerWidth, innerHeight), scene, camera);
outlinePass.edgeStrength = 5;
outlinePass.edgeGlow = 0.7;
outlinePass.edgeThickness = 2;
outlinePass.visibleEdgeColor.set(0xffd24d);
outlinePass.hiddenEdgeColor.set(0x554015);
outlinePass.pulsePeriod = 2;
outlinePass.selectedObjects = [shapes[0]];
composer.addPass(outlinePass);
composer.addPass(new OutputPass());

let active = 0;
function resize() {
  renderer.setSize(innerWidth, innerHeight);
  camera.aspect = innerWidth / innerHeight;
  camera.updateProjectionMatrix();
  composer.setSize(innerWidth, innerHeight);
}
addEventListener('resize', resize); resize();
renderer.setAnimationLoop((t) => {
  const idx = Math.floor(t / 1600) % shapes.length;
  if (idx !== active) { active = idx; outlinePass.selectedObjects = [shapes[active]]; }
  shapes.forEach((s) => { s.rotation.y = t * 0.0006; });
  composer.render();
});

The inverted-hull technique in toon-shading is a "mesh-based" outline made by scaling geometry outward. OutlinePass takes a different approach — it renders only the selected object into a separate mask (silhouette), then detects that mask’s edges in screen space, blurs them, and colors them in. That means it can outline any object instantly without touching its geometry at all.

Build it with new OutlinePass(resolution, scene, camera), then change which objects get outlined at any time just by reassigning the array: outlinePass.selectedObjects = [mesh]. visibleEdgeColor (for edges not occluded by another object) and hiddenEdgeColor (for occluded parts), plus edgeStrength, edgeGlow, and edgeThickness, control thickness and glow. Set pulsePeriod and the outline pulses like a heartbeat.

The demo places three shapes and cycles selectedObjects on a timer so you see "the currently selected object" rotate through them. In production this is usually combined with something like the raycasting entry — whatever the pointer clicks or hovers gets pushed into selectedObjects.

When to use

Highlighting a selected object in a 3D editor or game, or flagging interactive targets.