OpenGLでの選択処理は、GL_SELECTモードでポリゴンを描画することによって行われます。
指定された領域にポリゴンが描画されたかどうかで、選択範囲に入っているかを判断します。
ただし、GL_SELECTモードでは実際の描画は行われません。
PyOpenGLで、選択されたポリゴンを調べる手順は以下のようになります。
sel = glSelectBuffer(バッファの個数)
glRenderMode(GL_SELECT)
glInitNames()
glPushName(0)
glMatrixMode(GL_PROJECTION)
glPushMatrix()
glLoadIdentity()
gluPickMatrix(選択範囲中心X座標, 選択範囲中心Y座標, 選択範囲横幅, 選択範囲縦幅, ビュー情報)
glLoadName(番号)
glMatrixMode(GL_PROJECTION)
glPopMatrix()
hits = glRenderMode(GL_RENDER)
マウスの左ボタンでクリックされたポリゴンの色を変えてみます。
#!env python
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
vertex = [
[ -1.0, -1.0, 1.0 ],
[ 1.0, -1.0, 1.0 ],
[ -1.0, 1.0, 1.0 ],
[ 1.0, 1.0, 1.0 ],
[ -1.0, 1.0, -1.0 ],
[ 1.0, 1.0, -1.0 ],
[ -1.0, -1.0, -1.0 ],
[ 1.0, -1.0, -1.0 ]]
face = [
[ 0, 1, 3, 2 ],
[ 2, 3, 5, 4 ],
[ 4, 5, 7, 6 ],
[ 6, 7, 1, 0 ],
[ 1, 7, 5, 3 ],
[ 6, 0, 2, 4 ]]
color = [
[ 0.3, 0.3, 0.3 ],
[ 0.4, 0.4, 0.4 ],
[ 0.5, 0.5, 0.5 ],
[ 0.6, 0.6, 0.6 ],
[ 0.7, 0.7, 0.7 ],
[ 0.8, 0.8, 0.8 ]]
angleX = 0.0
angleY = 0.0
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 drawObjs(name=False):
global angleX, angleY
glLoadIdentity()
gluLookAt(3.0, 4.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0)
glRotated(angleX, 1.0, 0.0, 0.0);
glRotated(angleY, 0.0, 1.0, 0.0);
for j in range(0, len(face)):
if name:
glLoadName(j)
glBegin(GL_QUADS)
glColor3dv(color[j])
for i in range(0, 4):
glVertex(vertex[face[j][i]])
glEnd()
def draw():
glClearColor(0.0, 0.0, 1.0, 0.0)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
drawObjs()
glFlush()
glutSwapBuffers()
def mouse(button, state, x, y):
if state == GLUT_DOWN:
if button == GLUT_LEFT_BUTTON:
sel = glSelectBuffer(8)
glRenderMode(GL_SELECT)
glInitNames()
glPushName(0)
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)
drawObjs(name=True)
glMatrixMode(GL_PROJECTION)
glPopMatrix()
hits = glRenderMode(GL_RENDER)
for n in hits:
h = n.names[0]
color[h] = [1.0, 0, 0]
glMatrixMode(GL_MODELVIEW)
glutPostRedisplay()
def keyboard(key, x, y):
global angleX, angleY
if key=='q':
sys.exit()
elif key=='h':
angleY += 1.0
glutPostRedisplay()
elif key=='j':
angleX += 1.0
glutPostRedisplay()
glutInit(sys.argv)
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH)
glutInitWindowSize(320, 320)
glutCreateWindow("PyOpenGL 17")
glutDisplayFunc(draw)
glutReshapeFunc(resize)
glutKeyboardFunc(keyboard)
glutMouseFunc(mouse)
glClearColor(0.0, 0.0, 1.0, 0.0)
glEnable(GL_DEPTH_TEST)
glEnable(GL_CULL_FACE)
glCullFace(GL_BACK)
glutMainLoop()
def drawObjs(name=False):
if name:
glLoadName(j)
sel = glSelectBuffer(8)
glRenderMode(GL_SELECT)
glInitNames()
glPushName(0)
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)
drawObjs(name=True)
glMatrixMode(GL_PROJECTION)
glPopMatrix()
hits = glRenderMode(GL_RENDER)
for n in hits:
h = n.names[0]
color[h] = [1.0, 0, 0]
glMatrixMode(GL_MODELVIEW)
GL_SELECTモードで、名前に階層構造を与えたいときにはglPushName(), glPopName()を使用します。
glPushName(1)
glPushName(1)
glPushName(0)
glLoadName(0)
# ポリゴンA1を描画
glLoadName(1)
# ポリゴンA2を描画
glPopName()
glPopName()
glPushName(2)
glPushName(0)
glLoadName(0)
# ポリゴンB1を描画
glLoadName(1)
# ポリゴンB2を描画
glPopName()
glPopName()
glPopName()
glPushName(2)
glPushName(1)
glPushName(0)
glLoadName(0)
# ポリゴンC1を描画
glLoadName(1)
# ポリゴンC2を描画
glPopName()
glPopName()
glPopName()
上のコードで、選択されたオブジェクトの名前は以下のようになります。
マウスの選択スクリプトでは、n.namesに入っている値です。