マウスでオブジェクトを選択する(1)
OpenGLで描画した物体をマウスで選択していろいろとやってみたい。セレクションという概念を使って実現するみたいだが、その練習をやってみる。
上記(1)のサイトのセレクションを使ったサンプル(アニメーション版)は、C言語で書かれたサンプルプログラムなのだが、これをPythonで書き直す。
from OpenGL.GL import * from OpenGL.GLUT import * from OpenGL.GLU import * SELECTIONS = 100 NOBJECTS = 5 color = [ [0.1, 0.1, 0.9], [0.1, 0.9, 0.1], [0.9, 0.1, 0.1], [0.1, 0.9, 0.9], [0.9, 0.1, 0.9], [0.9, 0.9, 0.1] ] ARRANGEWIDTH = 4.0 ARRANGECENTER = ARRANGEWIDTH/2.0 ARRANGESTEP = ARRANGEWIDTH/(NOBJECTS-1) ARRANGEDEPTH = 0.0 INITIALHEIGHT = 0.0 INITIALVELOCITY = 2.0 GRAVITY = -1.0 REFRESHRATE = 0.01 ESCAPE = 27 cframe = 0 light0pos = [4.0, 8.0, 6.0, 1.0] objects = None touchtime = list() def init(): global objects global touchtime glClearColor(1.0, 1.0, 1.0, 0.0) glEnable(GL_DEPTH_TEST) glEnable(GL_CULL_FACE) glEnable(GL_LIGHT0) glEnable(GL_LIGHTING) objects = glGenLists(NOBJECTS) touchtime = [0]*NOBJECTS def display(): global cframe cframe += 1 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) glLoadIdentity() gluLookAt(5.0, 4.0, 5.0, 0.4, 0.0, 0.0, 0.0, 1.0, 0.0) glLightfv(GL_LIGHT0, GL_POSITION, light0pos) for i in range(NOBJECTS): h = INITIALHEIGHT if touchtime[i] > 0: t = (cframe-touchtime[i]) * REFRESHRATE h += (GRAVITY*t*0.5 + INITIALVELOCITY)*t if h < 0.0: h = INITIALHEIGHT touchtime[i] = 0 glMaterialfv(GL_FRONT, GL_DIFFUSE, color[i%6]) glNewList(objects + i, GL_COMPILE_AND_EXECUTE) glPushMatrix() glTranslated(float(i)*ARRANGESTEP - ARRANGECENTER, h, ARRANGEDEPTH) glutSolidCube(0.8) glPopMatrix() glEndList() glutSwapBuffers() def mouse(button, state, x, y): global touchtime if state == GLUT_DOWN: if button == GLUT_LEFT_BUTTON: sel = glSelectBuffer(SELECTIONS) #選択されたオブジェクトのデータを入れるバッファ glRenderMode(GL_SELECT) #セレクションモードに入る glInitNames() #名前スタックを初期化 glPushName(-1) #名前スタックの最初の名前を-1に glMatrixMode(GL_PROJECTION) #視点座標系に入る glPushMatrix() #現在の透視変換マトリックスを保存 glLoadIdentity() #透視変換マトリックスを初期化 vp = glGetIntegerv(GL_VIEWPORT) #現在のビューポート設定を得る gluPickMatrix(x, vp[3]-y-1, 1, 1, vp) #表示領域がマウスがクリックされた周囲だけになるように gluPerspective(30.0, vp[2]/vp[3], 1.0, 100.0) #透視変換マトリックスを設定 glMatrixMode(GL_MODELVIEW) #モデルビューマトリックスに切り替え for i in range(NOBJECTS): glLoadName(i) #オブジェクトの番号を設定 glCallList(objects + i) #オブジェクトの描画(画面には表示されず) glMatrixMode(GL_PROJECTION) #再び透視変換マトリックスに glPopMatrix() #透視変換マトリックスを元に戻す glMatrixMode(GL_MODELVIEW) hits = glRenderMode(GL_RENDER) #レンダリングモードを元に戻す for n in hits: #選択されたオブジェクトの処理 h = n.names[0] #選択されたオブジェクトの番号 touchtime[h] = cframe def resize(w, h): glViewport(0, 0, w, h) glMatrixMode(GL_PROJECTION) glLoadIdentity() gluPerspective(30.0, w/h, 1.0, 100.0) glMatrixMode(GL_MODELVIEW) def keyboard(key, x, y): if key == 'q': sys.exit() def idle(): glutPostRedisplay() glutInit(sys.argv) glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH) glutInitWindowSize(320, 320) glutCreateWindow("sample") glutDisplayFunc(display) glutReshapeFunc(resize) glutKeyboardFunc(keyboard) glutMouseFunc(mouse) glutIdleFunc(idle) init() glutMainLoop()