The source of your problem is that you cannot get from the web pages that were opened using the file:// protocol using the same protocol resources that are near to the disk. This feature is disabled in browsers for security reasons.
However, you are absolutely not obliged to connect the shaders as separate files.
You need to pass the source code to the shader compiler, in the form of strings, and how you will store and retrieve these strings in the place where you need it - there are options.
Thus, you can create one html page with a webgl application that will open locally and without a web server .
To do this, you can:
Keep the glsl code directly in the javascript sections as strings:
<canvas> <script> let started = new Date().getTime(); let canvas = document.querySelector('canvas'); let size = canvas.width = canvas.height = 150; let gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl'); let pid = gl.createProgram(); shader(` attribute vec2 coords; void main(void) { gl_Position = vec4(coords.xy, 0.0, 1.0); } `, gl.VERTEX_SHADER); shader(` precision highp float; uniform float time; void main(void) { vec2 uv = gl_FragCoord.xy / ${size}.; gl_FragColor = vec4(uv,sin(time),1.); } `, gl.FRAGMENT_SHADER); gl.linkProgram(pid); gl.useProgram(pid); let array = new Float32Array([-1, 3, -1, -1, 3, -1]); gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer()); gl.bufferData(gl.ARRAY_BUFFER, array, gl.STATIC_DRAW); let al = gl.getAttribLocation(pid, "coords"); gl.vertexAttribPointer(al, 2 /*components per vertex */, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(al); let time = gl.getUniformLocation(pid, 'time'); draw(); function draw() { requestAnimationFrame(draw); gl.uniform1f(time, (new Date().getTime() - started)/1000); gl.viewport(0, 0, size, size); gl.clearColor(0, 0, 0, 0); gl.drawArrays(gl.TRIANGLES, 0, 3); } function shader(src, type) { let sid = gl.createShader(type); gl.shaderSource(sid, src); gl.compileShader(sid); gl.attachShader(pid, sid); } </script>
If you use any of the various modern bundlers that pack web applications into one or more js tailings, you can keep the shader text in a separate file. And import it at the place of use, so there is no modularity in glsl .
The next step is modularity directly inside the glsl code, (so as not to copy-paste 300 times in different shaders the same code), there are 2 ways: your own bike or a more serious solution, for example, glslify is a ready-made solution and a huge ecosystem of various pieces for shaders built on top of npm
let glsl = require('glslify') let shaderCode = glsl(` #pragma glslify: noise = require('glsl-noise/simplex/3d') precision mediump float; varying vec3 vpos; void main () { gl_FragColor = vec4(noise(vpos*25.0),1); } `);
On the Internet and in many tutorials they use <script> tags with a type other than text/javascript . Indirectly using the fact that such sections will not automatically be executed by themselves, like javascript itself :
Here is an example:
<canvas></canvas> <script type='glsl/vertex'> attribute vec2 coords; void main(void) { gl_Position = vec4(coords.xy, 0.0, 1.0); } </script> <script type='glsl/fragment'>precision highp float; uniform vec4 mr; // (m)ouse position and screen (r)esolution void main(void) { vec2 p = gl_FragCoord.xy; vec2 q = (p + p - mr.ba) / mr.b; for(int i = 0; i < 13; i++) q = abs(q)/dot(q,q) - mr.xy/mr.zw; gl_FragColor = vec4(q, qx/qy, 1.0); } </script> <script> let canvas = document.querySelector('canvas'); canvas.width = window.innerWidth; canvas.height = window.innerHeight; let gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl'); var h = gl.drawingBufferHeight; var w = gl.drawingBufferWidth; let pid = gl.createProgram(); shader('glsl/vertex', gl.VERTEX_SHADER); shader('glsl/fragment', gl.FRAGMENT_SHADER); gl.linkProgram(pid); gl.useProgram(pid); let array = new Float32Array([-1, 3, -1, -1, 3, -1]); gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer()); gl.bufferData(gl.ARRAY_BUFFER, array, gl.STATIC_DRAW); let al = gl.getAttribLocation(pid, "coords"); gl.vertexAttribPointer(al, 2 /*components per vertex */, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(al); let mr = gl.getUniformLocation(pid, 'mr'); // (m)ouse position and screen (r)esolution window.addEventListener('mousemove', draw); window.addEventListener('touchmove', draw); draw(); function draw(e) { let ev = e && e.touches ? e.touches[0] : e; let x = ev ? ev.clientX : 250; let y = ev ? h - ev.clientY: 111; gl.uniform4f(mr, x, y, w, h); gl.viewport(0, 0, w, h); gl.clearColor(0, 0, 0, 0); gl.drawArrays(gl.TRIANGLES, 0, 3 /* 3 vertices */); } function shader(name, type) { let src = [...document.scripts].find(s => s.type === name).innerText; let sid = gl.createShader(type); gl.shaderSource(sid, src); gl.compileShader(sid); gl.attachShader(pid, sid); } </script> <style> body { margin: 0; overflow: hidden; } </style>
PS: fractal, which is drawn here, someone Kali found and told the world about it in this topic with fractalforums