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我都先打,但我没打glClearColor因此,如果我先调用glClearColor每个帧,然后再调用glClear它就可以了。但这对我来说仍然没有意义,我想避免glClearColor在每一帧都调用,以为只要更改颜色就调用一次就足够了。

雷托·科拉迪(Reto Koradi)

只有在具有当前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] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章