포스트 프로세싱 과욕 - 효과 5개가 3개보다 못한 이유
"이것도 넣고, 저것도 넣으면 더 멋있겠지?" 포스트 프로세싱의 달콤한 유혹에 빠졌습니다. 결과는 처참했습니다.
시작은 Bloom #
3D 포트폴리오에 Bloom 효과를 넣었습니다. 빛나는 요소들이 은은하게 퍼지는 게 예뻤습니다.
const bloomPass = new UnrealBloomPass(
new THREE.Vector2(window.innerWidth, window.innerHeight),
1.5, // 강도
0.4, // 반경
0.85 // 임계값
);
composer.addPass(bloomPass);
"좋아, 더 넣어보자."
욕심의 시작: 전부 다 넣기 #
하나하나 추가했습니다.
// 1. Bloom - 빛나는 효과
const bloomPass = new UnrealBloomPass(size, 1.5, 0.4, 0.85);
composer.addPass(bloomPass);
// 2. SSAO - 주변 폐색
const ssaoPass = new SSAOPass(scene, camera, width, height);
ssaoPass.kernelRadius = 16;
composer.addPass(ssaoPass);
// 3. Film Grain - 영화 느낌
const filmPass = new FilmPass(0.35, 0.5, 648, false);
composer.addPass(filmPass);
// 4. Vignette - 가장자리 어둡게
const vignettePass = new ShaderPass(VignetteShader);
vignettePass.uniforms.darkness.value = 1.5;
composer.addPass(vignettePass);
// 5. Chromatic Aberration - 색수차
const rgbShiftPass = new ShaderPass(RGBShiftShader);
rgbShiftPass.uniforms.amount.value = 0.003;
composer.addPass(rgbShiftPass);
문제 1: 성능 폭락 #
5개의 포스트 프로세싱 패스는 5번의 화면 렌더링을 의미합니다.
측정 결과:
- 효과 없음: 60fps
- Bloom만: 55fps
- +SSAO: 35fps
- +Film: 30fps
- +Vignette: 28fps
- +RGB Shift: 25fps
모바일에서는 10fps 이하. 사용 불가 수준이었습니다.
문제 2: 시각적 혼란 #
더 심각한 건 보기 싫어졌다는 것입니다.
Bloom이 Film Grain 위에 적용되면서 노이즈가 반짝거렸습니다. Chromatic Aberration과 Bloom이 합쳐지면서 무지개색 번짐이 생겼습니다. SSAO의 그림자에 Vignette가 겹쳐서 화면 가장자리가 너무 어두웠습니다.
"영화 같은 느낌"을 원했는데, "90년대 VHS 테이프"가 되어버렸습니다.
디자이너 친구의 조언 #
디자이너 친구에게 보여줬더니 이런 피드백을 받았습니다:
"효과가 서로 싸우고 있어. 주인공이 없어."
"뭘 보여주고 싶은 건데? 기술력? 그럼 오히려 미니멀하게 가야 해."
"효과는 '있으면 좋고'가 아니라 '목적'이 있어야 해."
다시 시작: 목적 중심 접근 #
각 효과의 목적을 정리했습니다.
- Bloom: 발광하는 요소 강조 → 필요
- SSAO: 입체감, 깊이감 → 필요하지만 성능 비용이 큼
- Film Grain: 아날로그 느낌 → 포트폴리오와 안 맞음
- Vignette: 중앙 집중 → 약하게만
- Chromatic Aberration: 렌즈 느낌 → 이 프로젝트에서 불필요
최종 구성 #
남긴 것: Bloom + 가벼운 Vignette
// Bloom (강도 낮춤)
const bloomPass = new UnrealBloomPass(size, 0.8, 0.4, 0.9);
composer.addPass(bloomPass);
// 커스텀 Vignette (가벼운 버전)
const vignettePass = new ShaderPass({
uniforms: {
tDiffuse: { value: null },
darkness: { value: 0.3 },
offset: { value: 0.9 }
},
fragmentShader: `
uniform sampler2D tDiffuse;
uniform float darkness;
uniform float offset;
varying vec2 vUv;
void main() {
vec4 color = texture2D(tDiffuse, vUv);
vec2 center = vUv - 0.5;
float dist = length(center);
float vignette = smoothstep(0.5, offset, dist);
color.rgb *= 1.0 - vignette * darkness;
gl_FragColor = color;
}
`
});
composer.addPass(vignettePass);
조건부 SSAO #
SSAO는 성능 영향이 크지만 입체감에는 효과적입니다. 고성능 기기에서만 활성화하도록 했습니다.
function setupPostProcessing() {
const tier = detectGPUTier();
composer.addPass(renderPass);
composer.addPass(bloomPass);
if (tier === 'high') {
// 고성능 기기에서만 SSAO
const ssaoPass = new SSAOPass(scene, camera, width, height);
ssaoPass.kernelRadius = 8; // 품질 낮춤
composer.addPass(ssaoPass);
}
composer.addPass(vignettePass);
}
배운 원칙들 #
1. Less is More #
효과 3개보다 잘 조정된 1개가 낫습니다.
// 나쁨: 약한 효과 여러 개
bloom: 0.5, ssao: low, film: 0.2, vignette: 0.3
// 좋음: 강한 효과 하나
bloom: 1.0 (잘 튜닝된)
2. 순서가 중요하다 #
포스트 프로세싱 패스 순서에 따라 결과가 달라집니다.
// 일반적으로 좋은 순서:
// 1. SSAO (3D 관련)
// 2. Bloom (밝기 관련)
// 3. Color Correction (색상 관련)
// 4. Film/Grain (노이즈)
// 5. Vignette (가장자리)
// 6. FXAA (안티앨리어싱, 마지막)
3. 목적을 명확히 #
효과를 추가하기 전에 질문하세요:
- 이 효과로 무엇을 표현하고 싶은가?
- 사용자 경험을 향상시키는가?
- 기존 효과와 충돌하지 않는가?
4. 성능 예산 #
포스트 프로세싱에 성능 예산을 할당하세요.
const performanceBudget = {
rendering: '60%', // 기본 씬 렌더링
postProcessing: '30%', // 후처리
other: '10%' // UI 등
};
// 후처리가 30%를 넘으면 효과 줄이기
효과 선택 가이드 #
프로젝트 유형별 추천 조합:
제품 비주얼라이저:
- Bloom (0.5): 금속/유리 하이라이트
- SSAO (약하게): 입체감
- Tone Mapping: 사실적 색감
아트/실험적 프로젝트:
- Bloom (강하게): 몽환적 분위기
- Custom Shader: 독특한 시각 효과
- Film Grain: 아날로그 느낌
게임/인터랙티브:
- FXAA: 성능 좋은 안티앨리어싱
- Bloom (중간): 마법/효과 강조
- 성능 우선으로 효과 최소화
데이터 시각화:
- 최소한의 효과
- 가독성 우선
- Bloom 피하기 (데이터 왜곡 위험)
결론 #
포스트 프로세싱은 강력하지만, "있으니까 다 써야지"는 함정입니다.
제 최종 포트폴리오:
- Bloom (0.8): 로고와 주요 요소 강조
- Vignette (0.3): 시선 집중
- 끝
처음 5개 효과를 넣었을 때보다 훨씬 깔끔하고, 성능도 좋고, "뭔가 있어 보입니다."
효과를 추가하기보다 제거할 때 디자인이 좋아지는 경우가 많습니다.
- Previous: 10만 개 파티클 렌더링 - 성능과의 싸움
- Next: TSL 입문 - GLSL 없이 Three.js 쉐이더 작성하기