glClearColor无法正常工作(android opengl)

Ale*_*nus 3 java android opengl-es opengl-es-2.0

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

GLES20.glClearColor(color[0], color[1], color[2], color[3]);
Run Code Online (Sandbox Code Playgroud)

然后我打电话给:

GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
Run Code Online (Sandbox Code Playgroud)

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

编辑: 我发现了一种方法.我首先打电话的每一帧,glClear但我打电话glClearColor.所以,如果我glClearColor在调用之前先调用每个帧,glClear它就可以工作.但这对我来说仍然没有意义,我想避免glClearColor在每一帧调用,认为如果我想改变颜色的话我会调用它就足够了.

Ret*_*adi 11

您只能在拥有当前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();
Run Code Online (Sandbox Code Playgroud)

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

synchronized(mBackLock) {
    mBackRed = ...;
    mBackGreen = ...;
    mBackBlue = ...;
    mBackChanged = true;
}
Run Code Online (Sandbox Code Playgroud)

并且在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);
}
Run Code Online (Sandbox Code Playgroud)

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

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

  • 惊人的答案.感谢您超越.先生,祝你好运,先生. (2认同)