如何将着色器包含为外部文件

时间:2018-11-16 10:49:47

标签: glsl webgl

是否有一种方法可以将此着色器代码作为外部 vertexShader.js 而不加引号并将其包含在“ script”标记之间?

var vertCode =
'attribute vec3 coordinates;' +

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

2 个答案:

答案 0 :(得分:3)

您可以将着色器代码添加到用于顶点着色器的<script>类型的"x-shader/x-vertex"标签和用于片段着色器的"x-shader/x-fragment"中。 另请参见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>

可以轻松地“加载”着色器代码:

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?可能也很有趣。

答案 1 :(得分:2)

您询问如何将着色器作为外部文件

有几种方法,但首先要注意的是,对称为multiline template literals的字符串使用反引号可以使您拥有多行字符串

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

因此,您无需像以前一样使用'this'+'that'。

但是,如果您确实希望将它们放在单独的文件中,那么至少可以使用以下三种方法

  • 将它们放在单独的脚本文件中,并分配给一些全局文件。例子

    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;'
    }
    `;
    

    在您的html中

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

    请注意,您的最终JavaScript脚本也可以位于单独的文件中,只要它位于着色器文件之后即可。

  • 将它们放在单独的JavaScript模块中

    现代浏览器支持ES6 modules

    vertexShader.js

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

    在这种情况下,您的JavaScript脚本必须位于外部文件中,因此您的 HTML可能看起来像这样

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

    和main.js看起来像这样

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

    有一个示例here

  • 使用fetch

    加载它们

    在这种情况下,着色器文件中没有JavaScript

    vertexShader.shader

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

    然后在您的脚本中

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

    此方法的最大问题是脚本是异步下载的,因此您必须手动等待它们下载。不过,使用async / await非常简单。

    想象一下,您想下载6个着色器文件,然后使用它们。此代码将在开始之前等待所有6个文件下载

    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();
    

如果是我,并且我真的想将着色器放在外部文件中,则可能会使用import,然后要么仅针对现代浏览器,要么使用诸如webpack或{{3 }}将它们打包为一个文件进行运输。 rollup目前正在这样做。