有谁知道是否可以在单个 Web-GL“程序”中连续运行多个片段着色器?我正在尝试使用着色器效果复制我在 WPF 中编写的一些代码。在 WPF 程序中,我将包装具有多个边框的图像,并且每个边框都会附加一个效果(允许多个效果在同一个图像上连续运行)。
4 回答
恐怕您可能需要稍微澄清一下您的问题,但无论如何我都会尝试回答:
WebGL 可以有效地支持任意数量的不同着色器。(当然存在一些实际限制,例如可用内存,但您必须非常努力地通过创建太多着色器来达到这些限制。)事实上,大多数“现实世界”WebGL/OpenGL 应用程序将使用许多不同的组合着色器以生成渲染到屏幕的最终场景。(一个简单的例子:水通常会使用与其周围环境的其他部分不同的着色器或一组着色器来渲染。)
在调度渲染命令时,一次只能有一个着色器程序处于活动状态。当前活动的程序是通过调用指定的,gl.useProgram(shaderProgram);
之后将使用该程序渲染绘制的任何几何图形。如果要渲染需要多个不同着色器的效果,则需要按着色器对它们进行分组并分别绘制每个批次:
gl.useProgram(shader1);
// Setup shader1 uniforms, bind the appropriate buffers, etc.
gl.drawElements(gl.TRIANGLES, shader1VertexCount, gl.UNSIGNED_SHORT, 0); // Draw geometry that uses shader1
gl.useProgram(shader2);
// Setup shader2 uniforms, bind the appropriate buffers, etc.
gl.drawElements(gl.TRIANGLES, shader2VertexCount, gl.UNSIGNED_SHORT, 0); // Draw geometry that uses shader2
// And so on...
其他答案都在正确的轨道上。您要么需要动态创建将所有效果应用到一个着色器或帧缓冲区中的着色器,然后一次应用一个效果。有一个后面的例子here
正如 Toji 建议的那样,您可能想澄清您的问题。如果我理解正确,您想对图像应用一组后处理效果。
您的问题的简单答案是:不,您不能将多个片段着色器与一个顶点着色器一起使用。
但是,有两种方法可以做到这一点:首先,您可以在一个片段着色器中编写所有内容,最后将它们组合起来。这取决于你想要的效果!其次,您可以编写多个着色器程序(每个效果一个)并将结果写入片段缓冲区对象(渲染到纹理)。每个着色器都会获得前一个效果的结果并应用下一个效果。这会有点复杂,但它是最灵活的方法。
如果您的意思是在单个渲染过程中运行多个着色器,就像这样(从稀薄的空气中提取的示例):
- 顶点颜色
- 质地
- 灯光
- 阴影
...每个阶段都附加到一个WebGLProgram
对象,每个阶段都有自己的main()
功能,那么不,GLSL 不能以这种方式工作。
GLSL 的工作方式更像 C/C++,其中您有一个main()
作为程序入口点的全局函数,以及附加到它的任意数量的库。上面的四个示例都可以是一个单独的“库”,可以单独编译,但可以链接到一个程序中,并由一个main()
函数调用,但它们可能并不都定义自己的main()
函数,因为 GLSL 中的这些定义是共享的整个程序。
main()
不幸的是,这要求您(至少)为您打算使用的每个着色器编写单独的函数,这会导致大量冗余编程,即使您打算重用库本身。这就是为什么我最终编写了一个美化的字符串处理程序来管理我的Jax的 GLSL 库;我不确定代码在我的框架之外会有多大用处,但您当然可以随意查看它,并使用您认为有帮助的任何内容。相关文件为:
- lib/assets/javascripts/jax/shader.js.coffee
- lib/assets/javascripts/jax/shader/program.js.coffee
- spec/javascripts/jax/shader_spec.js.coffee(测试和使用示例)
- spec/javascripts/jax/shader/program_spec.js.coffee(更多测试和使用示例)
祝你好运!