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

App*_*lik 6 shader glsl webgl

有没有办法将此着色器代码作为不带引号的外部vertexShader.js包含在“脚本”标签之间?

var vertCode =
'attribute vec3 coordinates;' +

'void main(void) {' +
' gl_Position = vec4(coordinates, 1.0);' +
'gl_PointSize = 10.0;'+
'}';
Run Code Online (Sandbox Code Playgroud)

gma*_*man 6

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

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

  const str = `
  this
  string
  is
  on
  multiple lines
  `;
Run Code Online (Sandbox Code Playgroud)

所以没有必要像你在做的那样使用“这个”+“那个”。

如果你真的想把它们放在单独的文件中,那么这里至少有 3 种方法可以做到

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

    顶点着色器.js

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

    在你的 html

    <script src="vertexShader.js"></script>
    <script>
     // use shader as window.shaders.someVertexShader
     ...
    </script>
    
    Run Code Online (Sandbox Code Playgroud)

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

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

    现代浏览器支持ES6 模块

    顶点着色器.js

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

    在这种情况下,您的 JavaScript 脚本必须位于外部文件中,因此您的 HTML 可能如下所示

    <script src="main.js" type="module"></script>
    
    Run Code Online (Sandbox Code Playgroud)

    和 main.js 看起来像这样

    import someVertexShader from './vertexShader.js';
    
    // use someVertexShader
    
    Run Code Online (Sandbox Code Playgroud)

    这里有一个例子在这里

  • 加载它们 fetch

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

    vertexShader.shader

    attribute vec3 coordinates;
    
    void main(void) {
        gl_Position = vec4(coordinates, 1.0);
        gl_PointSize = 10.0;'
    }
    
    Run Code Online (Sandbox Code Playgroud)

    然后在你的脚本中

    fetch('./vertexShader.shader')
    .then(response => response.text())
    .then((shaderSource) => {
       // use shadeSource
    });
    
    Run Code Online (Sandbox Code Playgroud)

    这种方法的最大问题是脚本是异步下载的,因此您必须手动等待它们下载。不过使用 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();
    
    Run Code Online (Sandbox Code Playgroud)

如果是我并且我真的想将我的着色器放在我可能会使用的外部文件中import,然后要么只针对现代浏览器,要么使用诸如webpackrollup 之类的程序将它们打包成单个文件以供运输。这就是THREE.js当前所做的。


Rab*_*d76 5

您可以将着色器代码添加到顶点着色器和片段着色器<script>的类型标记中。另见WebGL 和 HTML 着色器类型"x-shader/x-vertex""x-shader/x-fragment"

<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>
Run Code Online (Sandbox Code Playgroud)

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

var vertCode = document.getElementById("my_vertex_shader").text;
var fragCode = document.getElementById("my_fragment_shader").text;
Run Code Online (Sandbox Code Playgroud)

WebGL - 有没有替代在 HTML 中嵌入着色器的方法?可能也很有趣。