Technologies and Software Engineering

Understanding GLSL Shaders for Web Graphics

Overview

GLSL (OpenGL Shading Language) is a C-like, strongly-typed language executed directly by the GPU’s graphics pipeline. It enables advanced visual effects and computations in web-based 3D graphics, complementing JavaScript rendering APIs like WebGL.

Key Insights

Technical Details

Shaders are fundamental GPU-processed functions for rendering graphics. They operate in parallel, simultaneously processing numerous vertices or pixels.

Core Shader Types

Vertex Shaders

A vertex shader executes once per vertex, manipulating 3D vertex coordinates and projecting them onto a 2D screen.

Fragment Shaders

A fragment shader executes once per pixel (or fragment), determining its final color.

Implementing Shaders with Three.js

Integrate custom GLSL shaders into a Three.js scene to render a simple cube. Three.js simplifies the underlying WebGL setup.

Environment Setup

A basic Three.js project requires the Three.js library and a <canvas> element.

HTML Structure

Embed GLSL shader code and main JavaScript logic within script tags in the HTML:

<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8" />
    <title>MDN Games: Shaders demo</title>
    <style>
      html,
      body,
      canvas {
        margin: 0;
        padding: 0;
        width: 100%;
        height: 100%;
        font-size: 0;
      }
    </style>
    <script src="three.min.js"></script>
  </head>
  <body>
    <script id="vertexShader" type="x-shader/x-vertex">
      // Vertex shader code here
    </script>
    <script id="fragmentShader" type="x-shader/x-fragment">
      // Fragment shader code here
    </script>
    <script>
      // Three.js scene setup and application logic here
    </script>
  </body>
</html>

Cube Integration

Begin with a standard Three.js cube setup. Modify its material to utilize custom shaders, reusing existing renderer, camera, and lights.

Vertex Shader Implementation

This shader translates the cube’s position:

void main() {
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position.x+10.0, position.y, position.z+5.0, 1.0);
}

Fragment Shader Implementation

This shader assigns a static blue color to the cube:

void main() {
    gl_FragColor = vec4(0.0, 0.58, 0.86, 1.0);
}

Applying the Shaders

Integrate GLSL code into the Three.js scene by creating a ShaderMaterial:

// Comment out or remove the basic material
// const basicMaterial = new THREE.MeshBasicMaterial({color: 0x0095DD});

// Create ShaderMaterial
const shaderMaterial = new THREE.ShaderMaterial({
  vertexShader: document.getElementById("vertexShader").textContent,
  fragmentShader: document.getElementById("fragmentShader").textContent,
});

// Assign the shader material to the cube
// const cube = new THREE.Mesh(boxGeometry, basicMaterial);
const cube = new THREE.Mesh(boxGeometry, shaderMaterial);

This configuration instructs Three.js to compile and execute the provided GLSL shaders for the cube object, overriding default material properties.

Complete Code Example

<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8" />
    <title>MDN Games: Shaders demo</title>
    <style>
      body {
        margin: 0;
        padding: 0;
        font-size: 0;
      }
      canvas {
        width: 100%;
        height: 100%;
      }
    </style>
    <script src="https://end3r.github.io/MDN-Games-3D/Shaders/js/three.min.js"></script>
  </head>
  <body>
    <script id="vertexShader" type="x-shader/x-vertex">
      void main() {
          gl_Position = projectionMatrix * modelViewMatrix * vec4(position.x+10.0, position.y, position.z+5.0, 1.0);
      }
    </script>
    <script id="fragmentShader" type="x-shader/x-fragment">
      void main() {
          gl_FragColor = vec4(0.0, 0.58, 0.86, 1.0);
      }
    </script>
    <script>
      const WIDTH = window.innerWidth;
      const HEIGHT = window.innerHeight;

      const renderer = new THREE.WebGLRenderer({ antialias: true });
      renderer.setSize(WIDTH, HEIGHT);
      renderer.setClearColor(0xdddddd, 1);
      document.body.appendChild(renderer.domElement);

      const scene = new THREE.Scene();

      const camera = new THREE.PerspectiveCamera(70, WIDTH / HEIGHT);
      camera.position.z = 50;
      scene.add(camera);

      const boxGeometry = new THREE.BoxGeometry(10, 10, 10);

      const shaderMaterial = new THREE.ShaderMaterial({
        vertexShader: document.getElementById("vertexShader").textContent,
        fragmentShader: document.getElementById("fragmentShader").textContent,
      });

      const cube = new THREE.Mesh(boxGeometry, shaderMaterial);
      scene.add(cube);
      cube.rotation.set(0.4, 0.2, 0);

      function render() {
        requestAnimationFrame(render);
        renderer.render(scene, camera);
      }
      render();
    </script>
  </body>
</html>
Tags:

Search