避免两个glsl着色器之间共享的函数的代码重复

时间:2016-04-28 20:51:02

标签: webgl shader code-duplication

我的HTML页面(pipad.org/tmp/fourier02.html)包含两个着色器:

<script type="application/glsl" id="shaderA">
    uniform vec4 a;
    vec4 f(vec4 x, vec4 y){ ... } // DUP
    vec4 main(vec4 u, vec4 v) { return f(a,u); }
</script>

<script type="application/glsl" id="shaderB">
    uniform vec4 a;
    vec4 f(vec4 x, vec4 y){ ... } // DUP
    vec4 main(vec4 u) { return f(a,u); } // notice main's sig is different
</script>  

我希望我不会过于简单化,如果是的话,我可能需要修改。这些着色器以不同的方式使用(shaderB是RTT)。

可以看出,f在两种情况下都是相同的。

有没有办法避免写两次?

我能看到的唯一方法就是将着色器保持为字符串,因为语法突出显示不再有效而你必须这样做:

:
var
f = 
    "vec4 f(vec4 x, vec4 y){\n" +
    "...\n" +
    "}\n",

shaderA = f + 
    "uniform vec4 a;\n" +
    "vec4 main(vec4 u, vec4 v) { return f(a,u); }\n",

shaderB = f + 
    "uniform vec4 a;\n" +
    "vec4 main(vec4 u) { return f(a,u); }\n"
;

这是...... meh。没有比原来明显的优势。我们刚刚交换了ickyness的重复。

有更好的方法吗?

3 个答案:

答案 0 :(得分:2)

正如您已经发现的那样,字符串操作是制作着色器的常用方法。几乎所有大型引擎都使用大量字符串替换来在运行时构建着色器。 WaclawJasper指出了模板字符串。它们是JavaScript的一个新功能,但由于几乎所有支持WebGL的浏览器都能获得定期更新,因此您可以非常安全地使用它们,或者您可以使用polyfill。

实施例

&#13;
&#13;
var t = {
  PI: '3.14159',
  plusToPlusMinus: `
    float plusToPlusMinus(float v) {
       return v * 2.0 - 1.0;
    }
  `,
};

var shader = `
  ${t.plusToPlusMinus}
  ...
  void main() {
   a = b * ${t.PI};
  }
`;

console.log(shader);
&#13;
&#13;
&#13;

输出:

  float plusToPlusMinus(float v) {
     return v * 2.0 - 1.0;
  }

...
void main() {
 a = b * 3.14159;
}

答案 1 :(得分:1)

听起来你正在寻找的是template strings。它默认支持多行字符串。

如果兼容性是一个问题,shader = ["blah", "blah"].join('\n');是IMO清洁而不是字符串连接。

答案 2 :(得分:1)

最后,我将我的常用功能移到了一个单独的<script type="application/glsl" id="common">标签上并执行了:

<script> 
    :
    function joinElements(A,B) {
        return document.getElementById(A).innerHTML 
             + document.getElementById(B).innerHTML;
    }
    :

...然后将"#shaderA"替换为joinElements("#common", "shaderA");