読者です 読者をやめる 読者になる 読者になる

TadaoYamaokaの日記

山岡忠夫 Home で公開しているプログラムの開発ネタを中心に書いていきます。

PyOpenGLを使ってみる その3(移動と回転)

前回表示したテクスチャを移動と回転させる。

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

def load_texture():
    img = Image.open("sample1.png")
    w, h = img.size
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, img.tobytes())

def display():
    glClear(GL_COLOR_BUFFER_BIT)

    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
    glEnable(GL_BLEND)

    glEnable(GL_TEXTURE_2D)

    glPushMatrix()
    glTranslatef(0.0, 0.5, 0.0)
    glRotatef(90.0, 0.0, 0.0, 1.0)

    glBegin(GL_QUADS)
    glTexCoord2d(0.0, 1.0)
    glVertex3d(-0.5, -0.5,  0.0)
    glTexCoord2d(1.0, 1.0)
    glVertex3d( 0.5, -0.5,  0.0)
    glTexCoord2d(1.0, 0.0)
    glVertex3d( 0.5,  0.5,  0.0)
    glTexCoord2d(0.0, 0.0)
    glVertex3d(-0.5,  0.5,  0.0)
    glEnd()

    glPopMatrix()

    glDisable(GL_TEXTURE_2D)

    glDisable(GL_BLEND)

    glFlush()

def main():
    glutInit(sys.argv)
    glutInitDisplayMode(GLUT_RGBA)
    glutInitWindowSize(300, 300)
    glutCreateWindow(b"TextureSample1")
    glutDisplayFunc(display)
    glClearColor(0.0, 0.0, 1.0, 1.0)

    load_texture()
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)

    glutMainLoop()

if __name__ == '__main__':
    main()
解説

表示するテクスチャを貼った四角の座標はローカル座標系で指定するため、行列スタックを使用して、現在の座標系(この例では、ワールド座標系)を保存する。

    glPushMatrix()

ローカル座標系での操作が終わった後、

    glPopMatrix()

で保存時の座標系(この例では、ワールド座標系)に復元する。
この例ではローカル座標系は1つしか扱っていないので、保存しなくても問題ない。
2つ以上のローカル座標系を扱う場合や親子関係のオブジェクトを扱う場合は行列スタックが必要になる。


移動は、

    glTranslatef(0.0, 0.5, 0.0)

で行う。

回転は、

    glRotatef(90.0, 0.0, 0.0, 1.0)

で行う。
この例では、Z軸周りに90度(右回り)回転させて、Y軸方向に0.5移動している。

移動の行列をA_2、回転をA_1、頂点のベクトルを\mathbf{x}とすると、ローカル座標系からワールド座標系への変換(モデリング変換)は、A_2 A_1 \mathbf{x}の式で計算される。
行列の積に交換法則は成立しないので、A_2A_1を逆にできないことに注意する。
回転してから移動と、移動してから回転では、回転の原点が異なることは直観的に理解できる。

補足

初期状態では、モデリング変換は、単位行列になっている。
何か操作を行った後に、単位行列に初期化したい場合は、

    glLoadIdentity()

を実行する。

透視変換の行列の操作をした後は、

    glMatrixMode(GL_MODELVIEW)

モデリング変換の行列を選択することを忘れないようにする。

実行結果

f:id:TadaoYamaoka:20170304162124p:plain