如何使用OpenGL组织Shader系统?

4
我在思考:
创建一个主着色器,该着色器将应用于应用程序中的每个对象,用于投影、变换、定位、着色等。
每个对象都可以有自己的额外着色器来处理其他内容,例如水对象肯定需要一个额外的着色器。
但是存在一个问题,如何将2个或更多的着色器应用于一个对象?因为我需要应用主着色器+对象自己的着色器。
1个回答

2
如果OpenGL(或Direct3D!)允许您在每个顶点/片段/任何阶段拥有多个着色器,那将是非常好的,但不幸的是我们被困在现有系统中。
假设您编写了一堆GLSL函数。其中一些是通用于所有对象的,例如应用模型视图变换和将纹理坐标复制到下一个阶段。有些则特定于特定类别的对象,例如水或岩石。
然后您编写的是“ubershader”,这是一个程序,在其中顶点/片段/任何阶段的main()函数除了调用所有这些函数之外什么都不做。这是一个模板或原型,从中生成更专业的程序。
最常见的方法是使用预处理器和大量的#ifdefs来调用main()函数内部的函数调用。也许如果您没有任何#define编译,您会得到标准变换和Gouraud着色。添加#define WATER以获得水效果,#define DISTORT以获得某种自由形变算法,两者都可以获得自由形变的水,#define FOG以添加雾效果,...
您甚至不需要拥有超级着色器源代码的多个副本,因为您可以在运行时生成#define字符串,并将它们传递给glCompileShader。
您最终得到了很多着色器程序,每种渲染类型一个。如果出于任何原因,您希望始终只使用一个程序,则可以在较新的GLSL子例程系统上执行类似操作。
这些基本上是GLSL中的函数指针,您可以像uniforms一样设置它们。现在您的ubershader在main()函数中有1,2,...个函数指针调用。您的程序只需将#1设置为标准变换,#2设置为岩石/水/其他,#3设置为雾,...如果您不想使用阶段,请拥有一个NOP函数,可以分配它。
虽然这具有仅使用一个程序的优点,但与#define方法相比并不那么灵活,因为任何给定指针都必须使用相同的函数原型。如果说WATER需要在多个着色器中处理,那么这也需要更多的工作,因为您必须记住在每个着色器中设置函数指针,而不仅仅是单个#define。
希望这可以帮助您。

您可以将多个着色器附加到一个着色器阶段,只要其中一个着色器有一个 main() 函数即可。 - Reto Koradi
谢谢你的回答。所以如果我理解正确,我的额外着色器应该只是没有main()函数的函数,并且我应该通过主着色器的main()函数来调用它们,并使用预处理指令进行管理。 - thp9
是的。举个非常简单的例子,可以访问 https://github.com/apertus-open-source-cinema/stereo_cam_check 并查看 renderer.py 和 video_frag.glsl。(代码是内联的,而不是调用单独的函数。) - Hugh Fisher

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接