2017-04-10 1 views
0

나는 디스플레이/UI없이 대부분의 작업을 수행하는 프로그램을 가지고 있지만 대기 시간이 짧은 방식으로 내용을 간단히 표시해야합니다. 필자는 별도의 스레드에 창을 표시하기 위해 PyOpenGL을 통해 GLUT를 사용하고 있는데, 필요한 경우 주 스레드의 내용으로 채 웁니다. 내가 겪고있는 문제는 GLUT 윈도우는 마우스 커서가 윈도우를 가로 질러 움직일 때 재발견 요청이 발행되었다는 것을 인식하는 것 같다. 이것은 매우 이상하게 보입니다. 분명히 마우스 커서가 움직일 때까지 무기한 기다릴 필요없이 GLUT 창을 가능한 한 빨리 업데이트하고 싶습니다.GLUT 창이 다시 표시 요청에 응답하지 않는 이유는 무엇입니까?

이것이 플랫폼 관련 문제 일 수 있습니다. 우분투 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.") 

답변

2

glutPostRedisplay()은 GLUT가 초기화 된 동일한 스레드에서 호출해야합니다.

어떻게 완전히 다른 방법으로 주위에 대해 생각 glutMainLoop

이 차지하는 스레드에서 glutPostRedisplay를 호출 할 수 있습니다. 이벤트를 사용하여 메인 루프에 변경된 사항이 있음을 알립니다.

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()을 호출합니다.

+0

흠, 일반적으로 합리적인 것처럼 보이는데, 그 스레드가 glutMainLoop에 되돌릴 수 없게 갇혀있을 때 어떻게 할 수 있습니까? (GLUT에게 glutMainLoop을 종료하도록 지시하는 방법조차 없다) – Ben

+0

예,'glutLeaveMainLoop()'이있다. 그러나보다 구체적인 최종 목표를 아는 것이 더 쉬울 것입니다. – Vallentin

+0

아, 아마도 같은 문제가 강조 표시됩니다. glutLeaveMainLoop이 다른 스레드에서 작동하지 않습니다. 그래서이 답변에 내 원래 의견을 다시 : 어떻게 glutMainLoop 완전히 점령 스레드에서 glutPostRedisplay 호출 할 수 있습니까? 내 최종 목표는 하나의 스레드에서 CPU 작업을 수행하고 GLUT 창 (또는 실제로 OpenGL 창)에서 해당 작업의 결과를 주기적으로 표시하는 것입니다. 이 코드의 구체적인 목표는 마우스를 움직이지 않고도 완료하는 것입니다. – Ben

관련 문제