2016-04-28 83 views
1

我的HTML页面(pipad.org/tmp/fourier02.html)之间共享包含两个着色器:一个函数避免重复代码2个GLSL着色器

<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> 

我希望我没有简单化,我可以有如果我是修改。这些着色器以不同的方式使用(着色器B是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。没有明显的优势。我们刚刚交换了琐碎的重复。

有没有更好的方法?

回答

2

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

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

输出:

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

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

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

如果兼容性问题,shader = ["blah", "blah"].join('\n');是比字符串串联更清洁的IMO。

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