クラス DeprecatedApp
の実装¶
本稿で述べるクラス DeprecatedApp
は、あくまでも過去に制作したOpenGL 3.0 以前の機能で実装した PyOpenGL プログラムをリファクタリングするためのみに利用する。
もう少し具体的に説明すると、そのような古臭いソースコードが何十枚とある。そこでの処理で似通った部分、例えば
描画処理開始直後のモデルビュー行列設定、
ウィンドウサイズ変更時におけるビューポートの更新処理
は deprecated features を用いた実装方法で共通化したい。言い換えると、OpenGL 3.0
以降の API と混在したコードを持ちたくないので、クラス DeprecatedApp
とクラス
ModernApp
のようなものを設けることにした。
クラス DeprecatedApp
¶
まずクラス全景を示す。
#!/usr/bin/env python
"""deprecatedapp.py: Do not use.
References:
* rndblnch / opengl-programmable
<http://bitbucket.org/rndblnch/opengl-programmable>
* OpenGLBook.com
<http://openglbook.com/chapter-4-entering-the-third-dimension.html>
* Tutorials for modern OpenGL (3.3+)
<http://www.opengl-tutorial.org/beginners-tutorials/tutorial-3-matrices/>
"""
# pylint: disable=unused-argument, no-self-use
import sys
import numpy as np
import OpenGL.GL as GL
import OpenGL.GLU as GLU
from appbase import AppBase
class DeprecatedApp(AppBase):
"""The base class for classes that use some deprecated features
of OpenGL 3.0.
"""
def __init__(self, **kwargs):
"""Initialize an instance of class DeprecatedApp."""
kwargs.setdefault('context_version', (2, 1))
super(DeprecatedApp, self).__init__(**kwargs)
self.rotation_matrix = np.identity(4)
def init_program(self):
"""Setup shaders."""
self.program_manager = None
def get_shader_sources(self):
"""Return shader sources."""
return {}
def update_projection(self, fovy, width, height):
"""Update the projection matrix."""
GL.glMatrixMode(GL.GL_PROJECTION)
GL.glLoadIdentity()
GLU.gluPerspective(fovy, width / height, self.znear, self.zfar)
self.fovy = fovy
def update_rotation(self, quat=None):
"""Update the model transform."""
if quat is None:
# Initial update.
self.rotation_matrix = np.identity(4)
else:
self.quat = quat
self.rotation_matrix[:3, :3] = quat.transform.transpose()
def set_modelview_matrix(self):
"""Set the modelview matrix with deprecated GL commands."""
GL.glLoadIdentity()
GLU.gluLookAt(
self.camera_eye[0], self.camera_eye[1], self.camera_eye[2],
self.camera_center[0], self.camera_center[1], self.camera_center[2],
self.camera_up[0], self.camera_up[1], self.camera_up[2])
GL.glMultMatrixf(self.rotation_matrix)
def main(args):
"""The main function."""
app = DeprecatedApp()
app.run(sys.argv)
if __name__ == "__main__":
sys.exit(main(sys.argv))
各メソッドはほぼすべてベースクラス AppBase
からのオーバーライドとなるが、その実装は OpenGL 3.0 以前の機能で実現する。
以下、特徴的なメソッドの説明をする。
メソッド __init__
¶
"""Initialize an instance of class DeprecatedApp."""
kwargs.setdefault('context_version', (2, 1))
super(DeprecatedApp, self).__init__(**kwargs)
self.rotation_matrix = np.identity(4)
コンテキストバージョンを未指定の場合
(2, 1)
にしておく。この値は、私の環境で認められているバージョン値の最大値で、 3.0 を超えない値、という意味だ。モデル回転用の行列として、メンバーデータ
self.rotation_matrix
を導入する。ベースクラスに同じ目的のメンバーデータself.quat
が既にあるので本来は要らないものだが、四元数オブジェクトから行列オブジェクトを生成する処理が高くつく可能性があるので、キャッシュ的に置く。
メソッド update_projection
¶
"""Update the projection matrix."""
GL.glMatrixMode(GL.GL_PROJECTION)
GL.glLoadIdentity()
GLU.gluPerspective(fovy, width / height, self.znear, self.zfar)
self.fovy = fovy
ご覧のとおり、古典的な射影行列の設定処理である。
メソッド update_rotation
¶
"""Update the model transform."""
if quat is None:
# Initial update.
self.rotation_matrix = np.identity(4)
else:
self.quat = quat
self.rotation_matrix[:3, :3] = quat.transform.transpose()
外部で計算した回転量を受け取って、メンバーデータ self.rotation_matrix
に保存しておく。
クラス Quat
のプロパティー transform
で回転変換を表現する 3 次正規直交行列にアクセスする。これをマウスドラッグ時の優位な移動が発生する都度、OpenGL 形式の 4 次行列に作り変える。
最後の転置処理は、この self.rotation_matrix
を GL.glMultMatrixf
にそのまま渡したいため行う。
メソッド set_modelview_matrix
¶
"""Set the modelview matrix with deprecated GL commands."""
GL.glLoadIdentity()
GLU.gluLookAt(
self.camera_eye[0], self.camera_eye[1], self.camera_eye[2],
self.camera_center[0], self.camera_center[1], self.camera_center[2],
self.camera_up[0], self.camera_up[1], self.camera_up[2])
GL.glMultMatrixf(self.rotation_matrix)
メソッド set_modelview_matrix
だけは、ベースクラスからのオーバーライドではない。処理は古典的なモデルビュー行列の適用である。
造りが悪いのだが、サブクラスのメソッド do_render
からの呼び出しを想定している。その際には GL.glMatrixMode(GL.GL_MODELVIEW)
を伴う。