PyOpenGL + PIL でテクスチャ貼り
www.komoto.org の OpenGL入門 sample09 を PyOpenGL と PIL で再現。動作させるにはこの2つのライブラリと texture2.ppm が必要。
テクスチャを作成するには PIL で画像を読み込んで、 tostring() でバイト列に直してから glTexImage2D にわたせば OK 。つまり PIL が読める画像形式ならばテクスチャとしてつかえる。オリジナルでは C言語で PPM画像をがんばって読んでいるのに対して、 PIL だと Image.open するだけ。やはり PIL は便利すぎる。
# coding: utf-8 u""" 参考 OpenGL Programing サンプル9 ミップマップ http://www.komoto.org/opengl/sample09.html これを PyOpenGL + PIL に移植してみた """ import sys import os from OpenGL.GL import * from OpenGL.GLU import * from OpenGL.GLUT import * from PIL import Image tex = 0 # テクスチャ番号 mipmap = 0 # ミップマップ番号 def check_size(img): u""" テクスチャ用画像のサイズが 2 の累乗になっているか調べる """ for size in img.size: # img.size は幅・高さのタプル while True: if (size & 1) != 0: break size >>= 1 if size != 1: return False return True def ppm2texture(ppm_path): u""" PPM ファイルを読み込んでテクスチャを返す """ ppm = Image.open(ppm_path) assert check_size(ppm) w, h = ppm.size # 幅・高さのタプル data = ppm.tostring() # 画像データを文字列化 # テクスチャ番号を取得 tex = glGenTextures(1) # 取得した番号のテクスチャを使うように設定 glBindTexture(GL_TEXTURE_2D, tex) # テクスチャを生成する glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, data) return tex def ppm2mipmap(ppm_path): u""" PPM ファイルを読み込んでミップマップを返す """ ppm = Image.open(ppm_path) assert check_size(ppm) w, h = ppm.size data = ppm.tostring() tex = glGenTextures(1) glBindTexture(GL_TEXTURE_2D, tex) # ミップマップを生成する gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, w, h, GL_RGB, GL_UNSIGNED_BYTE, data) return tex def display_func(): u""" 描画用関数 """ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) glColor3f(1.0, 1.0, 1.0) # テクスチャマップを有効にする glEnable(GL_TEXTURE_2D) # 1 つ目のテクスチャを設定 glBindTexture(GL_TEXTURE_2D, tex) # テクスチャマップの方法を設定 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) glBegin(GL_QUADS) # 四角形を描く glTexCoord2f(0.0, 1.0) # テクスチャ画像での位置を指定 glVertex3f(2.0, -1.0, -50.0) # 頂点をセット glTexCoord2f(5.0, 1.0) glVertex3f(2.0, -1.0, 0.0) glTexCoord2f(5.0, 0.0) glVertex3f(2.0, 1.0, 0.0) glTexCoord2f(0.0, 0.0) glVertex3f(2.0, 1.0, -50.0) glEnd() # 2 つ目のテクスチャを設定 glBindTexture(GL_TEXTURE_2D, mipmap) # テクスチャマップの方法を設定 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) glBegin(GL_QUADS) # 四角形を描く glTexCoord2f(5.0, 1.0) # テクスチャ画像での位置を指定 glVertex3f(-2.0, -1.0, -50.0) # 頂点をセット glTexCoord2f(0.0, 1.0) glVertex3f(-2.0, -1.0, 0.0) glTexCoord2f(0.0, 0.0) glVertex3f(-2.0, 1.0, 0.0) glTexCoord2f(5.0, 0.0) glVertex3f(-2.0, 1.0, -50.0) glEnd() glFlush() def reshape_func(width, height): u""" ウィンドウサイズ更新時の処理 """ glViewport(0, 0, width, height) glMatrixMode(GL_PROJECTION) glLoadIdentity() glFrustum(-1.0, 1.0, -1.0, 1.0, 3.0, 10000.0) glMatrixMode(GL_MODELVIEW) def main(): global tex # テクスチャ番号 global mipmap # ミップマップ番号 glutInit(sys.argv) glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH) glutInitWindowSize(300, 300) glutCreateWindow(u"Sample 9") glutDisplayFunc(display_func) glutReshapeFunc(reshape_func) glEnable(GL_DEPTH_TEST) ppm_path = os.path.join(os.path.dirname(__file__), u"texture2.ppm") tex = ppm2texture(ppm_path) mipmap = ppm2mipmap(ppm_path) glutMainLoop() if __name__ == '__main__': main()