diff --git a/www/css/shader-style.css b/www/css/shader-style.css index 9b39002..2e87d83 100644 --- a/www/css/shader-style.css +++ b/www/css/shader-style.css @@ -1,11 +1,8 @@ .gl-canvas-bg { - display:block; - width: 100vw; - height: 100vh; - position: fixed; left: 0; top: 0; - + width: 100%; + height: 100%; z-index: -1; } diff --git a/www/js/draw-scene.js b/www/js/draw-scene.js index 0df76cc..6405916 100644 --- a/www/js/draw-scene.js +++ b/www/js/draw-scene.js @@ -1,7 +1,4 @@ function drawScene(gl, programInfo, buffers, time) { - // Tell WebGL how to convert from clip space to pixels - gl.viewport(0, 0, gl.canvas.width, gl.canvas.height); - gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear to black, fully opaque gl.clearDepth(1.0); // Clear everything gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); @@ -24,8 +21,8 @@ function drawScene(gl, programInfo, buffers, time) { // Viewport resolution in pixels gl.uniform2f( programInfo.uniformLocations.resolution, - gl.canvas.width, - gl.canvas.height, + gl.drawingBufferWidth, + gl.drawingBufferHeight, ); { diff --git a/www/js/webgl-demo.js b/www/js/webgl-demo.js index 10deb74..d300cc5 100644 --- a/www/js/webgl-demo.js +++ b/www/js/webgl-demo.js @@ -3,6 +3,10 @@ import { drawScene } from "./draw-scene.js"; main(); +/* XXX: TODO: Avoid using alerts! Check return values instead, + * XXX: TODO: or create/use a Result like object. + */ + // Initialize a shader program, so WebGL knows how to draw our data function initShaderProgram(gl, vsSource, fsSource) { const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource); @@ -39,14 +43,73 @@ function loadShader(gl, type, source) { // See if it compiled successfully if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { + alert( + `An error occurred compiling the shaders: ${gl.getShaderInfoLog(shader)}`, + ); gl.deleteShader(shader); - throw new Error(`An error occurred compiling the shaders: ${gl.getShaderInfoLog(shader)}`); + return null; } return shader; } -function renderShader(gl, vsSource, fsSource) { +function main() { + const canvas = document.querySelector("#gl-canvas"); + // Initialize the GL context + const gl = canvas.getContext("webgl"); + + // Only continue if WebGL is available and working + if (gl === null) { + alert( + "Unable to initialize WebGL. Your browser or machine may not support it.", + ); + return; + } + + // Vertex shader program + const vsSource = ` + attribute vec4 aVertexPosition; + + void main() { + gl_Position = aVertexPosition; + } + `; + + // const fsSource = ` + // // is highp wasteful for this shader? + // #ifdef GL_FRAGMENT_PRECISION_HIGH + // precision highp float; + // #else + // precision mediump float; + // #endif + + // // shadertoy-like parameters + // // uniform vec2 uResolution; + // uniform float uTime; + + // void main() { + // vec2 uv = gl_FragCoord.xy/vec2(300, 300).xy; + + // // Time varying pixel color + // vec3 col = 0.5 + 0.5*cos(uTime+uv.xyx+vec3(0,2,4)); + + // // Output to screen + // gl_FragColor = vec4(col,1.0); + + // // gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); + // } + // `; + const fsSource = (async () => { + const res = await fetch("../shaders/segfault.glsl"); + if (!res.ok) { + const error = `Failed to load fragment shader source ${url}: ${res.status}`; + alert(error); + throw new Error(error); + } + + return await res.text() + })(); + const shaderProgram = initShaderProgram(gl, vsSource, fsSource); // Collect all the info needed to use the shader program. @@ -58,8 +121,8 @@ function renderShader(gl, vsSource, fsSource) { vertexPosition: gl.getAttribLocation(shaderProgram, "aVertexPosition"), }, uniformLocations: { - resolution: gl.getUniformLocation(shaderProgram, "u_resolution"), - time: gl.getUniformLocation(shaderProgram, "u_time"), + resolution: context.getUniformLocation(program, "uResolution"), + time: gl.getUniformLocation(shaderProgram, "uTime"), }, }; @@ -82,47 +145,5 @@ function renderShader(gl, vsSource, fsSource) { requestAnimationFrame(render); } requestAnimationFrame(render); - - // XXX: TODO: read this guide it's great! https://stackoverflow.com/questions/56998225/why-is-rendering-blurred-in-webgl - // window.addEventListener('resize', render); -} - -function fetchShader(name) { - return fetch(`../shaders/${name}`) - .then(res => { - if (!res.ok) throw new Error(`Failed to load fragment shader source ${url}: ${res.status}`); - return res.text(); - }); - -} - -function main() { - const canvas = document.querySelector("#gl-canvas"); - // Initialize the GL context - const gl = canvas.getContext("webgl"); - - // XXX: TODO: use `window.addEventListener('resize', ...);` - canvas.setAttribute('width', window.innerWidth); - canvas.setAttribute('height', window.innerHeight); - - // Only continue if WebGL is available and working - if (gl === null) { - throw new Error("Unable to initialize WebGL. Your browser or machine may not support it."); - } - - // Vertex shader program - const vsSource = ` - attribute vec4 aVertexPosition; - - void main() { - gl_Position = aVertexPosition; - } - `; - - // Fetch fragment shader program - fetchShader("segfault.glsl") - .then(fsSource => { - renderShader(gl, vsSource, fsSource); - }); } diff --git a/www/shaders/segfault.glsl b/www/shaders/segfault.glsl index a3d73a8..78e9766 100644 --- a/www/shaders/segfault.glsl +++ b/www/shaders/segfault.glsl @@ -4,20 +4,16 @@ * View this shader on shadertoy: https://www.shadertoy.com/view/t3tSRj# */ -// is highp wasteful for this shader? -#ifdef GL_FRAGMENT_PRECISION_HIGH - precision highp float; -#else - precision mediump float; +#ifdef GL_ES +precision highp float; #endif -uniform float u_time; -uniform vec2 u_resolution; +uniform float uTime; +uniform vec2 uResolution; /* ==== Text Colouring ==== */ #define PHOSPHOR_COL vec4(1, 1., 1., 1.) -// #define BG_COL vec4(0.2, 0.0, 0.2, 0.5) -#define BG_COL vec4(0.0, 0.0, 0.0, 1.) +#define BG_COL vec4(0.2, 0.0, 0.2, 0.) /* ======= Text Size ======= */ #define FONT_SIZE vec2(10.,20.) #define ROWCOLS vec2(80., 24.) @@ -155,9 +151,9 @@ float roundLine(vec2 p, vec2 a, vec2 b) { b -= a + vec2(1.0,0.); p -= a; float f = length(p-clamp(dot(p,b)/dot(b,b),0.0,1.0)*b); - if (u_resolution.y < 320.) // attempt to get rid of aliasing on small resolution + if (uResolution.y < 320.) // attempt to get rid of aliasing on small resolution return smoothstep(1.0, 0.9, f); - else if (u_resolution.y < 720.) + else if (uResolution.y < 720.) return smoothstep(0.75, 0.5, f); else return smoothstep(1., 0., f); @@ -305,7 +301,7 @@ float vt220Font(vec2 p, float c) { // https://www.shadertoy.com/view/MsdGWn // float textLines(vec2 uvG) { - float wt = 5. * (u_time + 0.5*sin(u_time*1.4) + 0.2*sin(u_time*2.9)); // wobbly time + float wt = 5. * (uTime + 0.5*sin(uTime*1.4) + 0.2*sin(uTime*2.9)); // wobbly time vec2 uvGt = uvG + vec2(0., floor(wt)); float ll = rand(vec2(uvGt.y, - 1.)) * ROWCOLS.x; // line length @@ -350,22 +346,33 @@ float smokeNoise(vec3 v) { return fbm5(v) / 2. + 0.5; } +// =================================================================== +// Graphical Styling / Effects +// +float bloom(vec2 uv2) { + // TODO + c += (textureLod(iChannel0, uvC, 3.) + + textureLod(iChannel0, uvC, 4.) + + textureLod(iChannel0, uvC, 5.)) + * smoothstep(0., -SMOOTH*20., stdRS(uvC, -0.02)) * 0.5; +} + void main() { - vec2 uv = vec2(gl_FragCoord.x, u_resolution.y - gl_FragCoord.y); - vec2 uvT = ROWCOLS * FONT_SIZE * uv / u_resolution.xy; - vec2 uvG = floor(ROWCOLS * uv / u_resolution.xy); - vec2 uvC = gl_FragCoord.xy / u_resolution.xy; + vec2 uv = vec2(gl_FragCoord.x, uResolution.y - gl_FragCoord.y); + vec2 uvT = ROWCOLS * FONT_SIZE * uv / uResolution.xy; + vec2 uvG = floor(ROWCOLS * uv / uResolution.xy); + vec2 uvC = gl_FragCoord.xy / uResolution; - vec2 uvNoise = gl_FragCoord.xy / u_resolution.xy; + vec2 uvNoise = uvC; uvNoise = ceil(uvNoise * ROWCOLS) / ROWCOLS; float val; - if (u_time < 2.0) + if (uTime < 2.0) val = textLines(uvG); - else if (u_time < 2.3) - val = rand(uvG * u_time) * 17.; + else if (uTime < 2.3) + val = rand(uvG * uTime) * 17.; else { - float noise = smokeNoise(vec3(uvNoise * noiseScale, u_time * noiseTimeScale)); + float noise = smokeNoise(vec3(uvNoise * noiseScale, uTime * noiseTimeScale)); // Noise is fed through a sigmoid function, then quantised to integer range 0-17 val = (exp(noise) / 2.71828); // increase contrast (normalised 0.0 - 1.0) val = 1.0 / val; @@ -374,6 +381,6 @@ void main() { val = pow(18.0, val) - 1.0; // TODO: try changing 18.0 to 200.0 and you'll notice some pretty changes :) } - gl_FragColor = vt220Font(uvT - uvG * FONT_SIZE, val) * PHOSPHOR_COL + BG_COL; + gl_FragColor = vt220Font(uvT - uvG * FONT_SIZE, val) * PHOSPHOR_COL + BG_COL; } diff --git a/www/shaders/trivial.glsl b/www/shaders/trivial.glsl deleted file mode 100644 index 22464ae..0000000 --- a/www/shaders/trivial.glsl +++ /dev/null @@ -1,18 +0,0 @@ -// is highp wasteful for this shader? -#ifdef GL_FRAGMENT_PRECISION_HIGH - precision highp float; -#else - precision mediump float; -#endif - -uniform float u_time; -uniform vec2 u_resolution; - -void main() { - vec2 uv = gl_FragCoord.xy / u_resolution; - - vec3 col = 0.5 + 0.5 * cos(u_time + uv.xyx + vec3(0, 2, 4)); - - gl_FragColor = vec4(col,1.0); -} -