编程语言
首页 > 编程语言> > java – glClearColor无法正常工作(android opengl)

java – 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之前每次调用glClearColor它都可以工作.但是这对我来说仍然没有意义,我想避免在每一帧调用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个值,最后混合使用旧值和新值.

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

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文档中有一个例子,所以我不会在这里拼出代码.

标签:java,android,opengl-es,opengl-es-2-0
来源: https://codeday.me/bug/20190717/1489514.html