Vignette & Lens Distortion
Camera imperfections including dark edges (vignette) and radial lens warping.
Game Over
What this code does
- VignetteShader: a classic effect that darkens the corners of the screen to draw focus to the center.
- Custom Lens Pass: implements a radial distortion shader to simulate barrel or pincushion lens warping.
- Strength Control: adjust the intensity of the lens distortion from negative (pincushion) to positive (barrel).
- Composition: multiple effect passes are layered via the EffectComposer to create a polished camera look.
- Scene Context: a simple room setup helps visualize how straight lines warp under lens distortion.
JavaScript Implementation
ES6+
const scene = new THREE.Scene()
scene.background = new THREE.Color(0x222222)
const camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000)
camera.position.set(2, 2, 5)
const renderer = new THREE.WebGLRenderer({ antialias: true })
renderer.setSize(width, height)
document.body.appendChild(renderer.domElement)
const composer = new EffectComposer(renderer)
composer.addPass(new RenderPass(scene, camera))
const lensPass = new ShaderPass({
uniforms: { 'tDiffuse': { value: null }, 'strength': { value: 0.1 } },
vertexShader: 'varying vec2 vUv; void main() { vUv = uv; gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); }',
fragmentShader: 'uniform sampler2D tDiffuse; uniform float strength; varying vec2 vUv; void main() { vec2 uv = vUv - 0.5; float r2 = uv.x*uv.x + uv.y*uv.y; uv *= 1.0 + r2 * strength; uv += 0.5; if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0) gl_FragColor = vec4(0,0,0,1); else gl_FragColor = texture2D(tDiffuse, uv); }'
})
composer.addPass(lensPass)
const vignettePass = new ShaderPass(VignetteShader)
vignettePass.uniforms.darkness.value = 1.0
composer.addPass(vignettePass)
scene.add(new THREE.Mesh(new THREE.BoxGeometry(2, 2, 2), new THREE.MeshStandardMaterial({ color: 0x0077ff })))
scene.add(new THREE.AmbientLight(0xffffff, 0.5))
const light = new THREE.DirectionalLight(0xffffff, 1)
light.position.set(5, 10, 5)
scene.add(light)
function animate() {
requestAnimationFrame(animate)
composer.render()
}
animate()