クラス ModernApp
の実装¶
本稿で採り上げるクラス ModernApp
こそが、今後制作する PyOpenGL プログラムの「ベース」となるものだ。 OpenGL 3.0 以降の新機能と、古参かつ現役の機能とから何かを描画するためのクラスだ。
Warning
シェーダープログラム管理クラス 参照。
クラス ModernApp
¶
まずクラス全景を示す。
#!/usr/bin/env python
"""glmodernapp.py: For OpenGL 3.x applications.
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
from appbase import AppBase
from program_manager import ProgramManager
from transform import (lookat, perspective)
class ModernApp(AppBase):
"""The base class for classes that never use deprecated features
of OpenGL.
"""
def __init__(self, **kwargs):
"""Initialize an instance of class ModernApp."""
super(ModernApp, self).__init__(**kwargs)
def init_program(self):
"""Setup shaders."""
shader_sources = self.get_shader_sources()
if not shader_sources:
return
self.program_manager = ProgramManager()
self.program_manager.setup(shader_sources)
def init_transform(self):
"""Initialize VM transforms."""
self.update_rotation()
camera_matrix = lookat(
self.camera_eye, self.camera_center, self.camera_up)
GL.glUniformMatrix4fv(
GL.glGetUniformLocation(
self.program_manager.program_id, b"camera"),
1, GL.GL_TRUE,
camera_matrix)
def get_shader_sources(self):
"""Return shader sources."""
return {}
def update_projection(self, fovy, width, height):
"""Update the projection matrix."""
if not self.program_manager:
return
if self.program_manager.program_id:
GL.glUniformMatrix4fv(
GL.glGetUniformLocation(
self.program_manager.program_id, b"projection"),
1, GL.GL_TRUE,
perspective(
fovy, width / height, self.znear, self.zfar))
self.fovy = fovy
def update_rotation(self, quat=None):
"""Update the model transform."""
if not self.program_manager or not self.program_manager.program_id:
return
rotation_matrix = np.identity(4)
if quat is not None:
self.quat = quat
rotation_matrix[:3, :3] = quat.transform
GL.glUniformMatrix4fv(
GL.glGetUniformLocation(
self.program_manager.program_id, b"rotation"),
1, GL.GL_TRUE,
rotation_matrix)
def cleanup(self):
"""The clean up callback function."""
if self.program_manager:
self.program_manager.cleanup()
def main(args):
"""The main function."""
app = ModernApp()
app.run(sys.argv)
if __name__ == "__main__":
sys.exit(main(sys.argv))
各メソッドはすべてベースクラス AppBase
からのオーバーライドとなる。以下、主要メソッドの実装を解説する。
メソッド init_program
¶
"""Setup shaders."""
shader_sources = self.get_shader_sources()
if not shader_sources:
return
self.program_manager = ProgramManager()
self.program_manager.setup(shader_sources)
サブクラスでオーバーライドされているメソッド get_shader_sources
を呼び出し、シェーダータイプとシェーダーコードのペアからなる辞書オブジェクトを受け取り、クラス ProgramManager
のオブジェクトを生成し、それに初期化処理を委ねる。
詳細は シェーダープログラム管理クラス を参照。
メソッド init_transform
¶
"""Initialize VM transforms."""
self.update_rotation()
camera_matrix = lookat(
self.camera_eye, self.camera_center, self.camera_up)
GL.glUniformMatrix4fv(
GL.glGetUniformLocation(
self.program_manager.program_id, b"camera"),
1, GL.GL_TRUE,
camera_matrix)
初回にシェーダーオブジェクトに行列データを送信する処理である。モデル回転用行列、カメラ用行列、投影用行列すべてを設定する。
関数
lookat
については ベクトル・行列・座標変換 参照。GL.glUniformMatrix4fv
の転置フラグを ON にすることで、OpenGL に行列の column-major 化をさせる。
言い忘れたが、頂点シェーダーでの各行列の名前は次のとおりとする:
#version 330 core
uniform mat4 camera;
uniform mat4 projection;
uniform mat4 rotation;
...
決め打ちなのはいかにも手抜きだが、当面これでいく。
メソッド update_projection
¶
"""Update the projection matrix."""
if not self.program_manager:
return
if self.program_manager.program_id:
GL.glUniformMatrix4fv(
GL.glGetUniformLocation(
self.program_manager.program_id, b"projection"),
1, GL.GL_TRUE,
perspective(
fovy, width / height, self.znear, self.zfar))
self.fovy = fovy
直接呼び出すというよりは、ベースクラスでウィンドウサイズ変更時に呼び出すメソッドだ。
関数
perspective
については ベクトル・行列・座標変換 参照。
メソッド update_rotation
¶
"""Update the model transform."""
if not self.program_manager or not self.program_manager.program_id:
return
rotation_matrix = np.identity(4)
if quat is not None:
self.quat = quat
rotation_matrix[:3, :3] = quat.transform
GL.glUniformMatrix4fv(
GL.glGetUniformLocation(
self.program_manager.program_id, b"rotation"),
1, GL.GL_TRUE,
rotation_matrix)
前半部はほぼ クラス DeprecatedApp の実装 でのオーバーライドと同じだ。外部で計算した回転量を受け取って、直接メンバーデータ self.quat
に保存しておく。後半はシェーダーオブジェクトへの行列送信である。
メソッド cleanup
¶
"""The clean up callback function."""
if self.program_manager:
self.program_manager.cleanup()
シェーダー関連の後始末を行う。詳細は シェーダープログラム管理クラス を参照。
なお、サブクラスではこのメソッドをオーバーライドし、この処理に加えて、バッファーオブジェクトやテクスチャーオブジェクトの破棄をすることになる。