Frontend Development 12 min read

Advanced Three.js and Shader Techniques for Hero Sections with Post‑Processing

This article walks through building an eye‑catching Hero Section using Three.js, custom GLSL shaders, dynamic point lights, and post‑processing effects such as UnrealBloomPass, FilmPass, and a custom ShaderPass, providing complete code snippets and practical tips for front‑end developers.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Advanced Three.js and Shader Techniques for Hero Sections with Post‑Processing

In the introduction the author explains the motivation to promote Web3D and share advanced Three.js and shader knowledge, then outlines the prerequisites: a solid understanding of core Three.js components (Scene, Camera, Renderer, Geometry, Material, Mesh) and basic GLSL shader syntax.

Hero Section Overview

Hero Section refers to the large visual banner at the top of a page, which for developers means the immediate visual impact that keeps users on the site.

The author presents a demo project (Fluid Light) with interactive mouse‑drag and click controls, providing URLs for live preview, debug view, and source code.

Basic Scene Construction

A simple scene is created consisting of a plane geometry that receives lighting and several point lights.

Plane Geometry

this.geometry = new THREE.PlaneGeometry(2 * screenAspectRatio, 2);

The material uses MeshPhysicalMaterial with a displacement map and normal map to achieve realistic surface detail.

this.material = new THREE.MeshPhysicalMaterial({
  color: '#121423',
  metalness: 0.59,
  roughness: 0.41,
  displacementMap: downloadedTexture,
  displacementScale: 0.1,
  normalMap: downloadedNormalMap,
  normalScale: new THREE.Vector2(0.68, 0.75),
  side: THREE.FrontSide
});

The mesh is then added to the scene:

this.mesh = new THREE.Mesh(this.geometry, this.material);
scene.add(this.mesh);

Lighting Setup

Multiple point lights are created via a helper function that returns an object containing the light and a target color.

createPointLight(intensity) {
  const light = new THREE.PointLight(0xffffff, intensity, 100, Math.random() * 10);
  light.position.copy(this.lightPosition);
  return { object: light, targetColor: new THREE.Color() };
}

Several lights with different intensities are instantiated and assigned distinct colors.

this.colors = [new THREE.Color('orange'), new THREE.Color('red'), new THREE.Color('lightblue'), new THREE.Color('green'), new THREE.Color('blue')];
this.lights = [
  this.createPointLight(2),
  this.createPointLight(3),
  this.createPointLight(2.5),
  this.createPointLight(10),
  this.createPointLight(2),
  this.createPointLight(3)
];
for (let i = 0; i < this.lights.length; i++) {
  this.lights[i].object.color.copy(this.colors[Math.min(i, this.colors.length - 1)]);
  this.scene.add(this.lights[i].object);
}

On mouse click the color array is shuffled and each light receives a new target color; the render loop then smoothly interpolates each light’s color using an easing function.

window.addEventListener('click', () => {
  this.colors = [...this.colors.sort(() => Math.random() - 0.5)];
  this.colorTransition = true;
  for (let i = 0; i < this.lights.length; i++) {
    const idx = Math.min(i, this.colors.length - 1);
    this.lights[i].targetColor = this.colors[idx].clone();
  }
});

update() {
  if (this.colorTransition) {
    let allDone = true;
    for (let i = 0; i < this.lights.length; i++) {
      const smooth = 0.25 + i * 0.05;
      this.dampC(this.lights[i].object.color, this.lights[i].targetColor, smooth, delta);
      if (!this.isColorClose(this.lights[i].object.color, this.lights[i].targetColor)) {
        allDone = false;
      }
    }
    if (allDone) this.colorTransition = false;
  }
}

Post‑Processing Enhancements

After the basic scene is ready, the author adds visual polish using the Three.js post‑processing pipeline: EffectComposer , RenderPass , UnrealBloomPass , and FilmPass .

this.composer = new EffectComposer(this.renderer);
this.composer.addPass(this.renderPass);
this.composer.addPass(this.bloomPass);
this.composer.addPass(this.filmPass);

A custom ShaderPass is introduced to manipulate UV coordinates for a subtle screen‑warp effect.

import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js';
const BaseShader = {
  name: 'BaseShader',
  uniforms: { tDiffuse: { value: null }, opacity: { value: 1.0 } },
  vertexShader: `
    varying vec2 vUv;
    void main() {
      vUv = uv;
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
  `,
  fragmentShader: `
    uniform float opacity;
    uniform sampler2D tDiffuse;
    varying vec2 vUv;
    void main() {
      vec2 uv = vUv;
      uv.y += sin(uv.x * frequency + offset) * amplitude;
      gl_FragColor = opacity * texture2D(tDiffuse, uv);
    }
  `
};
const BasePass = new ShaderPass(BaseShader);
this.composer.addPass(BasePass);

The combined effect yields a vibrant, cinematic Hero Section with dynamic lighting, bloom, film grain, and subtle distortion.

Conclusion

The article emphasizes that as AI lowers the barrier to 3D development, front‑end engineers should adopt modern Web3D tools like Three.js to create compelling visual experiences, and the shared techniques can be directly applied to production projects.

frontendgraphicsThree.jsWebGLShader3Dpostprocessing
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.