ShaderMaterial Banding

by Matt

HTML

<base href="https://rawcdn.githack.com/mrdoob/three.js/r156/examples/" />
<script async src="https://cdn.jsdelivr.net/npm/[email protected]/dist/es-module-shims.js"></script>
<script type="importmap">
	{
		"imports": {
			"three": "https://cdn.jsdelivr.net/npm/[email protected]/build/three.module.js",
			"three/addons/": "https://cdn.jsdelivr.net/npm/[email protected]/examples/jsm/"
		}
	}
</script>

<template id="vertex-shader">
varying vec3 vPos;

void main() {
  vPos = position;
	gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
</template>

<template id="fragment-shader">
varying vec3 vPos;

void main() {
  float radius = length(vPos);
  float gaussian = exp( -0.5 * radius * radius );
	gl_FragColor = vec4(vec3(gaussian), 1.0);
}
</template>

CSS

canvas {
	position: fixed;
	inset: 0;
}

JavaScript

import * as THREE from 'three'
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'

let scene, camera, renderer
let mesh, orbitControls, clock
let params

init().then(animate)

async function init() {

	scene = new THREE.Scene()
	scene.background = new THREE.Color('black')

	camera = new THREE.PerspectiveCamera(75, undefined, 0.1, 1000)
	camera.position.set(0, 0, 10)
	
	clock = new THREE.Clock()

	const directionalLight = new THREE.DirectionalLight('white', Math.PI)
	directionalLight.position.set(2, 3, 4)
	scene.add(directionalLight)

	const ambientLight = new THREE.AmbientLight('white', 0.3 * Math.PI)
	scene.add(ambientLight)

	renderer = new THREE.WebGLRenderer({ antialias: true })
	document.body.appendChild(renderer.domElement)

	orbitControls = new OrbitControls(camera, renderer.domElement)

	const vertexShader = document.querySelector("#vertex-shader").content.textContent
	const fragmentShader = document.querySelector("#fragment-shader").content.textContent
	
	const geometry = new THREE.PlaneGeometry(100, 100)
	const material = new THREE.ShaderMaterial({
		vertexShader,
		fragmentShader
	})
	
	mesh = new THREE.Mesh(geometry, material)
	scene.add(mesh)

	onWindowResize()
	
	window.addEventListener('resize', onWindowResize, false)
	
}

function animate() {

	const dt = clock.getDelta()

	orbitControls.update()

	renderer.render(scene, camera)

	requestAnimationFrame(animate)

}


function onWindowResize() {

	camera.aspect = window.innerWidth / window.innerHeight
	camera.updateProjectionMatrix()
	renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))

	renderer.setSize(window.innerWidth, window.innerHeight)

}