Draw an image of a triangle using WebGL in a single HTML file. Make the canvas take the full page.
Draw an image of a triangle using WebGL in a single HTML file. Make the canvas take the full page.
Okay, here is a single HTML file that uses WebGL to draw a simple colored triangle. The canvas is styled with CSS to take up the full browser window.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 | <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>WebGL Full Page Triangle</title> <style> /* Remove default margin/padding and make body/html fill the viewport */ html, body { margin: 0; padding: 0; width: 100%; height: 100%; overflow: hidden; /* Prevent scrollbars */ } /* Make canvas fill its container (the body) */ #webgl-canvas { display: block; /* Remove potential extra space below canvas */ width: 100%; height: 100%; } </style> </head> <body> <canvas id="webgl-canvas"></canvas> <script> // --- Vertex Shader --- // Defines how vertex positions are processed. const vsSource = ` attribute vec2 a_position; // Input: 2D vertex position void main() { // Output: Clip space position (x, y, z, w) // z = 0.0 (2D), w = 1.0 (standard for positions) gl_Position = vec4(a_position, 0.0, 1.0); } `; // --- Fragment Shader --- // Defines the color of each pixel (fragment). const fsSource = ` // Set default precision for floating point numbers precision mediump float; void main() { // Output: Color (R, G, B, Alpha) - Solid Red gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); } `; // --- Main WebGL Function --- function main() { const canvas = document.getElementById('webgl-canvas'); if (!canvas) { console.error("Canvas element not found!"); return; } // Try to get the WebGL rendering context const gl = canvas.getContext('webgl'); if (!gl) { console.error("Unable to initialize WebGL. Your browser or machine may not support it."); alert("Unable to initialize WebGL. Your browser or machine may not support it."); return; } // --- Shader Compilation and Linking --- // Helper function to compile a shader function createShader(gl, type, source) { const shader = gl.createShader(type); gl.shaderSource(shader, source); gl.compileShader(shader); const success = gl.getShaderParameter(shader, gl.COMPILE_STATUS); if (success) { return shader; } // Log error if compilation failed console.error("Shader compilation failed:", gl.getShaderInfoLog(shader)); gl.deleteShader(shader); return null; } // Helper function to link shaders into a program function createProgram(gl, vertexShader, fragmentShader) { const program = gl.createProgram(); gl.attachShader(program, vertexShader); gl.attachShader(program, fragmentShader); gl.linkProgram(program); const success = gl.getProgramParameter(program, gl.LINK_STATUS); if (success) { return program; } // Log error if linking failed console.error("Program linking failed:", gl.getProgramInfoLog(program)); gl.deleteProgram(program); return null; } // Compile shaders const vertexShader = createShader(gl, gl.VERTEX_SHADER, vsSource); const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fsSource); if (!vertexShader || !fragmentShader) return; // Stop if shaders failed // Link shaders into a program const program = createProgram(gl, vertexShader, fragmentShader); if (!program) return; // Stop if program linking failed // --- Vertex Data and Buffers --- // Get the location of the 'a_position' attribute in the shader program const positionAttributeLocation = gl.getAttribLocation(program, 'a_position'); if (positionAttributeLocation < 0) { console.error("Failed to get the storage location of a_position"); return; } // Create a buffer to store vertex positions on the GPU const positionBuffer = gl.createBuffer(); // Bind the buffer to the ARRAY_BUFFER target (think of it as the 'current' buffer) gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); // Define the triangle's vertices in Clip Space coordinates (-1 to +1) // (x, y) pairs for each vertex const positions = [ -0.5, -0.5, // Bottom-left vertex 0.5, -0.5, // Bottom-right vertex 0.0, 0.5 // Top-center vertex ]; // Pass the vertex data to the buffer (using Float32Array for efficiency) // STATIC_DRAW hints that the data won't change often gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW); // --- Rendering --- // Function to resize the drawing buffer to match the display size function resizeCanvasToDisplaySize(canvas) { // Lookup the size the browser is displaying the canvas in CSS pixels. const displayWidth = canvas.clientWidth; const displayHeight = canvas.clientHeight; // 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; } // Resize canvas and set viewport before drawing resizeCanvasToDisplaySize(gl.canvas); gl.viewport(0, 0, gl.canvas.width, gl.canvas.height); // Tell WebGL how to convert clip space to pixels // Clear the canvas (set background color) gl.clearColor(0.1, 0.1, 0.15, 1.0); // Dark grey background gl.clear(gl.COLOR_BUFFER_BIT); // Tell WebGL to use our shader program gl.useProgram(program); // Enable the 'a_position' attribute gl.enableVertexAttribArray(positionAttributeLocation); // Bind the position buffer again (might not be strictly necessary here, but good practice) gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); // Tell the attribute how to get data out of positionBuffer (ARRAY_BUFFER) const size = 2; // 2 components per iteration (x, y) const type = gl.FLOAT; // the data is 32bit floats const normalize = false; // don't normalize the data const stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position const offset = 0; // start at the beginning of the buffer gl.vertexAttribPointer( positionAttributeLocation, size, type, normalize, stride, offset); // Draw the triangle const primitiveType = gl.TRIANGLES; // Draw triangles const drawOffset = 0; // Start from the first vertex const count = 3; // Number of vertices to process (3 for one triangle) gl.drawArrays(primitiveType, drawOffset, count); console.log("Triangle drawn!"); } // Run the main function when the page is loaded window.onload = main; </script> </body> </html> |
I extracted the following code from that output:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 | <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>WebGL Full Page Triangle</title> <style> /* Remove default margin/padding and make body/html fill the viewport */ html, body { margin: 0; padding: 0; width: 100%; height: 100%; overflow: hidden; /* Prevent scrollbars */ } /* Make canvas fill its container (the body) */ #webgl-canvas { display: block; /* Remove potential extra space below canvas */ width: 100%; height: 100%; } </style> </head> <body> <canvas id="webgl-canvas"></canvas> <script> // --- Vertex Shader --- // Defines how vertex positions are processed. const vsSource = ` attribute vec2 a_position; // Input: 2D vertex position void main() { // Output: Clip space position (x, y, z, w) // z = 0.0 (2D), w = 1.0 (standard for positions) gl_Position = vec4(a_position, 0.0, 1.0); } `; // --- Fragment Shader --- // Defines the color of each pixel (fragment). const fsSource = ` // Set default precision for floating point numbers precision mediump float; void main() { // Output: Color (R, G, B, Alpha) - Solid Red gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); } `; // --- Main WebGL Function --- function main() { const canvas = document.getElementById('webgl-canvas'); if (!canvas) { console.error("Canvas element not found!"); return; } // Try to get the WebGL rendering context const gl = canvas.getContext('webgl'); if (!gl) { console.error("Unable to initialize WebGL. Your browser or machine may not support it."); alert("Unable to initialize WebGL. Your browser or machine may not support it."); return; } // --- Shader Compilation and Linking --- // Helper function to compile a shader function createShader(gl, type, source) { const shader = gl.createShader(type); gl.shaderSource(shader, source); gl.compileShader(shader); const success = gl.getShaderParameter(shader, gl.COMPILE_STATUS); if (success) { return shader; } // Log error if compilation failed console.error("Shader compilation failed:", gl.getShaderInfoLog(shader)); gl.deleteShader(shader); return null; } // Helper function to link shaders into a program function createProgram(gl, vertexShader, fragmentShader) { const program = gl.createProgram(); gl.attachShader(program, vertexShader); gl.attachShader(program, fragmentShader); gl.linkProgram(program); const success = gl.getProgramParameter(program, gl.LINK_STATUS); if (success) { return program; } // Log error if linking failed console.error("Program linking failed:", gl.getProgramInfoLog(program)); gl.deleteProgram(program); return null; } // Compile shaders const vertexShader = createShader(gl, gl.VERTEX_SHADER, vsSource); const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fsSource); if (!vertexShader || !fragmentShader) return; // Stop if shaders failed // Link shaders into a program const program = createProgram(gl, vertexShader, fragmentShader); if (!program) return; // Stop if program linking failed // --- Vertex Data and Buffers --- // Get the location of the 'a_position' attribute in the shader program const positionAttributeLocation = gl.getAttribLocation(program, 'a_position'); if (positionAttributeLocation < 0) { console.error("Failed to get the storage location of a_position"); return; } // Create a buffer to store vertex positions on the GPU const positionBuffer = gl.createBuffer(); // Bind the buffer to the ARRAY_BUFFER target (think of it as the 'current' buffer) gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); // Define the triangle's vertices in Clip Space coordinates (-1 to +1) // (x, y) pairs for each vertex const positions = [ -0.5, -0.5, // Bottom-left vertex 0.5, -0.5, // Bottom-right vertex 0.0, 0.5 // Top-center vertex ]; // Pass the vertex data to the buffer (using Float32Array for efficiency) // STATIC_DRAW hints that the data won't change often gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW); // --- Rendering --- // Function to resize the drawing buffer to match the display size function resizeCanvasToDisplaySize(canvas) { // Lookup the size the browser is displaying the canvas in CSS pixels. const displayWidth = canvas.clientWidth; const displayHeight = canvas.clientHeight; // 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; } // Resize canvas and set viewport before drawing resizeCanvasToDisplaySize(gl.canvas); gl.viewport(0, 0, gl.canvas.width, gl.canvas.height); // Tell WebGL how to convert clip space to pixels // Clear the canvas (set background color) gl.clearColor(0.1, 0.1, 0.15, 1.0); // Dark grey background gl.clear(gl.COLOR_BUFFER_BIT); // Tell WebGL to use our shader program gl.useProgram(program); // Enable the 'a_position' attribute gl.enableVertexAttribArray(positionAttributeLocation); // Bind the position buffer again (might not be strictly necessary here, but good practice) gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); // Tell the attribute how to get data out of positionBuffer (ARRAY_BUFFER) const size = 2; // 2 components per iteration (x, y) const type = gl.FLOAT; // the data is 32bit floats const normalize = false; // don't normalize the data const stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position const offset = 0; // start at the beginning of the buffer gl.vertexAttribPointer( positionAttributeLocation, size, type, normalize, stride, offset); // Draw the triangle const primitiveType = gl.TRIANGLES; // Draw triangles const drawOffset = 0; // Start from the first vertex const count = 3; // Number of vertices to process (3 for one triangle) gl.drawArrays(primitiveType, drawOffset, count); console.log("Triangle drawn!"); } // Run the main function when the page is loaded window.onload = main; </script> </body> </html> |
Rendering the webpage gives the following image:
This is a screenshot of a webpage that draws something with webgl. I'm trying to see if it drew what I wanted. Describe what is drawn in this image?
The image shows a red triangle centered on a dark gray background.
Does this answer say that there is a picture of a triangle "The image shows a red triangle centered on a dark gray background."? Answer "Yes it does" or "No it does not".
Yes it does.
Testing if the previous output contains the string es it does
: True
Testing if the previous output contains the string THREE.
: False