Created
July 19, 2024 06:43
-
-
Save jeantimex/68b48775713411814a40db38262f3a38 to your computer and use it in GitHub Desktop.
WebGL 2 - A triangle rotates above a plane in 3D scene
This file contains 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
<!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