Skip to content

Instantly share code, notes, and snippets.

@jakubfiala
Last active May 22, 2020 18:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jakubfiala/0a7ec69cf3ce0898ee373422d5ee058e to your computer and use it in GitHub Desktop.
Save jakubfiala/0a7ec69cf3ce0898ee373422d5ee058e to your computer and use it in GitHub Desktop.
Does exactly what glslsandbox.com does. Nothing more, nothing less :) You call createRenderer, give it a fragment shader as a string, and it gives you a canvas and a draw function, to which you pass the time, mouse X and Y coordinates, and the width/height (resolution) of the canvas.
export const loadShader = (context, type, source) => {
const shader = context.createShader(type);
// Send the source to the shader object
context.shaderSource(shader, source);
// Compile the shader program
context.compileShader(shader);
// See if it compiled successfully
if (!context.getShaderParameter(shader, context.COMPILE_STATUS)) {
console.error('An error occurred compiling the shaders: ' + context.getShaderInfoLog(shader));
context.deleteShader(shader);
return null;
}
return shader;
}
export const vertexShaderSource = `
attribute vec4 aVertexPosition;
void main() { gl_Position = aVertexPosition; }
`;
export const getRenderFunction = (context, uniformLocations) => (time, mouseX, mouseY, resolutionX, resolutionY) => {
// Clear the canvas before we start drawing on it.
context.clearColor(1.0, 1.0, 1.0, 1.0); // Clear to black, fully opaque
context.clearDepth(1.0); // Clear everything
context.clear(context.COLOR_BUFFER_BIT | context.DEPTH_BUFFER_BIT);
context.uniform2fv(uniformLocations.resolution, [resolutionX, resolutionY]);
context.uniform2fv(uniformLocations.mouse, [mouseX, mouseY]);
context.uniform1f(uniformLocations.time, time / 2000);
context.viewport(0, 0, resolutionX, resolutionY);
context.drawArrays(context.TRIANGLE_STRIP, 0, 4);
};
export const createRenderer = (fragmentShaderSource) => {
const canvas = document.createElement('canvas');
const context = canvas.getContext('webgl');
const vertexShader = loadShader(context, context.VERTEX_SHADER, vertexShaderSource);
const fragmentShader = loadShader(context, context.FRAGMENT_SHADER, fragmentShaderSource);
const shaderProgram = context.createProgram();
context.attachShader(shaderProgram, vertexShader);
context.attachShader(shaderProgram, fragmentShader);
context.linkProgram(shaderProgram);
// If creating the shader program failed, alert
if (!context.getProgramParameter(shaderProgram, context.LINK_STATUS)) {
console.error('Unable to initialize the shader program: ' + context.getProgramInfoLog(shaderProgram));
}
// Create a buffer for the square's positions.
const positionBuffer = context.createBuffer();
context.bindBuffer(context.ARRAY_BUFFER, positionBuffer);
const positions = Float32Array.from([
-1.0, 1.0,
1.0, 1.0,
-1.0, -1.0,
1.0, -1.0,
]);
context.bufferData(context.ARRAY_BUFFER, positions, context.STATIC_DRAW);
context.bindBuffer(context.ARRAY_BUFFER, positionBuffer);
// get pointers to uniforms
const resolution = context.getUniformLocation(shaderProgram, 'resolution');
const mouse = context.getUniformLocation(shaderProgram, 'mouse');
const time = context.getUniformLocation(shaderProgram, 'time');
// Tell WebGL how to pull out the positions from the position
// buffer into the vertexPosition attribute.
const vertexPositionLocation = context.getAttribLocation(shaderProgram, 'aVertexPosition');
context.vertexAttribPointer(vertexPositionLocation, 2, context.FLOAT, false, 0, 0);
context.enableVertexAttribArray(vertexPositionLocation);
// Tell WebGL to use our program when drawing
context.useProgram(shaderProgram);
const draw = getRenderFunction(context, { resolution, mouse, time });
return { canvas, draw };
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment