2018 年更新
在 2018 年,我建议使用多行模板文字,如用反引号围绕着色器,它可以跨越多行
const someShaderSource = `
attribute vec4 position;
uniform mat4 matrix;
void main() {
gl_Position = matrix * position;
}
`;
如果您想将着色器放在单独的文件中,您可以在 2018 年使用 JavaScript 模块轻松做到这一点。着色器文件可能如下所示
// someshader.glsl.js
export default `
attribute vec4 position;
uniform mat4 matrix;
void main() {
gl_Position = matrix * position;
}
`;
要使用 JavaScript 模块,您的主要 JavaScript 必须位于单独的文件中。您可以通过导入来访问着色器源
// main.js
import someShaderSource from './someshader.glsl.js';
// use someShadeSource
然后你将它包含在你的 HTML 中
<script src="main.js" type="module"></script>
或者您可以像这样从页面本身的脚本标签中使用它
<script type="module">
import someShaderSource from './someshader.glsl.js';
// use someShadeSource
</script>
如果您想支持较旧的浏览器,您可以使用汇总之类的工具,该工具将读取所有import
语句并生成一个大型 JavaScript 文件。这就是three.js 所做的。
如果需要支持 IE11,可以使用babel转换多行模板。多年来,所有其他浏览器都支持多行模板。
原始答案
为什么着色器必须在 webgl 程序的 html 文件中?
他们不
您可以将着色器放在外部 javascript 中。例如
// --myshader.js--
var myFragmentShader =
"void main() {\n" +
" gl_FragColor = vec4(1,0,0,1);\n" +
"}n\";
或者另一种常见的格式
// --myshader.js--
var myFragmentShader = [
"void main() {",
" gl_FragColor = vec4(1,0,0,1);",
"}",
].join("\n");
在所有支持 WebGL 的浏览器中,您都可以使用模板文字
// --myshader.js--
var myFragmentShader = `
void main() {
gl_FragColor = vec4(1,0,0,1);
}
`;
否则,您可以将它们放在文本文件中并使用 XMLHTTPRequest 加载它们
// --myshader.txt
void main() {
gl_FragColor = vec4(1,0,0,1);
}
然后在 JavaScript 中执行以下操作
function loadTextFile(url, callback) {
var request = new XMLHttpRequest();
request.open('GET', url, true);
request.addEventListener('load', function() {
callback(request.responseText);
});
request.send();
}
loadTextFile("myshader.txt", function(text) {
// use text...
});
人们将它们放在 HTML 中的原因是因为它简单、高效且同步。
easy:与 JS 文件版本不同,您不必在每一行都用引号和其他标点符号括起来。尽管现在使用 es6 不再是问题。每个支持 WebGL 的浏览器都支持 es6 模板字符串。
高效:与文本和 js 文件不同,服务器只有一个请求。当然,有些人可能会在他们的 js 文件上运行连接器来修复其中的一些问题。
同步:与文本文件不同,它们的用法是同步的。无需回调或承诺或以其他方式处理下载文件的异步问题。
至于为什么您的示例不起作用,我很确定原因是它允许跨源资源访问。该<script>
标签是在人们发现跨源访问是一个问题之前设计的,因此他们无法在不破坏一堆站点的情况下关闭跨源脚本。他们可以使其他一切变得更加严格。
例如,XMLHttpRequest 不允许跨源访问,除非您联系的服务器给予许可。如果脚本标签允许您访问该内容,您可以使用脚本标签来解决该限制。换句话说,request.responseText
您只需以编程方式制作一个脚本标记,而不是制作 XMLHttpRequest 并读取结果,而是将其设置src
为您想要的 URL,然后text
在完成时读取其字段。为了确保您不能这样做,您不允许读取具有属性text
的脚本标签的字段src