React Three Fiber Post-Processing Quick Start import { Canvas } from '@react-three/fiber' import { EffectComposer, Bloom, Vignette } from '@react-three/postprocessing'
function Scene() { return (
<EffectComposer>
<Bloom luminanceThreshold={0.5} luminanceSmoothing={0.9} intensity={1.5} />
<Vignette offset={0.5} darkness={0.5} />
</EffectComposer>
</Canvas>
) }
Installation npm install @react-three/postprocessing postprocessing
EffectComposer
The container for all post-processing effects.
import { EffectComposer } from '@react-three/postprocessing'
function Scene() { return (
{/* Post-processing - must be inside Canvas, after scene content */}
<EffectComposer
enabled={true} // Toggle all effects
depthBuffer={true} // Enable depth buffer
stencilBuffer={false} // Enable stencil buffer
autoClear={true} // Auto clear before render
multisampling={8} // MSAA samples (0 to disable)
>
{/* Effects go here */}
</EffectComposer>
</Canvas>
) }
Common Effects Bloom (Glow) import { EffectComposer, Bloom } from '@react-three/postprocessing' import { BlendFunction } from 'postprocessing'
// For objects to glow, use emissive materials
Selective Bloom import { EffectComposer, Bloom, Selection, Select } from '@react-three/postprocessing'
function Scene() { return (
{/* This mesh will bloom */}
<Select enabled>
<mesh>
<sphereGeometry />
<meshStandardMaterial emissive="red" emissiveIntensity={2} toneMapped={false} />
</mesh>
</Select>
{/* This mesh will NOT bloom */}
<mesh position={[2, 0, 0]}>
<boxGeometry />
<meshStandardMaterial color="blue" />
</mesh>
</Selection>
</Canvas>
) }
Depth of Field import { EffectComposer, DepthOfField } from '@react-three/postprocessing'
// With target object import { useRef } from 'react'
function Scene() { const targetRef = useRef()
return (
<>
<EffectComposer>
<DepthOfField
target={targetRef}
focalLength={0.02}
bokehScale={2}
/>
</EffectComposer>
</>
) }
Vignette import { EffectComposer, Vignette } from '@react-three/postprocessing'
Noise import { EffectComposer, Noise } from '@react-three/postprocessing' import { BlendFunction } from 'postprocessing'
Chromatic Aberration import { EffectComposer, ChromaticAberration } from '@react-three/postprocessing' import { BlendFunction } from 'postprocessing'
SSAO (Screen Space Ambient Occlusion) import { EffectComposer, SSAO } from '@react-three/postprocessing' import { BlendFunction } from 'postprocessing'
Outline import { EffectComposer, Outline, Selection, Select } from '@react-three/postprocessing'
function Scene() { return (
{/* Outlined object */}
<Select enabled>
<mesh>
<boxGeometry />
<meshStandardMaterial color="orange" />
</mesh>
</Select>
{/* Non-outlined object */}
<mesh position={[2, 0, 0]}>
<sphereGeometry />
<meshStandardMaterial color="blue" />
</mesh>
</Selection>
</Canvas>
) }
Color Grading import { EffectComposer, BrightnessContrast, HueSaturation } from '@react-three/postprocessing'
Tone Mapping import { EffectComposer, ToneMapping } from '@react-three/postprocessing' import { ToneMappingMode } from 'postprocessing'
Glitch import { EffectComposer, Glitch } from '@react-three/postprocessing' import { GlitchMode } from 'postprocessing'
Pixelation import { EffectComposer, Pixelation } from '@react-three/postprocessing'
Scanline import { EffectComposer, Scanline } from '@react-three/postprocessing' import { BlendFunction } from 'postprocessing'
Grid import { EffectComposer, Grid } from '@react-three/postprocessing' import { BlendFunction } from 'postprocessing'
DotScreen import { EffectComposer, DotScreen } from '@react-three/postprocessing' import { BlendFunction } from 'postprocessing'
SMAA (Anti-Aliasing) import { EffectComposer, SMAA } from '@react-three/postprocessing'
FXAA (Anti-Aliasing) import { EffectComposer, FXAA } from '@react-three/postprocessing'
Combining Multiple Effects import { EffectComposer, Bloom, Vignette, ChromaticAberration, Noise, SMAA } from '@react-three/postprocessing' import { BlendFunction } from 'postprocessing'
function PostProcessing() {
return (
{/* Color aberration */}
<ChromaticAberration
offset={[0.001, 0.001]}
radialModulation
modulationOffset={0.5}
/>
{/* Film grain */}
<Noise
premultiply
blendFunction={BlendFunction.ADD}
opacity={0.2}
/>
{/* Vignette */}
<Vignette
offset={0.3}
darkness={0.5}
/>
{/* Anti-aliasing (should be last) */}
<SMAA />
</EffectComposer>
) }
Custom Effects Using postprocessing Effect Class import { forwardRef, useMemo } from 'react' import { Effect, BlendFunction } from 'postprocessing' import { Uniform } from 'three'
// Fragment shader const fragmentShader = ` uniform float time; uniform float intensity;
void mainImage(const in vec4 inputColor, const in vec2 uv, out vec4 outputColor) { vec2 distortedUv = uv; distortedUv.x += sin(uv.y * 10.0 + time) * 0.01 * intensity;
vec4 color = texture2D(inputBuffer, distortedUv);
outputColor = color;
} `
// Effect class class WaveDistortionEffect extends Effect { constructor({ intensity = 1.0, blendFunction = BlendFunction.NORMAL } = {}) { super('WaveDistortionEffect', fragmentShader, { blendFunction, uniforms: new Map([ ['time', new Uniform(0)], ['intensity', new Uniform(intensity)], ]), }) }
update(renderer, inputBuffer, deltaTime) { this.uniforms.get('time').value += deltaTime } }
// React component wrapper
export const WaveDistortion = forwardRef(({ intensity = 1.0, blendFunction }, ref) => {
const effect = useMemo(() => new WaveDistortionEffect({ intensity, blendFunction }), [intensity, blendFunction])
return
// Usage
Shader with wrapEffect import { wrapEffect } from '@react-three/postprocessing' import { Effect, BlendFunction } from 'postprocessing' import { Uniform } from 'three'
class InvertEffect extends Effect {
constructor({ blendFunction = BlendFunction.NORMAL } = {}) {
super('InvertEffect', void mainImage(const in vec4 inputColor, const in vec2 uv, out vec4 outputColor) {
outputColor = vec4(1.0 - inputColor.rgb, inputColor.a);
}, {
blendFunction,
})
}
}
export const Invert = wrapEffect(InvertEffect)
// Usage
Conditional Effects import { useState } from 'react' import { EffectComposer, Bloom, Vignette, Glitch } from '@react-three/postprocessing'
function ConditionalPostProcessing() { const [effects, setEffects] = useState({ bloom: true, vignette: true, glitch: false, })
return (
<>
{/* UI to toggle effects */}
<div className="controls">
<button onClick={() => setEffects(e => ({ ...e, bloom: !e.bloom }))}>
Toggle Bloom
</button>
<button onClick={() => setEffects(e => ({ ...e, vignette: !e.vignette }))}>
Toggle Vignette
</button>
<button onClick={() => setEffects(e => ({ ...e, glitch: !e.glitch }))}>
Toggle Glitch
</button>
</div>
</>
) }
Animated Effects import { useRef } from 'react' import { useFrame } from '@react-three/fiber' import { EffectComposer, Bloom, ChromaticAberration } from '@react-three/postprocessing'
function AnimatedEffects() { const bloomRef = useRef() const chromaticRef = useRef()
useFrame(({ clock }) => { const t = clock.elapsedTime
// Animate bloom intensity
if (bloomRef.current) {
bloomRef.current.intensity = 1 + Math.sin(t) * 0.5
}
// Animate chromatic aberration
if (chromaticRef.current) {
const offset = Math.sin(t * 2) * 0.002
chromaticRef.current.offset.set(offset, offset)
}
})
return (
N8AO (High Quality AO) import { EffectComposer } from '@react-three/postprocessing' import { N8AO } from '@react-three/postprocessing'
God Rays import { EffectComposer, GodRays } from '@react-three/postprocessing' import { useRef } from 'react'
function Scene() { const sunRef = useRef()
return (
<EffectComposer>
{sunRef.current && (
<GodRays
sun={sunRef}
blendFunction={BlendFunction.SCREEN}
samples={60}
density={0.96}
decay={0.9}
weight={0.4}
exposure={0.6}
clampMax={1}
blur
/>
)}
</EffectComposer>
</Canvas>
) }
LUT (Color Lookup Table) import { EffectComposer, LUT } from '@react-three/postprocessing' import { LUTCubeLoader } from 'postprocessing' import { useLoader } from '@react-three/fiber'
function ColorGradedScene() { const texture = useLoader(LUTCubeLoader, '/luts/cinematic.cube')
return (
Blend Functions import { BlendFunction } from 'postprocessing'
// Available blend functions: BlendFunction.SKIP // Skip blending BlendFunction.ADD // Additive BlendFunction.ALPHA // Alpha BlendFunction.AVERAGE // Average BlendFunction.COLOR // Color BlendFunction.COLOR_BURN // Color Burn BlendFunction.COLOR_DODGE // Color Dodge BlendFunction.DARKEN // Darken BlendFunction.DIFFERENCE // Difference BlendFunction.DIVIDE // Divide BlendFunction.DST // Destination BlendFunction.EXCLUSION // Exclusion BlendFunction.HARD_LIGHT // Hard Light BlendFunction.HARD_MIX // Hard Mix BlendFunction.HUE // Hue BlendFunction.INVERT // Invert BlendFunction.INVERT_RGB // Invert RGB BlendFunction.LIGHTEN // Lighten BlendFunction.LINEAR_BURN // Linear Burn BlendFunction.LINEAR_DODGE // Linear Dodge BlendFunction.LINEAR_LIGHT // Linear Light BlendFunction.LUMINOSITY // Luminosity BlendFunction.MULTIPLY // Multiply BlendFunction.NEGATION // Negation BlendFunction.NORMAL // Normal BlendFunction.OVERLAY // Overlay BlendFunction.PIN_LIGHT // Pin Light BlendFunction.REFLECT // Reflect BlendFunction.SATURATION // Saturation BlendFunction.SCREEN // Screen BlendFunction.SET // Set BlendFunction.SOFT_LIGHT // Soft Light BlendFunction.SRC // Source BlendFunction.SUBTRACT // Subtract BlendFunction.VIVID_LIGHT // Vivid Light
Performance Tips
Limit effect count: Each effect adds rendering overhead
Use multisampling wisely: Higher values = slower performance
Disable when not needed: Toggle enabled prop
Lower resolution: Some effects have resolution props
Profile with DevTools: Monitor GPU usage
// Disable all effects
// Reduce effect quality on mobile const isMobile = /iPhone|iPad|Android/i.test(navigator.userAgent)
See Also r3f-shaders - Custom shader development r3f-materials - Emissive materials for bloom r3f-fundamentals - Canvas and renderer setup