ChatGPT’s solution to creating a GLSL WebGL Shader

Want to know more about GLSL check out my courses page

I was playing about with ChatGPT. I asked it

Show me how to code a GLSL shader to use in a browser

Here is what happened. The first result was this…

A GLSL (OpenGL Shading Language) shader is a program that runs on the GPU (graphics processing unit) and is used to manipulate the appearance of 3D graphics. To use a GLSL shader in a browser, you can use the WebGL API (Web Graphics Library), which is a JavaScript API that allows you to create and control a WebGL context, which is a 3D rendering context that can be used to display 3D graphics in a browser.

Here is an example of a basic vertex and fragment shader written in GLSL, along with some JavaScript code that creates a WebGL context and uses the shaders to render a simple triangle:

// GLSL 
// Vertex Shader
attribute vec4 a_position;
uniform mat4 u_matrix;
void main() {
  gl_Position = u_matrix * a_position;
}

// Fragment Shader
precision mediump float;
uniform vec4 u_color;
void main() {
  gl_FragColor = u_color;
}
// JavaScript code
var canvas = document.getElementById("canvas");
var gl = canvas.getContext("webgl");

var vertexShaderSource = document.getElementById("vertex-shader").text;
var fragmentShaderSource = document.getElementById("fragment-shader").text;

var vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexShaderSource);
gl.compileShader(vertexShader);

var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentShaderSource);
gl.compileShader(fragmentShader);

var program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
gl.useProgram(program);

var positionAttributeLocation = gl.getAttribLocation(program, "a_position");
var colorUniformLocation = gl.getUniformLocation(program, "u_color");
var matrixUniformLocation = gl.getUniformLocation(program, "u_matrix");

var positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
  0, 0,
  0, 0.5,
  0.7, 0,
]), gl.STATIC_DRAW);

gl.enableVertexAttribArray(positionAttributeLocation);
gl.vertexAttribPointer(positionAttributeLocation, 2, gl.FLOAT, false, 0, 0);

gl.uniform4f(colorUniformLocation, Math.random(), Math.random(), Math.random(), 1);

var matrix = new Float32Array(16);
mat4.ortho(matrix, -1, 1, -1, 1, 0, 1);
gl.uniformMatrix4fv(matrixUniformLocation, false, matrix);

gl.drawArrays(gl.TRIANGLES, 0, 3);

I asked “Make the example code use ES6 style let and const and classes”. Here’s the response.

Sure, here’s an example of the same basic vertex and fragment shaders, but written using ES6 const and let instead of var, and using classes to organize the code:

// Vertex Shader
const vertexShaderSource = `
attribute vec4 a_position;
uniform mat4 u_matrix;
void main() {
  gl_Position = u_matrix * a_position;
}
`;

// Fragment Shader
const fragmentShaderSource = `
precision mediump float;
uniform vec4 u_color;
void main() {
  gl_FragColor = u_color;
}
`;
class WebGLRenderer {
  constructor(canvasId) {
    this.canvas = document.getElementById(canvasId);
    this.gl = this.canvas.getContext("webgl");

    this.vertexShader = this.createShader(this.gl.VERTEX_SHADER, vertexShaderSource);
    this.fragmentShader = this.createShader(this.gl.FRAGMENT_SHADER, fragmentShaderSource);

    this.program = this.createProgram(this.vertexShader, this.fragmentShader);

    this.positionAttributeLocation = this.gl.getAttribLocation(this.program, "a_position");
    this.colorUniformLocation = this.gl.getUniformLocation(this.program, "u_color");
    this.matrixUniformLocation = this.gl.getUniformLocation(this.program, "u_matrix");

    this.positionBuffer = this.gl.createBuffer();
    this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.positionBuffer);
    this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array([
      0, 0,
      0, 0.5,
      0.7, 0,
    ]), this.gl.STATIC_DRAW);
  }

  createShader(type, source) {
    let shader = this.gl.createShader(type);
    this.gl.shaderSource(shader, source);
    this.gl.compileShader(shader);
    return shader;
  }

  createProgram(vertexShader, fragmentShader) {
    let program = this.gl.createProgram();
    this.gl.attachShader(program, vertexShader);
    this.gl.attachShader(program, fragmentShader);
    this.gl.linkProgram(program);
    return program;
  }

  render() {
    this.gl.useProgram(this.program);

    this.gl.enableVertexAttribArray(this.positionAttributeLocation);
    this.gl.vertexAttribPointer(this.positionAttributeLocation, 2, this.gl.FLOAT, false, 0, 0);

    this.gl.uniform4f(this.colorUniformLocation, Math.random(), Math.random(), Math.random(), 1);

    let matrix = new Float32Array(16);
    mat4.ortho(matrix, -1, 1, -1, 1, 0, 1);
    this.gl.uniformMatrix4fv(this.matrixUniformLocation, false, matrix);

    this.gl.drawArrays(this.gl.TRIANGLES, 0, 3);
  }
}

const renderer = new WebGLRenderer("canvas");
renderer.render();

The WebGLRenderer class is used to create and render the GLSL shaders using WebGL.

You can create an instance of the class with an id of a canvas element, and call the render() method to render the shaders.

The render() method sets the active program to the one created by the constructor, enables the vertex attribute for the position attribute location, sets the color uniform value to a random value, sets the matrix uniform value to an orthographic matrix, and then draws the triangles using the position buffer.

  1. this.gl.useProgram(this.program); sets the active program to the one created in the constructor.
  2. this.gl.enableVertexAttribArray(this.positionAttributeLocation); enables the vertex attribute for the position attribute location.
  3. this.gl.vertexAttribPointer(this.positionAttributeLocation, 2, this.gl.FLOAT, false, 0, 0); sets the vertex attribute pointer for the position attribute location to the position buffer.
  4. this.gl.uniform4f(this.colorUniformLocation, Math.random(), Math.random(), Math.random(), 1); sets the color uniform value to a random value.
  5. let matrix = new Float32Array(16); mat4.ortho(matrix, -1, 1, -1, 1, 0, 1); this.gl.uniformMatrix4fv(this.matrixUniformLocation, false, matrix); sets the matrix uniform value to an orthographic matrix.
  6. this.gl.drawArrays(this.gl.TRIANGLES, 0, 3); draws the triangles using the position buffer.

This will render the triangle with a random color on the canvas with id canvasId.

I am very impressed. Want to know more about GLSL check out my courses page