Screen Space Reflections
Real-time reflections using render targets to create realistic water surface reflections with interactive controls.
What this code does
- Render Target Reflections: uses WebGLRenderTarget to capture scene from mirrored camera position for realistic reflections.
- Reflection Camera: mathematically mirrors main camera across reflection plane for accurate perspective.
- Dynamic Water Surface: adjustable water level with reflective material properties and transparency controls.
- Clipping Planes: prevents objects below water surface from appearing in reflection for realistic depth.
- Interactive Controls: adjust reflection intensity, blur, water level, and material properties in real-time.
- Animated Scene: moving objects, rotating lights, and bobbing animations demonstrate reflection quality.
JavaScript (plain)
const scene = new THREE.Scene()
const camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000)
camera.position.set(0, 5, 8)
const renderer = new THREE.WebGLRenderer({ antialias: true })
renderer.setSize(width, height)
renderer.shadowMap.enabled = true
document.querySelector('#app').appendChild(renderer.domElement)
// Create reflection render target
const reflectionRenderTarget = new THREE.WebGLRenderTarget(512, 512)
const reflectionCamera = camera.clone()
// Create reflective floor
const floorGeometry = new THREE.PlaneGeometry(20, 20)
const floorMaterial = new THREE.MeshStandardMaterial({
color: 0x444444,
roughness: 0.1,
metalness: 0.8
})
const floor = new THREE.Mesh(floorGeometry, floorMaterial)
floor.rotation.x = -Math.PI / 2
floor.position.y = 0
scene.add(floor)
// Add reflectable objects
const boxGeometry = new THREE.BoxGeometry(1, 2, 1)
const materials = [
new THREE.MeshStandardMaterial({ color: 0xff4444 }),
new THREE.MeshStandardMaterial({ color: 0x44ff44 }),
new THREE.MeshStandardMaterial({ color: 0x4444ff })
]
for (let i = 0; i < 3; i++) {
const box = new THREE.Mesh(boxGeometry, materials[i])
box.position.set((i - 1) * 3, 1, 0)
box.castShadow = true
scene.add(box)
}
// Lighting
const ambientLight = new THREE.AmbientLight(0x404040, 0.3)
scene.add(ambientLight)
const directionalLight = new THREE.DirectionalLight(0xffffff, 1)
directionalLight.position.set(5, 10, 5)
directionalLight.castShadow = true
scene.add(directionalLight)
function animate() {
requestAnimationFrame(animate)
// Update reflection camera (mirror main camera across floor plane)
reflectionCamera.position.copy(camera.position)
reflectionCamera.position.y = -camera.position.y + 2 * 0 // water level
reflectionCamera.lookAt(0, -camera.position.y, 0)
// Render reflection
floor.visible = false
renderer.setRenderTarget(reflectionRenderTarget)
renderer.render(scene, reflectionCamera)
// Render main scene
floor.visible = true
floor.material.map = reflectionRenderTarget.texture
renderer.setRenderTarget(null)
renderer.render(scene, camera)
}
animate()