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

PythonOpenGLライブラリで、図形の描画を行う練習をしている。とりあえずは、以下のプロセスに沿って、いろいろと機能を試して練習を進める。

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

描いた図形を移動したり、スケールしようとするとき、基本的なことがちゃんと理解できていないのに気づく。そこで、もう一度始めに戻って図形描画の基本を復習する。

  • 参考文献

OpenGLプログラミングテキスト (株)エクサ

OpenGLによる図形描画の基本

  • 2次元図形
    • ユーザはワールド空間の任意の位置に図形を描くことができる
    • 描画ウィンドウに描画するワールド空間の部分はクリッピングウィンドウで指定する(gluOrtho2D関数を使う)
    • クリッピングウィンドウの縦横比が描画ウィンドウの縦横比と異なると、歪んでマップされてしまう。
    • クリッピングウィンドウの設定手順は以下の通り。
      • glMatrixMode(GL_PROJECTION)
      • glLoadIdentity()
      • gluOrtho2D(left, right, bottom, top)
      • glMatrixMode(GL_MODELVIEW)
    • 描画ウィンドウの中で、シーンのマップされる矩形領域をビューポートと呼ぶ。最初はビューポートは描画ウィンドウと一致している。
    • 描画ウィンドウのサイズが変更になるときに、ビューポートを再設定する(glViewport関数を使う)
  • 3次元図形
    • ユーザはワールド空間中に可視領域を設定し、その内部を見ることができる。可視領域内部の3次元シーンを描画ウィンドウのビューポートにマップし表示する。
    • 可視領域の設定手順は以下の通り。
      • glMatrixMode(GL_PROJECTION)
      • glLoadIdentity()
      • glFrustum(), またはgluPerspective, glOrtho等
      • glMatrixMode(GL_MODELVIEW)
    • ワールド空間の原点を視点位置にして、可視領域が設定される。
    • 物体を描くためのローカル座標系をモデリング座標系と呼ぶ。
    • モデリング座標系はモデリング変換を使い、ワールド空間中の任意の位置に配置したり、スケール、回転ができる(glRotatef, glScalef, glTranslatef関数を使う)。モデリング変換によって物体が可視領域に入るようにしないと見られない。
    • モデリング変換を行う場合には、MatrixモードをMODELVIEWにしておく。

図形描画を理解するためのサンプルコード

以上のことを踏まえて、簡単なコードで描画を試してみる。立方体を描画するだけのシンプルなコード。

from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GLU import *
import sys

lastx = 0
lasty = 0

def initialize():
    glClearDepth(1.0)
    glEnable(GL_DEPTH_TEST)
    glClearColor(0.0, 0.5, 0.0, 0.0)
    glShadeModel(GL_SMOOTH)

# 投影変換
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    #ビューイングボリュームの設定
    gluPerspective( 30.0, 1.0, 1.0, 200.0 )  #透視投影変換
#    glFrustum(-0.5, 0.5, -0.5, 0.5, 1.0, 3.0)
    glMatrixMode(GL_MODELVIEW)

# モデリング変換(モデリング座標系の移動、回転、スケール)
    glTranslatef(0.0, 0.0, -5.0)  #移動

    glEnable(GL_LIGHTING)
    glEnable(GL_LIGHT0)
    glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE)
    glEnable(GL_COLOR_MATERIAL)

#マウス位置の座標を取得(描画ウィンドウの左上が(0,0))
def mouseMotion(x, y):
    global lastx, lasty
    lastx = x
    lasty = y
    glutPostRedisplay()  #再描画する

def display():
    global lastx, lasty
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT )
    glPushMatrix()
  # モデリング座標系の回転(物体が回転する)
    glRotatef(lastx, 0.0, 1.0, 0.0)
    glRotatef(lasty, 1.0, 0.0, 0.0)

    #モデリング座標系に物体(辺の長さ1の立方体)を描画する
    glBegin(GL_QUADS)
    glNormal3f( 0.0, 1.0, 0.0)
    glVertex3f( 0.5, 0.5, 0.5)
    glVertex3f( 0.5, 0.5,-0.5)
    glVertex3f(-0.5, 0.5,-0.5)
    glVertex3f(-0.5, 0.5, 0.5)

    glNormal3f( 1.0, 0.0, 0.0)
    glVertex3f( 0.5, 0.5, 0.5)
    glVertex3f( 0.5,-0.5, 0.5)
    glVertex3f( 0.5,-0.5,-0.5)
    glVertex3f( 0.5, 0.5,-0.5)

    glNormal3f( 0.0, 0.0, 1.0)
    glVertex3f( 0.5, 0.5, 0.5)
    glVertex3f(-0.5, 0.5, 0.5)
    glVertex3f(-0.5,-0.5, 0.5)
    glVertex3f( 0.5,-0.5, 0.5)

    glNormal3f( 0.0,-1.0, 0.0)
    glVertex3f(-0.5,-0.5,-0.5)
    glVertex3f( 0.5,-0.5,-0.5)
    glVertex3f( 0.5,-0.5, 0.5)
    glVertex3f(-0.5,-0.5, 0.5)

    glNormal3f(-1.0, 0.0, 0.0)
    glVertex3f(-0.5,-0.5,-0.5)
    glVertex3f(-0.5,-0.5, 0.5)
    glVertex3f(-0.5, 0.5, 0.5)
    glVertex3f(-0.5, 0.5,-0.5)

    glNormal3f( 0.0, 0.0,-1.0)
    glVertex3f(-0.5,-0.5,-0.5)
    glVertex3f(-0.5, 0.5,-0.5)
    glVertex3f( 0.5, 0.5,-0.5)
    glVertex3f( 0.5,-0.5,-0.5)
    glEnd()

    glPopMatrix()
    glutSwapBuffers()
    
def main():
    glutInit(sys.argv)

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

    glutDisplayFunc( display )
    glutMotionFunc( mouseMotion )
    initialize()
    glutMainLoop()

main()


起動直後の画面。回転させないとただの四角が表示される。

回転させたところ。

今後の検討項目

これらから、描画した物体を操作するにはモデリング変換を使えばいいのではないかと思われる。実際に試してみる。