In the book of K. Matsuda, R. Lee - WebGL. Programming of three-dimensional graphics is used everywhere embedded shaders. How to connect shaders from files. The solution described in the same book did not work:

XMLHttpRequest cannot load file: /// D: /Development/WebGL/DrawPoint/DrawPointVertesShader.gls. Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https, chrome-extension-resource.loadShaderFile @ ShaderUtilities.js: 12

XMLHttpRequest cannot load file: /// D: /Development/WebGL/DrawPoint/DrawPointFragmentShader.gls. Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https, chrome-extension-resource.

Some suggested raising a server and taking it from there. But this is not good as the game is spelled, and of course the game should work without a hitch and a hitch from the user. Is there any simple mechanism?

  • Raise the server. There are static hosting, the same Github Pages . - D-side

1 answer 1

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

  • Yeah. Excellent answer and the picture is fascinating, and not one bite. Most people stuck :)) - Alexandr_TT
  • @Alexandr_TT thanks for the kind word, and the picture is the Kali fractal ( twitter.com/pabloandrioli ), with a slight change - Stranger in the Q
  • @Alexandr_TT changed the number of iterations in the shader, now the picture is more interesting - Stranger in the Q
  • Generally shine has become. Okay, see you tomorrow - Alexandr_TT