OpenGL ES 2.0多个程序或多个着色器,哪个更好?它是如何工作的?

56

问题(简而言之)

我的问题在于,我不知道OpenGL ES 2.0希望我如何编写和使用多个着色器;或者一个人是否应该这样做。

这里的根本问题是:如果我有一个苹果、一个发光的石头和一个模糊的网格,都在同一个3D世界中,最好用不同的着色器程序绘制,但使用相同的mvpMatrix,那么我该如何在同一个OpenGL渲染中使用它们,以便它们都使用我编写的最合适的着色器?

我做了什么

所以,我为我的Android游戏编写了一个基本的OpenGL ES 2.0程序,在屏幕上可以绘制对象的轮廓,这完美地工作了。但它除此之外什么也没做;主要是因为着色器看起来像这样:

顶点着色器

uniform mat4 uMVPMatrix;
attribute vec4 aPosition;

void main() {
    gl_Position = uMVPMatrix * aPosition;
}

片段着色器

void main() {
    gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
}

现在它们非常基础。我之所以没有继续深入,是因为我无法确定是否应该编写一个着色器来应用于我所有不同的对象,还是应该使用多个着色器。如果我应该使用多个着色器来绘制多个不同的对象,那么我该如何以高效的方式做到这一点?
我觉得对于每天都在进行OpenGL ES 2.0的任何人来说,这必须是基本知识,因此我希望有人能回答我的问题或指引我正确的方向。
我已经:
- 查看了多个教程;其中没有一个使用除最基本的着色器之外的任何东西。 - 阅读了整个OpenGL ES 2.0 GLSL规范(其中没有提到它的预期用途;它只是关于每个内容的功能,而不是如何将其组合在一起)。 - 尝试稍微修改了我的着色器。
因此,我希望我已经接近理解OpenGL工作流程,但似乎还没有到达那里。
编辑:我在此之后找到了这个:
如果您的应用程序是针对OpenGL ES 2.0编写的,请勿创建一个有很多开关和条件语句的单个着色器,以执行应用程序需要呈现场景的每个任务。相反,编译多个着色器程序,每个程序执行特定的、专注的任务。这是来自iOS OpenGL ES 2.0指南的建议。

你能提一下你是怎么实现的吗? - Ashika Umanga Umagiliya
@AshikaUmangaUmagiliya:我正在考虑不久写一篇关于它的博客文章,或者写一个样例应用程序。如果我写了一个,我会更新这个问题。 - Robert Massaioli
我想知道,您是否使用相同的顶点着色器和多个片段着色器?如果是这样,您必须从“着色器程序”中分离当前的片段着色器并附加新的着色器。我认为这是不可能的。另一种方法是,您可以将所有片段着色器逻辑编写在一个着色器中,并在函数中区分不同的效果。在运行时,通过设置参数来执行当前的“着色器函数”。 - Ashika Umanga Umagiliya
@AshikaUmangaUmagiliya 就像在普通程序中一样,您可以使用任何组合的顶点和片段着色器,只要它们可以有效地编译在一起。您只需将它们一起编译成不同的程序,并将程序作为整体对象处理。因此,在运行时,您使用正确的“着色器程序”来渲染当前正在尝试呈现的内容。 - Robert Massaioli
顶点着色器的逻辑不是每次都一样吗?(处理矩阵、光照和雾)我在想,如果只改变“片段着色器”的逻辑,我就可以避免代码重复了吗? - Ashika Umanga Umagiliya
顶点着色器如果你想的话可以是相同的,但绝不意味着每次都必须相同。而且你完全可以编写一个顶点着色器和多个片段着色器。但是你将不得不为每个顶点/片段着色器组合编译不同的着色器程序。 - Robert Massaioli
1个回答

21

您可以使用多个着色器,但是在它们之间进行切换可能会非常昂贵,因此推荐的做法是绘制每个着色器的所有对象,然后切换到下一个着色器并绘制使用该着色器的所有对象,以此类推。


为了在不同着色器之间进行切换,您需要调用glUseProgram()函数。


好的,知道了。这需要我稍微重新调整一下,以确保每个特定着色器的对象一个接一个地绘制,但肯定是可能的。 - Robert Massaioli
3
追问:假设我有两个程序,Foo和Bar。我交替使用它们进行绘制。比如我调用glUseProgram(Foo), 设置Foo的uniforms、textures等参数,然后绘制;接着我调用glUseProgram(Bar),设置Bar的uniforms、textures等参数,然后绘制。下次我再调用glUseProgram(Foo),GL状态(例如激活/绑定的纹理单元)会反映出上一次使用Foo时的设置,还是我必须重新设置所有在使用Bar期间可能更改的内容? - Nicu Stiurca
@SchighSchagh 我相信你需要重置所有内容,但我不确定。如果你不需要重置某些东西,那么他们应该在规格说明中提到。 - Robert Massaioli
2
我只是想回来说,这正是我最终采用的方法。这个方法非常有效,而且由于z缓冲区,你不必按任何特定顺序绘制OpenGL中的深度就能得到正确的结果。 - Robert Massaioli

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