Created
April 19, 2025 06:38
-
-
Save greggman/ea1a1d5ea5d619c2e818230016481656 to your computer and use it in GitHub Desktop.
WebGL2 - 2D Geometry Matrix Transform with Projection
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@import url("https://webgl2fundamentals.org/webgl/resources/webgl-tutorials.css"); | |
body { | |
margin: 0; | |
} | |
canvas { | |
width: 100vw; | |
height: 100vh; | |
display: block; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<canvas id="canvas"></canvas> | |
<div id="uiContainer"> | |
<div id="ui"> | |
<div id="x"></div> | |
<div id="y"></div> | |
<div id="angle"></div> | |
<div id="scaleX"></div> | |
<div id="scaleY"></div> | |
</div> | |
</div> | |
<!-- | |
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/webgl-lessons-ui.js"></script> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// WebGL2 - 2D Geometry Matrix Transform with Projection | |
// from https://webgl2fundamentals.org/webgl/webgl-2d-geometry-matrix-transform-simpler-functions.html | |
"use strict"; | |
var vertexShaderSource = `#version 300 es | |
// an attribute is an input (in) to a vertex shader. | |
// It will receive data from a buffer | |
in vec2 a_position; | |
// A matrix to transform the positions by | |
uniform mat3 u_matrix; | |
// all shaders have a main function | |
void main() { | |
// Multiply the position by the matrix. | |
gl_Position = vec4((u_matrix * vec3(a_position, 1)).xy, 0, 1); | |
} | |
`; | |
var fragmentShaderSource = `#version 300 es | |
precision highp float; | |
uniform vec4 u_color; | |
// we need to declare an output for the fragment shader | |
out vec4 outColor; | |
void main() { | |
outColor = u_color; | |
} | |
`; | |
function main() { | |
// Get A WebGL context | |
/** @type {HTMLCanvasElement} */ | |
var canvas = document.querySelector("#canvas"); | |
var gl = canvas.getContext("webgl2"); | |
if (!gl) { | |
return; | |
} | |
// Use our boilerplate utils to compile the shaders and link into a program | |
var program = webglUtils.createProgramFromSources(gl, | |
[vertexShaderSource, fragmentShaderSource]); | |
// look up where the vertex data needs to go. | |
var positionAttributeLocation = gl.getAttribLocation(program, "a_position"); | |
// look up uniform locations | |
var colorLocation = gl.getUniformLocation(program, "u_color"); | |
var matrixLocation = gl.getUniformLocation(program, "u_matrix"); | |
// Create a buffer | |
var positionBuffer = gl.createBuffer(); | |
// 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); | |
// Bind it to ARRAY_BUFFER (think of it as ARRAY_BUFFER = positionBuffer) | |
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); | |
// Set Geometry. | |
setGeometry(gl); | |
// 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); | |
var color = [Math.random(), Math.random(), Math.random(), 1]; | |
drawScene(); | |
// Draw the scene. | |
function drawScene() { | |
webglUtils.resizeCanvasToDisplaySize(gl.canvas); | |
// Tell WebGL how to convert from clip space to pixels | |
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); | |
// Set the color. | |
gl.uniform4fv(colorLocation, color); | |
// Compute the matrix | |
var mat = m3.projection(gl.canvas.clientWidth, gl.canvas.clientHeight); // convert to clipspace | |
mat = m3.translate(mat, 25, 25); // move box back | |
mat = m3.rotate(mat, 45 * Math.PI / 180); // rotate box | |
mat = m3.translate(mat, -25, -25); // center box over origin | |
// Set the matrix. | |
gl.uniformMatrix3fv(matrixLocation, false, mat); | |
// Draw the geometry. | |
var primitiveType = gl.TRIANGLES; | |
var offset = 0; | |
var count = 6; | |
gl.drawArrays(primitiveType, offset, count); | |
} | |
} | |
// Fill the current ARRAY_BUFFER buffer | |
// with the values that define a square | |
function setGeometry(gl) { | |
gl.bufferData( | |
gl.ARRAY_BUFFER, | |
new Float32Array([ | |
// left column | |
0, 0, | |
50, 0, | |
0, 50, | |
0, 50, | |
50, 0, | |
50, 50, | |
]), | |
gl.STATIC_DRAW); | |
} | |
var m3 = { | |
projection: function projection(width, height) { | |
// Note: This matrix flips the Y axis so that 0 is at the top. | |
return [ | |
2 / width, 0, 0, | |
0, -2 / height, 0, | |
-1, 1, 1, | |
]; | |
}, | |
translation: function translation(tx, ty) { | |
return [ | |
1, 0, 0, | |
0, 1, 0, | |
tx, ty, 1, | |
]; | |
}, | |
rotation: function rotation(angleInRadians) { | |
var c = Math.cos(angleInRadians); | |
var s = Math.sin(angleInRadians); | |
return [ | |
c, -s, 0, | |
s, c, 0, | |
0, 0, 1, | |
]; | |
}, | |
scaling: function scaling(sx, sy) { | |
return [ | |
sx, 0, 0, | |
0, sy, 0, | |
0, 0, 1, | |
]; | |
}, | |
multiply: function multiply(a, b) { | |
var a00 = a[0 * 3 + 0]; | |
var a01 = a[0 * 3 + 1]; | |
var a02 = a[0 * 3 + 2]; | |
var a10 = a[1 * 3 + 0]; | |
var a11 = a[1 * 3 + 1]; | |
var a12 = a[1 * 3 + 2]; | |
var a20 = a[2 * 3 + 0]; | |
var a21 = a[2 * 3 + 1]; | |
var a22 = a[2 * 3 + 2]; | |
var b00 = b[0 * 3 + 0]; | |
var b01 = b[0 * 3 + 1]; | |
var b02 = b[0 * 3 + 2]; | |
var b10 = b[1 * 3 + 0]; | |
var b11 = b[1 * 3 + 1]; | |
var b12 = b[1 * 3 + 2]; | |
var b20 = b[2 * 3 + 0]; | |
var b21 = b[2 * 3 + 1]; | |
var b22 = b[2 * 3 + 2]; | |
return [ | |
b00 * a00 + b01 * a10 + b02 * a20, | |
b00 * a01 + b01 * a11 + b02 * a21, | |
b00 * a02 + b01 * a12 + b02 * a22, | |
b10 * a00 + b11 * a10 + b12 * a20, | |
b10 * a01 + b11 * a11 + b12 * a21, | |
b10 * a02 + b11 * a12 + b12 * a22, | |
b20 * a00 + b21 * a10 + b22 * a20, | |
b20 * a01 + b21 * a11 + b22 * a21, | |
b20 * a02 + b21 * a12 + b22 * a22, | |
]; | |
}, | |
translate: function(m, tx, ty) { | |
return m3.multiply(m, m3.translation(tx, ty)); | |
}, | |
rotate: function(m, angleInRadians) { | |
return m3.multiply(m, m3.rotation(angleInRadians)); | |
}, | |
scale: function(m, sx, sy) { | |
return m3.multiply(m, m3.scaling(sx, sy)); | |
}, | |
}; | |
main(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{"name":"WebGL2 - 2D Geometry Matrix Transform with Projection","settings":{},"filenames":["index.html","index.css","index.js"]} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment