Hologram Shader: Creating a Sci-Fi Projection Effect in Three.js

Introduction

In this article, we’ll break down a custom holographic shader effect in Three.js, using GLSL shaders to achieve a glitchy, sci-fi aesthetic. We’ll explore the Vertex Shader, Fragment Shader, and the JavaScript setup, highlighting key techniques such as:

  • Procedural distortion (glitch effect)
  • Fresnel shading for a glowing outline
  • Animated holographic stripes

By the end, you’ll have a holographic sphere that looks futuristic and dynamic.

1. JavaScript Setup in Three.js

Initializing the Mesh

The THREE.Mesh is created using:

  • SphereGeometry (a simple sphere)
  • ShaderMaterial (custom shaders)
mesh = new THREE.Mesh(
  new THREE.SphereGeometry(10, 64, 64), // High detail sphere
  new THREE.ShaderMaterial({
    uniforms: {
      u_time: new THREE.Uniform(0), // Animation time
      u_col: new THREE.Uniform(new THREE.Color(0x00ffff)), // Holographic cyan color
    },
    vertexShader: vShader,
    fragmentShader: fShader,
    transparent: true,
    side: THREE.DoubleSide, // Render both sides of the sphere
    depthWrite: false, // Prevents depth issues with transparency
    blending: THREE.AdditiveBlending, // Soft glow effect
    // wireframe: true, // Uncomment to debug geometry
  })
);
scene.add(mesh);

Animation Loop

  • Updates time (u_time) for shader animation
  • Rotates the sphere for dynamic motion
  • Uses Stats.js for performance monitoring
let stats = new Stats();
document.body.appendChild(stats.dom);

function animate() {
  let elapsedTime = clock.getElapsedTime();
  mesh.material.uniforms.u_time.value = elapsedTime; // Pass time to shader
  mesh.rotation.y += 0.001; // Slow rotation
  stats.update();
  requestAnimationFrame(animate);
  renderer.render(scene, camera);
}

2. Vertex Shader: Adding the Glitch Effect

Purpose

The vertex shader manipulates vertex positions to create a randomized glitch effect by slightly displacing vertices over time.

Key Features

  • Random 2D function: Generates random displacement for glitching
  • Sinusoidal distortion: Adds a wave-like movement to the glitch
  • Position jittering: Makes the sphere’s surface distort randomly over time

Vertex Shader Code

uniform float u_time; 

varying vec3 vNorm;
varying vec3 vPos;

// Generates pseudo-random numbers based on a 2D coordinate
float random2d(vec2 coord) {
    return fract(sin(dot(coord.xy, vec2(12.9898, 78.233))) * 43758.5453);
}

void main() {
    vec4 modelPosition = modelMatrix * vec4(position, 1.0);

    // Time-based glitch effect
    float glitchTime = u_time - modelPosition.y;
    float glitchStrength = sin(glitchTime) + sin(glitchTime * 3.45) + sin(glitchTime * 8.76);
    glitchStrength /= 3.0;
    glitchStrength = smoothstep(0.8, 1.0, glitchStrength);
    glitchStrength *= 0.1; // Strength of distortion

    // Apply random displacement
    modelPosition.x += (random2d(modelPosition.xz + u_time) - .5) * glitchStrength;
    modelPosition.z += (random2d(modelPosition.zx + u_time) - .5) * glitchStrength;

    gl_Position = projectionMatrix * viewMatrix * modelPosition;

    vec4 modelNorm = modelMatrix * vec4(normal, 0.0);
    vNorm = modelNorm.xyz;
    vPos = modelPosition.xyz;
}

Explanation

  • The random2d function generates pseudo-random noise for displacement.
  • Sinusoidal distortion (sin(glitchTime)) adds a smooth yet erratic effect.
  • Smoothstep function ensures a natural transition in glitch strength.
  • Position jittering (random2d(...)) makes the object appear dynamically distorted.

3. Fragment Shader: Holographic Effect

Purpose

The fragment shader controls the color and shading effects, using Fresnel shading and striped holographic patterns.

Key Features

  • Fresnel effect: A soft glow on the edges for a sci-fi look
  • Holographic stripes: Animated horizontal scan lines
  • Transparency and glow blending: Creates a floating light-like effect

Fragment Shader Code

uniform float u_time;
uniform vec3 u_col;

varying vec3 vPos;
varying vec3 vNorm;

void main() {
    vec3 normal = normalize(vNorm);
    if (!gl_FrontFacing) {
        normal = -normal; // Fix normal for inside faces
    }

    // Moving stripes effect
    float stripes = mod((vPos.y - u_time * 0.02) * 5.0, 1.0);
    stripes = pow(stripes, 3.0); // Softens stripe edges

    // Fresnel effect for glow
    vec3 viewDir = normalize(vPos - cameraPosition);
    float fresnel = dot(viewDir, normal) + 1.0;
    fresnel = pow(fresnel, 2.0); 

    // Fade effect towards edges
    float fallOff = 1.0 - smoothstep(0.8, 0.0, fresnel);

    // Combining effects
    float holo = stripes * fresnel;
    holo += fresnel * 1.25; // Amplifies glow
    holo *= fallOff; // Smooth blending

    gl_FragColor = vec4(u_col, holo); // Final color output

    #include <tonemapping_fragment>
    #include <colorspace_fragment>
}

Explanation

  • Stripes Animation
  • Uses mod() to create moving scan lines along the Y-axis.
  • pow(stripes, 3.0) makes them softer and more natural.
  • Fresnel Glow Effect
  • dot(viewDir, normal) calculates the angle-based glow intensity.
  • pow(fresnel, 2.0) amplifies the glow effect.
  • Edge Fading (Fall-off)
  • Smoothstep ensures that the glow fades out smoothly near the edges.
  • Final Color Output
  • The glow effect (holo) is multiplied by fallOff for better blending.
  • Uses THREE.js tonemapping and colorspace for proper rendering.

Final Output

This shader produces a glowing, glitchy holographic sphere, complete with:

  • Dynamic time-based distortion
  • Animated holographic stripes
  • Smooth Fresnel glow on edges
  • Transparent, floating effect

Leave a comment

Your email address will not be published. Required fields are marked *