描画した図形を操作する(4)

PythonOpenGLライブラリで、図形の描画を行う練習をしている。とりあえずは、以下のプロセスに沿って、いろいろと機能を試して練習を進めていく。最初は描画した図形をマウスで回転させるまでが目的であったが、段々やってみたいことが増えてきた。

  1. なんでもいいので3次元の図形を描画 (practice1.py)
  2. 描いた図形をマウスで回転できるようにする (practice2mod.py)
  3. 表面が連続した四角形からなる物体を描画
  4. 描いた物体をマウスで回転できるようにする (practice3.py) <--今、ここ。
  5. 描いた物体をマウスで平行移動したり、拡大縮小したりする
  6. その他

今回は六面体よりも、頂点数が多い図形を描いてみた(practice3.py)。コードの中で法線ベクトルの計算をしている。

# practice3.py
#
from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GLU import *
import sys
import math

ESCAPE = '\033'

class QuadsPicture:
    def __init__(self):
        self.lastx = self.x = 30
        self.lasty = self.y = 30
        glClearDepth(1.0)
        glEnable(GL_DEPTH_TEST)
        glClearColor(0.0, 0.5, 0.0, 0.0)
        glShadeModel(GL_SMOOTH)

        glMatrixMode(GL_PROJECTION)
        glFrustum(-0.5, 0.5, -0.5, 0.5, 1.0, 3.0)
        glMatrixMode(GL_MODELVIEW)

        glTranslatef(0.0, 0.0, -2.0)
        glRotatef(self.y, 1.0, 0.0, 0.0)
        glRotatef(self.x, 0.0, 1.0, 0.0)
        glEnable(GL_LIGHTING)
        glEnable(GL_LIGHT0)
        glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE)
        glEnable(GL_COLOR_MATERIAL)

        self.vpos = list()
        self.readpos()
        self.displaylist()

    def readpos(self):        #ファイルから頂点座標を読み込む
        fp = open('coordpos.txt', 'r')
        num = int(fp.readline())
        poss = fp.read().splitlines()
        for i in xrange(num):
            self.vpos.append([float(x) for x in poss[i].split(',')])
        fp.close()

    def crossproduct(self, a, b, c):  #面の法線ベクトルを計算
        cross = [0.0, 0.0, 0.0]
        cross[0] = (a[1]-b[1])*(c[2]-b[2]) - (a[2]-b[2])*(c[1]-b[1])
        cross[1] = (a[2]-b[2])*(c[0]-b[0]) - (a[0]-b[0])*(c[2]-b[2])
        cross[2] = (a[0]-b[0])*(c[1]-b[1]) - (a[1]-b[1])*(c[0]-b[0])
        cabs = math.sqrt(cross[0]**2+cross[1]**2+cross[2]**2)
        cc = [x/cabs for x in cross]
        return cc

    def mouseMotion(self, x, y):
        self.lastx = x
        self.lasty = y
        glutPostRedisplay()

    def displaylist(self):
        ps = self.vpos
        self.index = glGenLists(1)
        glNewList(self.index, GL_COMPILE_AND_EXECUTE)

        glBegin(GL_QUADS)
# 四角形の面1
        glNormal3fv(self.crossproduct(ps[4],ps[1],ps[0]))
        glVertex3fv(ps[0])
        glVertex3fv(ps[1])
        glVertex3fv(ps[4])
        glVertex3fv(ps[3])
# 四角形の面2
        glNormal3fv(self.crossproduct(ps[5],ps[2],ps[1]))
        glVertex3fv(ps[1])
        glVertex3fv(ps[2])
        glVertex3fv(ps[5])
        glVertex3fv(ps[4])
# 四角形の面3
......(続けて頂点の指定。中略)......

        glEnd()

        glEndList()

    def display(self):
        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT )
        glPushMatrix()
        glRotatef(self.lastx, 0.0, 1.0, 0.0)
        glRotatef(self.lasty, 1.0, 0.0, 0.0)

        glCallList(self.index)

        glPopMatrix()
        glutSwapBuffers()
    
    def keyboard(self, *args):
        if args[0] == ESCAPE:
            sys.exit()

    def reshape(self, w, h):
        glViewport(0, 0, w, h)

def main():
    glutInit(sys.argv)

    glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH )
    glutInitWindowPosition( 100, 100 )
    glutInitWindowSize( 500, 400 )
    glutCreateWindow( sys.argv[0] )

    qp = QuadsPicture()
    glutDisplayFunc( qp.display )
    glutKeyboardFunc( qp.keyboard )
    glutReshapeFunc( qp.reshape )
    glutMotionFunc( qp.mouseMotion )

    glutMainLoop()

print "Hit ESC key to quit."
main()

物体の頂点の座標値は、ファイルで与えている。
実行すると、下の図が描かれる。