<!DOCTYPE html> <html lang="en-us"> <head> <meta charset="utf-8"> <meta name="robots" content="noindex"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover"> <title>Generated Texture</title> <style> html, body, canvas { margin: 0; padding: 0; width: 100%; height: 100%; overflow: hidden; } </style> </head> <body> <canvas id="canvas"></canvas> <!-- © Adam Murray 2024 https://adammurray.link/ Creative Commons License Attribution-NonCommercial-ShareAlike 4.0 International https://creativecommons.org/licenses/by-nc-sa/4.0/ --> <script id="vertexShader" type="x-shader/x-vertex"> #version 300 es in vec4 vertexPosition; void main() { // no-op vertex shader gl_Position = vertexPosition; } </script> <script id="fragmentShader" type="x-shader/x-fragment"> #version 300 es precision highp float; uniform sampler2D tex; uniform vec2 canvasSize; out vec4 fragColor; void main() { vec2 coord = gl_FragCoord.xy/canvasSize; // stretch texture to canvas (don't maintain aspect ratio) fragColor = texture(tex, coord); } </script> <script> const canvas = document.querySelector('canvas'); const vertexShader = document.querySelector('script[type="x-shader/x-vertex"]'); const fragmentShader = document.querySelector('script[type="x-shader/x-fragment"]'); const gl = canvas.getContext("webgl2", { preserveDrawingBuffer: true }); if (!gl) { main.innerHTML = '<p>Error: WebGL2 is <a href="https://get.webgl.org/webgl2/">not supported by your browser</a></p>'; throw "WebGL2 not supported"; } function createShader(shaderType, sourceCode) { const shader = gl.createShader(shaderType); gl.shaderSource(shader, sourceCode); gl.compileShader(shader); if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) throw gl.getShaderInfoLog(shader); return shader; } const program = gl.createProgram(); gl.attachShader(program, createShader(gl.VERTEX_SHADER, vertexShader.textContent.trim())); gl.attachShader(program, createShader(gl.FRAGMENT_SHADER, fragmentShader.textContent.trim())); gl.linkProgram(program); if (!gl.getProgramParameter(program, gl.LINK_STATUS)) throw gl.getProgramInfoLog(program); gl.useProgram(program); const textureWidth = 20; const textureHeight = 20; const textureData = []; /* Format: [R, G, B, R, G, B, ...] */ for (let x = 0; x < textureWidth; x++) { for (let y = 0; y < textureHeight; y++) { // add a texture pixel via 3 values for R,G,B: textureData.push(x * 255 / textureWidth); // R textureData.push(y * 255 / textureHeight); // G textureData.push(127 * (Math.cos(x + y) + 1)); // B } } const tex = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, tex); gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGB, textureWidth, textureHeight, 0, gl.RGB, gl.UNSIGNED_BYTE, new Uint8Array(textureData) ); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); // or gl.LINEAR for interpolation /* // Prevent interpolating with wrap-around at the edges when using gl.LINEAR: gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); // or try gl.MIRRORED_REPEAT gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); */ const vertices = [[-1, -1], [1, -1], [-1, 1], [1, 1]]; gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer()); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices.flat()), gl.STATIC_DRAW); const vertexPosition = gl.getAttribLocation(program, "vertexPosition"); gl.enableVertexAttribArray(vertexPosition); gl.vertexAttribPointer(vertexPosition, 2, gl.FLOAT, false, 0, 0); const canvasSizeUniform = gl.getUniformLocation(program, 'canvasSize'); function draw() { const width = canvas.clientWidth; const height = canvas.clientHeight; canvas.width = width; canvas.height = height; gl.viewport(0, 0, width, height); gl.uniform2f(canvasSizeUniform, width, height); gl.drawArrays(gl.TRIANGLE_STRIP, 0, vertices.length); } window.addEventListener('resize', () => draw()); draw(); </script> </body> </html>