我应该如何使用opengl组织着色器系统

时间:2014-05-18 20:16:22

标签: opengl shader 3d-engine

我在考虑:

有一个主着色器将应用于我的应用程序的每个对象,它将用于投影,转换,定位,着色等。

每个对象都可以有额外的着色器,例如水对象肯定需要额外的着色器。

但是有一个问题,我如何将2个或更多着色器应用到一个对象中?因为我需要应用主着色器+对象自己的着色器。

1 个答案:

答案 0 :(得分:2)

如果OpenGL(或Direct3D!)允许你在每个顶点/片段/任何阶段拥有多个着色器,那将是非常好的,但是我们仍然坚持使用现有系统。

假设您已经编写了一堆GLSL函数。有些是所有对象的通用目的,例如应用模型视图转换和将纹理坐标复制到下一个阶段。有些特定于特定类别的物体,例如水或岩石。

然后你写的是 ubershader ,这是一个程序,其中除了调用所有这些函数之外,vertex / fragment /中任何阶段的main()函数都没有做任何事情。这是一个模板或原型,您可以从中生成更专业的程序。

最常见的方法是在main()内部使用预处理器和大量#ifdefs函数调用。也许如果您在没有任何#defines的情况下进行编译,您将获得标准变换和Gouraud着色。添加#define WATER以获得水效果,#define DISTORT用于某种自由形态变形算法,如果你想要自由形态变形水,#define FOG添加雾效果,......

您甚至不需要拥有ubershader源的多个副本,因为您可以在运行时生成#define字符串并将它们传递给glCompileShader。

你最终得到的是很多着色器程序,每种类型的渲染都有一个。如果出于任何原因,你只需要一个程序,你就可以在使用GLSL子程序的新系统上做类似的事情。

这些基本上是GLSL中的函数指针,你可以像制服一样设置它们。现在你的ubershader在main()函数中有1,2,...函数指针调用。你的程序只设置#1为标准变换,#2为rock / water / what,#3为fog,...如果你不想使用一个阶段,只需要一个NOP功能你可以分配。

虽然这具有仅使用一个程序的优点,但它不像#define方法那样灵活,因为任何给定的指针都必须使用相同的函数原型。如果说WATER需要在多个着色器中进行处理,那么它的工作也会更多,因为你必须记住在每个着色器中设置函数指针而不只是一个#define。

希望这有帮助。