Skip to content

Instantly share code, notes, and snippets.

@modster
Created May 30, 2022 04:26
Show Gist options
  • Save modster/d4b8ab63f6a68403e49efc6a4824b8a5 to your computer and use it in GitHub Desktop.
Save modster/d4b8ab63f6a68403e49efc6a4824b8a5 to your computer and use it in GitHub Desktop.
GLSL/JavaScript Template Literal Shader Program
"use strict";
var vs = `#version 300 es
in vec2 a_position;
uniform mat3 u_matrix;
void main() {
// Multiply the position by the matrix.
gl_Position = vec4((u_matrix * vec3(a_position, 1)).xy, 0, 1);
}
`;
<canvas id="canvas"></canvas>
<!--
for most samples webgl-utils only provides shader compiling/linking and
canvas resizing because why clutter the examples with code that's the same in every sample.
See https://webgl2fundamentals.org/webgl/lessons/webgl-boilerplate.html
and https://webgl2fundamentals.org/webgl/lessons/webgl-resizing-the-canvas.html
for webgl-utils, m3, m4, and webgl-lessons-ui.
-->
<script src="https://webgl2fundamentals.org/webgl/resources/webgl-utils.js"></script>
<script src="https://webgl2fundamentals.org/webgl/resources/m3.js"></script>
function main() {
// Get A WebGL context
/** @type {HTMLCanvasElement} */
var canvas = document.querySelector("#canvas");
var gl = canvas.getContext("webgl2");
if (!gl) {
return;
}
// setup GLSL program
var program = webglUtils.createProgramFromSources(gl, [vs, fs]);
// look up where the vertex data needs to go.
var positionAttributeLocation = gl.getAttribLocation(program, "a_position");
// lookup uniforms
var colorLocation = gl.getUniformLocation(program, "u_color");
var matrixLocation = gl.getUniformLocation(program, "u_matrix");
// Create a buffer and put a 2 points in it for 1 line
var positionBuffer = gl.createBuffer();
// Bind it to ARRAY_BUFFER (think of it as ARRAY_BUFFER = positionBuffer)
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
var positions = [
-2, -2,
2, 2,
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
// Create a vertex array object (attribute state)
var vao = gl.createVertexArray();
// and make it the one we're currently working with
gl.bindVertexArray(vao);
// Turn on the attribute
gl.enableVertexAttribArray(positionAttributeLocation);
// Tell the attribute how to get data out of positionBuffer (ARRAY_BUFFER)
var size = 2; // 2 components per iteration
var type = gl.FLOAT; // the data is 32bit floats
var normalize = false; // don't normalize the data
var stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position
var offset = 0; // start at the beginning of the buffer
gl.vertexAttribPointer(
positionAttributeLocation, size, type, normalize, stride, offset);
requestAnimationFrame(drawScene);
// Draw the scene.
function drawScene(now) {
resizeCanvasToDisplaySize(gl.canvas);
now *= 0.001; // convert to seconds
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
// Clear the canvas
gl.clearColor(0, 0, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
// Tell it to use our program (pair of shaders)
gl.useProgram(program);
// Bind the attribute/buffer set we want.
gl.bindVertexArray(vao);
// Compute the matrices
var matrix = m3.rotation(now);
// Set the matrix.
gl.uniformMatrix3fv(matrixLocation, false, matrix);
// Draw in Red
gl.uniform4fv(colorLocation, [1, 0, 0, 1]);
// Draw the line
var primitiveType = gl.LINES;
var offset = 0;
var count = 2;
gl.drawArrays(primitiveType, offset, count);
requestAnimationFrame(drawScene);
}
const canvasToDisplaySizeMap = new Map([[canvas, [300, 150]]]);
function onResize(entries) {
for (const entry of entries) {
let width;
let height;
let dpr = window.devicePixelRatio;
if (entry.devicePixelContentBoxSize) {
// NOTE: Only this path gives the correct answer
// The other 2 paths are an imperfect fallback
// for browsers that don't provide anyway to do this
width = entry.devicePixelContentBoxSize[0].inlineSize;
height = entry.devicePixelContentBoxSize[0].blockSize;
dpr = 1; // it's already in width and height
} else if (entry.contentBoxSize) {
if (entry.contentBoxSize[0]) {
width = entry.contentBoxSize[0].inlineSize;
height = entry.contentBoxSize[0].blockSize;
} else {
// legacy
width = entry.contentBoxSize.inlineSize;
height = entry.contentBoxSize.blockSize;
}
} else {
// legacy
width = entry.contentRect.width;
height = entry.contentRect.height;
}
const displayWidth = Math.round(width * dpr);
const displayHeight = Math.round(height * dpr);
canvasToDisplaySizeMap.set(entry.target, [displayWidth, displayHeight]);
}
}
const resizeObserver = new ResizeObserver(onResize);
resizeObserver.observe(canvas, {box: 'content-box'});
function resizeCanvasToDisplaySize(canvas) {
// Get the size the browser is displaying the canvas in device pixels.
const [displayWidth, displayHeight] = canvasToDisplaySizeMap.get(canvas);
// Check if the canvas is not the same size.
const needResize = canvas.width !== displayWidth ||
canvas.height !== displayHeight;
if (needResize) {
// Make the canvas the same size
canvas.width = displayWidth;
canvas.height = displayHeight;
}
return needResize;
}
}
main();
body {
margin: 0;
background-color: white;
}
canvas {
display: block; /* prevents scrollbar */
width: 100vw;
height: 100vh;
}
"use strict";
var vs = `#version 300 es
in vec2 a_position;
uniform mat3 u_matrix;
void main() {
// Multiply the position by the matrix.
gl_Position = vec4((u_matrix * vec3(a_position, 1)).xy, 0, 1);
}
`;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment