glClearColor无法正常工作(android opengl)

我想在运行时更改我的应用程序的背景颜色。 所以点击按钮我先打电话:

GLES20.glClearColor(color[0], color[1], color[2], color[3]); 

然后我打电话给:

 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT); 

它什么都不做! 它保持当前的背景颜色 – 不会改变它。 但是当我暂停我的应用并再次恢复时,背景颜色会发生变化。

编辑:我发现了一种方法。 每个帧我首先调用glClear但我dident调用glClearColor 。 因此,如果我在调用glClear之前每次调用glClear它都可以工作。 但是这对我来说仍然没有意义,我想避免在每一帧调用glClearColor ,认为如果我想改变颜色就调用它就足够了。

您只能在拥有当前OpenGL上下文时进行OpenGL调用。 当您使用GLSurfaceView ,上下文处理会得到照顾,所以这一切似乎都神奇地起作用。 直到出现问题,就像你的情况一样。 而不是只给你解决方案,让我仍然解释在幕后发生的事情,以避免未来的惊喜。

在进行任何OpenGL调用之前,需要创建一个OpenGL上下文,并将其设置为当前上下文。 在Android上,它使用EGL API。 GLSurfaceView为您处理,这一切都发生在渲染器上调用onSurfaceCreated()之前。 因此,当调用Renderer实现上的方法时,您始终可以依赖于当前上下文,而无需担心它。

然而,关键的方面是当前上下文是每个线程GLSurfaceView创建一个渲染线程,并在此线程中调用所有Renderer方法。

这样做的结果是你无法从其他线程进行OpenGL调用 ,因为它们没有当前的OpenGL上下文。 其中包括UI线程。 这正是你试图做的。 如果您在响应按钮单击时调用glClearColor() ,则表示您处于UI线程中,并且您没有当前的OpenGL上下文。

在这种情况下,您已经找到的解决方法实际上可能是最现实的解决方案。 glClearColor()应该是一个廉价的调用,所以在每个glClear()之前创建它不会很重要。 如果您需要采取的操作更昂贵,您还可以在值更改时设置布尔标志,然后仅在设置标志时在onDrawFrame()执行相应的工作。

这里有另一个微妙但非常重要的方面:线程安全。 只要在一个线程(UI线程)中设置值并在另一个线程(渲染线程)中使用它们,就必须担心这一点。 假设您有背景颜色的RGB组件的3个值,并逐个在UI线程中设置它们。 渲染线程可能在UI线程设置时使用3个值,最后混合使用旧值和新值。

为了说明所有这些,我将使用您的示例,并草拟一个工作和线程安全的解决方案。 涉及的class级成员可能如下所示:

 float mBackRed, mBackGreen, mBackBlue; boolean mBackChanged; Object mBackLock = new Object(); 

然后在UI线程中设置值的位置:

 synchronized(mBackLock) { mBackRed = ...; mBackGreen = ...; mBackBlue = ...; mBackChanged = true; } 

在调用glClear()之前的onDrawFrame()方法中:

 Boolean changed = false; float backR = 0.0f, backG = 0.0f, backB = 0.0f; synchronized(mBackLock) { if (mBackChanged) { changed = true; backR = mBackRed; backG = mBackGreen; backB = mBackBlue; mBackChanged = false; } } if (changed) { glClearColor(backR, backG, backB, 0.0f); } 

请注意两个线程共享的类成员的所有访问权限是如何锁定的。 在最后一个代码片段中,还要注意在使用之前如何将颜色值复制到局部变量。 对于这个简单的例子,这可能太过分了,但我想说明锁定应该尽可能短暂地保持的总体目标。 如果直接使用成员变量,则必须在锁内部进行glClearColor()调用。 如果这是一个可能需要很长时间的操作,则UI线程无法更新值,并且可能会等待一段时间等待锁定。

有一种使用锁的替代方法。 GLSurfaceView有一个queueEvent()方法,允许您传入Runnable ,然后在渲染线程中执行该Runnable 。 在GLSurfaceView文档中有一个例子,所以我不会在这里拼出代码。