Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to include shaders as external files

Tags:

glsl

shader

webgl

Is there a way to include this shader code as an external vertexShader.js without quotes and include between "script" tags?

var vertCode =
'attribute vec3 coordinates;' +

'void main(void) {' +
' gl_Position = vec4(coordinates, 1.0);' +
'gl_PointSize = 10.0;'+
'}';
like image 842
Applik Avatar asked Nov 16 '18 10:11

Applik


2 Answers

You asked how to include shaders as external files

There are several ways but first off it's important to note that using backticks for strings which are called multiline template literals let you have multiline strings

const str = `
this
string
is
on
multiple lines
`;

So there's no need to use 'this' + 'that' as you were doing.

If you really want to put them in separate files though then here's at least 3 of the many ways you could do it

  • put them in separate script files, assign to some global. Example

    vertexShader.js

      window.shaders = window.shaders || {};
      window.shaders.someVertexShader = `
      attribute vec3 coordinates;
    
      void main(void) {
          gl_Position = vec4(coordinates, 1.0);
          gl_PointSize = 10.0;'
      }
      `;
    

    in your html

      <script src="vertexShader.js"></script>
      <script>
       // use shader as window.shaders.someVertexShader
       ...
      </script>
    

    Note that your final JavaScript script could also be in a separate file just as long as it comes after the shader files.

  • Put them in a separate JavaScript module

    Modern browsers support ES6 modules

    vertexShader.js

      export default `
      attribute vec3 coordinates;
    
      void main(void) {
          gl_Position = vec4(coordinates, 1.0);
          gl_PointSize = 10.0;'
      }
      `;
    

    In this case your JavaScript script must be in an external file so your HTML might look something like this

      <script src="main.js" type="module"></script>
    

    and main.js would look something like this

      import someVertexShader from './vertexShader.js';
    
      // use someVertexShader
    

    There's an example here

  • Load them with fetch

    In this case there's no JavaScript in the shader file

    vertexShader.shader

      attribute vec3 coordinates;
    
      void main(void) {
          gl_Position = vec4(coordinates, 1.0);
          gl_PointSize = 10.0;'
      }
    

    Then in your script

      fetch('./vertexShader.shader')
      .then(response => response.text())
      .then((shaderSource) => {
         // use shadeSource
      });
    

    The biggest problem with this method is the scripts are downloaded asynchronously so you have to manually wait for them to download. Using async/await that's pretty easy though.

    Imagine you wanted to download 6 shaders files and then use them. This code would wait for all 6 files to download before starting

      function loadTextFile(url) {
        return fetch(url).then(response => response.text());
      }
    
      const urls = [
        './someShader1.shader',
        './someShader2.shader',
        './someShader3.shader',
        './someShader4.shader',
        './someShader5.shader',
        './someShader6.shader',
      });   
    
      async function main() {
        const files = await Promise.all(urls.map(loadTextFile));
        // use files[0] thru files[5]
      }
      main();
    

If it was me and I really wanted to put my shaders in external files I'd probably use import and then either only target modern browsers or else use some program like webpack or rollup to package them into a single file for shipping. This is what THREE.js currently does.

like image 149
gman Avatar answered Nov 01 '22 04:11

gman


You can add the shader code to a <script> tag of type "x-shader/x-vertex" for the vertex shader and "x-shader/x-fragment" for the fragment shader. See also WebGL and HTML shader-type

<script id="my_vertex_shader" type="x-shader/x-vertex">
attribute vec3 coordinates;
 
void main(void) {
    gl_Position = vec4(coordinates, 1.0);
    gl_PointSize = 10.0;
}
</script>

<script id="my_fragment_shader" type="x-shader/x-fragment">
// fragment shader code
</script>

The shader code can be "loaded" with ease:

var vertCode = document.getElementById("my_vertex_shader").text;
var fragCode = document.getElementById("my_fragment_shader").text;

WebGL - is there an alternative to embedding shaders in HTML? may be of interest, too.

like image 30
Rabbid76 Avatar answered Nov 01 '22 03:11

Rabbid76