Skip to content

Instantly share code, notes, and snippets.

@jeantimex
Created July 19, 2024 06:43
Show Gist options
  • Save jeantimex/68b48775713411814a40db38262f3a38 to your computer and use it in GitHub Desktop.
Save jeantimex/68b48775713411814a40db38262f3a38 to your computer and use it in GitHub Desktop.
WebGL 2 - A triangle rotates above a plane in 3D scene
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebGL2 Rotating Triangle and Static Plane</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gl-matrix/2.8.1/gl-matrix-min.js"></script>
</head>
<body>
<canvas id="glCanvas" width="800" height="600"></canvas>
<script>
const vsSource = `#version 300 es
in vec4 aPosition;
in vec4 aColor;
out vec4 vColor;
uniform mat4 uModelViewMatrix;
uniform mat4 uProjectionMatrix;
void main() {
gl_Position = uProjectionMatrix * uModelViewMatrix * aPosition;
vColor = aColor;
}`;
const fsSource = `#version 300 es
precision mediump float;
in vec4 vColor;
out vec4 fragColor;
void main() {
fragColor = vColor;
}`;
let gl;
let programInfo;
let buffers;
function initGL() {
const canvas = document.getElementById('glCanvas');
gl = canvas.getContext('webgl2');
if (!gl) {
alert('Unable to initialize WebGL2. Your browser may not support it.');
return;
}
const shaderProgram = initShaderProgram(gl, vsSource, fsSource);
programInfo = {
program: shaderProgram,
attribLocations: {
vertexPosition: gl.getAttribLocation(shaderProgram, 'aPosition'),
vertexColor: gl.getAttribLocation(shaderProgram, 'aColor'),
},
uniformLocations: {
projectionMatrix: gl.getUniformLocation(shaderProgram, 'uProjectionMatrix'),
modelViewMatrix: gl.getUniformLocation(shaderProgram, 'uModelViewMatrix'),
},
};
buffers = initBuffers(gl);
gl.enable(gl.DEPTH_TEST);
gl.depthFunc(gl.LEQUAL);
render();
}
function initBuffers(gl) {
const positions = [
// Triangle vertices
0.0, 1.0, 0.0,
-1.0, -1.0, 0.0,
1.0, -1.0, 0.0,
// Plane vertices
-2.0, -1.5, -2.0,
2.0, -1.5, -2.0,
2.0, -1.5, 2.0,
-2.0, -1.5, 2.0,
];
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
const colors = [
// Triangle colors
1.0, 0.0, 0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
0.0, 0.0, 1.0, 1.0,
// Plane colors
0.5, 0.5, 0.5, 1.0,
0.5, 0.5, 0.5, 1.0,
0.5, 0.5, 0.5, 1.0,
0.5, 0.5, 0.5, 1.0,
];
const colorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
const indices = [
// Triangle
0, 1, 2,
// Plane
3, 4, 5,
5, 6, 3
];
const indexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
return {
position: positionBuffer,
color: colorBuffer,
indices: indexBuffer,
};
}
function render() {
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
const fieldOfView = 45 * Math.PI / 180;
const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
const zNear = 0.1;
const zFar = 100.0;
const projectionMatrix = mat4.create();
mat4.perspective(projectionMatrix, fieldOfView, aspect, zNear, zFar);
const viewMatrix = mat4.create();
const eye = [0, 2, 5];
const center = [0, 0, 0];
const up = [0, 1, 0];
mat4.lookAt(viewMatrix, eye, center, up);
// Triangle model matrix
const triangleModelMatrix = mat4.create();
mat4.translate(triangleModelMatrix, triangleModelMatrix, [0.0, 0.5, -2.0]);
mat4.rotate(triangleModelMatrix, triangleModelMatrix, performance.now() * 0.001, [0, 1, 0]);
// Plane model matrix
const planeModelMatrix = mat4.create();
mat4.translate(planeModelMatrix, planeModelMatrix, [0.0, 0.0, -2.0]);
gl.bindBuffer(gl.ARRAY_BUFFER, buffers.position);
gl.vertexAttribPointer(programInfo.attribLocations.vertexPosition, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(programInfo.attribLocations.vertexPosition);
gl.bindBuffer(gl.ARRAY_BUFFER, buffers.color);
gl.vertexAttribPointer(programInfo.attribLocations.vertexColor, 4, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(programInfo.attribLocations.vertexColor);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffers.indices);
gl.useProgram(programInfo.program);
gl.uniformMatrix4fv(programInfo.uniformLocations.projectionMatrix, false, projectionMatrix);
// Draw triangle
let modelViewMatrix = mat4.create();
mat4.multiply(modelViewMatrix, viewMatrix, triangleModelMatrix);
gl.uniformMatrix4fv(programInfo.uniformLocations.modelViewMatrix, false, modelViewMatrix);
gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_SHORT, 0);
// Draw plane
modelViewMatrix = mat4.create();
mat4.multiply(modelViewMatrix, viewMatrix, planeModelMatrix);
gl.uniformMatrix4fv(programInfo.uniformLocations.modelViewMatrix, false, modelViewMatrix);
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 6);
requestAnimationFrame(render);
}
function initShaderProgram(gl, vsSource, fsSource) {
const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);
const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);
const shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
alert('Unable to initialize the shader program: ' + gl.getProgramInfoLog(shaderProgram));
return null;
}
return shaderProgram;
}
function loadShader(gl, type, source) {
const shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
return null;
}
return shader;
}
window.onload = initGL;
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment