为什么GLUT窗口没有响应重新显示请求?

时间:2017-04-10 17:20:24

标签: python glut python-multithreading pyopengl

我有一个程序可以在没有显示/ UI的情况下执行大部分工作,但之后需要以低延迟的方式显示一些内容。我通过PyOpenGL使用GLUT在一个单独的线程中显示一个窗口,然后我在必要时填充主线程中的内容。我遇到的问题是,当鼠标光标移过窗口时,GLUT窗口似乎只识别出已发出重写请求。这看起来很奇怪,显然我希望GLUT窗口一旦能够更新就能更新,而不是无限期地等待鼠标光标移动。

我怀疑这可能是特定于平台的问题。我已经确认在Ubuntu 16.04.2和14.04.5上可以重现这种行为。

要重现的完整代码如下(需要PyOpenGL)。此代码的所需行为是GLUT窗口显示黑色,然后在一秒后自动切换为红色,然后绿色然后蓝色然后退出,所有脚本启动后都没有任何鼠标移动。相反,GLUT窗口将在程序启动时显示黑色,并且它将无限期保持黑色,直到鼠标光标移过窗口(然后红色,直到鼠标再次移动等)。如果光标位于窗口内部或外部并不重要 - 必须移动它,否则onDisplay处理程序将不会触发。

无论鼠标在做什么,如何让下面的程序运行完成?

from OpenGL.GLUT import *
from OpenGL.GLU import *
from OpenGL.GL import *
import sys
import threading
import time

hWin = None
displayevent = threading.Event()
bgcolor = (0,0,0,1)

def onDisplay():
    print("  [onDisplay] Started")
    glClearColor(*bgcolor)
    glClear(GL_COLOR_BUFFER_BIT)
    glutSwapBuffers()
    print("  [onDisplay] Finished")
    displayevent.set()
    print("  [onDisplay] Exiting")

def runGl():
    global hWin

    glutInit(sys.argv)
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB)
    glutInitWindowPosition(0, 0)
    hWin = glutCreateWindow("GLWindow")

    glutDisplayFunc(onDisplay)

    print("[runGl] Entering main GLUT loop")
    glutMainLoop()
    print("[runGl] Exited main GLUT loop")


glThread = threading.Thread(target=runGl)
print("[main] Showing GLUT window")
glThread.start()
print("[main] Waiting for GLUT window to initialize")
time.sleep(1)
print("[main] GLUT window initialization (assumed) complete")

colors = [(1, 0, 0, 1), (0, 1, 0, 1), (0, 0, 1, 1)]

for i in range(len(colors)):
    print("[main] --- Iteration %d ---" % i)
    print("[main] Waiting...")
    time.sleep(1)
    print("[main] Trigging display update")
    bgcolor = colors[i]
    displayevent.clear()
    glutPostRedisplay()
    print("[main] Waiting for redraw to complete")
    displayevent.wait()
    print("[main] Redraw is complete")

print("[main] Closing window")
glutDestroyWindow(hWin)
print("[main] All done.")

1 个答案:

答案 0 :(得分:2)

您必须从初始化GLUT的同一个线程中调用glutPostRedisplay()

  

如何在glutPostRedisplay

完全占用的线程上调用glutMainLoop

反过来考虑一下。使用该事件告诉主循环某些内容发生了变化。

def display():
    glClearColor(*bgcolor)
    glClear(GL_COLOR_BUFFER_BIT)
    glutSwapBuffers()

def idle():
    if displayevent.is_set():
        glutPostRedisplay()

使用glutIdleFunc(idle)

这样你的主循环就会继续运行并检查是否设置了displayevent。然后在您的循环而不是displayevent.wait()中调用displayevent.set()

您当然可以在致电glutSwapBuffers()后设置其他活动。然后你可以等待那件事。

这与您进行异步加载的方式类似。您有一个辅助线程加载并处理图像数据。然后,当它完成时,你将其标记为主,并且主/渲染线程调用glTexImage2D()