我有一个程序可以在没有显示/ 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.")
答案 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()
。