아웃라인 패스

Outline pass

선택된 오브젝트의 실루엣을 화면 공간에서 감지해 발광하는 테두리로 강조하는 후처리 기법.

다른 이름: 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();
});

toon-shading 항목의 인버티드 헐 기법은 지오메트리를 늘려서 만드는 "메시 기반" 윤곽선입니다. OutlinePass는 다른 접근입니다 — 선택된 오브젝트만 별도로 마스크(실루엣)로 렌더링한 뒤, 그 마스크의 가장자리를 화면 공간에서 검출해 흐리고 색을 입힙니다. 그래서 지오메트리를 전혀 수정하지 않고 어떤 오브젝트에든 즉시 테두리를 씌울 수 있습니다.

new OutlinePass(resolution, scene, camera) 로 만든 뒤, outlinePass.selectedObjects = [mesh]처럼 배열을 바꾸는 것만으로 어떤 오브젝트에 테두리를 두를지 실시간으로 바꿀 수 있습니다. visibleEdgeColor(다른 물체에 가려지지 않은 테두리 색)와 hiddenEdgeColor(가려진 부분의 테두리 색), edgeStrength·edgeGlow·edgeThickness로 두께와 발광 강도를 조절합니다. pulsePeriod를 주면 테두리가 맥박처럼 깜빡입니다.

데모는 3개의 도형을 두고 일정 주기로 selectedObjects를 바꿔가며 "지금 선택된 오브젝트"가 순환하는 걸 보여줍니다. 실제 프로덕션에서는 raycasting 항목처럼 마우스로 클릭/호버한 오브젝트를 selectedObjects에 넣는 식으로 조합해서 씁니다.

언제 쓰나

3D 에디터·게임에서 선택된 오브젝트 강조, 상호작용 가능한 대상을 표시할 때.