我想在运行时更改应用程序的背景色。因此,在按钮上单击“我首先拨打”:
GLES20.glClearColor(color[0], color[1], color[2], color[3]);
然后我打电话给:
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
它什么也没做!它保留当前的背景颜色-不会更改。但是,当我然后暂停我的应用程序并再次恢复它时,背景颜色就会更改。
编辑:我发现了一种方法。每个帧glClear
我都先打,但我没打glClearColor
。因此,如果我先调用glClearColor
每个帧,然后再调用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线程设置它们时,渲染线程可能会使用这三个值,最终会混合使用旧值和新值。
为了说明所有这些,我将使用您的示例,并勾画出一个可行且线程安全的解决方案。涉及的班级成员可能看起来像这样:
float mBackRed, mBackGreen, mBackBlue;
boolean mBackChanged;
Object mBackLock = new Object();
然后在UI线程中设置值的位置:
synchronized(mBackLock) {
mBackRed = ...;
mBackGreen = ...;
mBackBlue = ...;
mBackChanged = true;
}
并在onDrawFrame()
调用之前的方法中glClear()
:
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
然后该方法将在渲染线程中执行。GLSurfaceView
文档中有一个示例,因此在这里我不会为它拼写代码。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句